1
0
mirror of https://github.com/UzixLS/zx-sizif-xxs.git synced 2025-07-18 23:01:40 +03:00
Files
zx-sizif-xxs/fpga/rtl/video.sv
2024-01-03 19:05:12 +03:00

319 lines
9.6 KiB
Systemverilog

import common::*;
module video(
input rst_n,
input clk28,
input machine_t machine,
input turbo_t turbo,
input [2:0] border,
output reg [5:0] r,
output reg [5:0] g,
output reg [5:0] b,
output reg vsync,
output reg hsync,
output reg csync,
input read_allow,
output reg read_req,
output read_req_next,
output [14:0] read_req_addr,
input [7:0] read_data,
output contention,
output reg even_line,
output port_ff_active,
output [7:0] port_ff_data,
input up_en,
output [5:0] up_ink_addr,
input [7:0] up_ink_data,
output [5:0] up_paper_addr,
input [7:0] up_paper_data,
output [8:0] hc_out,
output [8:0] vc_out,
output clk14,
output clk7,
output clk35,
output ck14,
output ck7,
output ck35
);
reg [8:0] vc;
reg [10:0] hc0;
wire [8:0] hc = hc0[10:2];
assign vc_out = vc;
assign hc_out = hc;
assign clk14 = hc0[0];
assign clk7 = hc0[1];
assign clk35 = hc0[2];
assign ck14 = hc0[0];
assign ck7 = hc0[0] & hc0[1];
assign ck35 = hc0[0] & hc0[1] & hc0[2];
/* SYNC SIGNALS */
localparam H_AREA = 256;
localparam V_AREA = 192;
localparam SCREEN_DELAY = 13;
localparam H_LBORDER_S48 = 54 - SCREEN_DELAY;
localparam H_RBORDER_S48 = 53 + SCREEN_DELAY;
localparam H_BLANK1_S48 = 12;
localparam H_SYNC_S48 = 33;
localparam H_BLANK2_S48 = 40;
localparam H_TOTAL_S48 = H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48 + H_BLANK2_S48 + H_LBORDER_S48;
localparam V_BBORDER_S48 = 56;
localparam V_SYNC_S48 = 8;
localparam V_TBORDER_S48 = 56;
localparam V_TOTAL_S48 = V_AREA + V_BBORDER_S48 + V_SYNC_S48 + V_TBORDER_S48;
localparam H_LBORDER_S128 = 54 - SCREEN_DELAY;
localparam H_RBORDER_S128 = 53 + SCREEN_DELAY;
localparam H_BLANK1_S128 = 16;
localparam H_SYNC_S128 = 33;
localparam H_BLANK2_S128 = 44;
localparam H_TOTAL_S128 = H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128 + H_BLANK2_S128 + H_LBORDER_S128;
localparam V_BBORDER_S128 = 55;
localparam V_SYNC_S128 = 8;
localparam V_TBORDER_S128 = 56;
localparam V_TOTAL_S128 = V_AREA + V_BBORDER_S128 + V_SYNC_S128 + V_TBORDER_S128;
localparam H_LBORDER_PENT = 54 - SCREEN_DELAY;
localparam H_RBORDER_PENT = 53 + SCREEN_DELAY;
localparam H_BLANK1_PENT = 12;
localparam H_SYNC_PENT = 33;
localparam H_BLANK2_PENT = 40;
localparam H_TOTAL_PENT = H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT + H_BLANK2_PENT + H_LBORDER_PENT;
localparam V_BBORDER_PENT = 56;
localparam V_SYNC_PENT = 8;
localparam V_TBORDER_PENT = 64;
localparam V_TOTAL_PENT = V_AREA + V_BBORDER_PENT + V_SYNC_PENT + V_TBORDER_PENT;
wire hc0_reset =
(machine == MACHINE_S48)?
hc0 == (H_TOTAL_S48<<2) - 1'b1 :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
hc0 == (H_TOTAL_S128<<2) - 1'b1 :
// Pentagon
hc0 == (H_TOTAL_PENT<<2) - 1'b1 ;
wire vc_reset =
(machine == MACHINE_S48)?
vc == V_TOTAL_S48 - 1'b1:
(machine == MACHINE_S128 || machine == MACHINE_S3)?
vc == V_TOTAL_S128 - 1'b1 :
// Pentagon
vc == V_TOTAL_PENT - 1'b1 ;
wire hsync0 =
(machine == MACHINE_S48)?
(hc >= (H_AREA + H_RBORDER_S48 + H_BLANK1_S48)) && (hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48)) :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
(hc >= (H_AREA + H_RBORDER_S128 + H_BLANK1_S128)) && (hc < (H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128)) :
// Pentagon
(hc >= (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT)) && (hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT)) ;
wire vsync0 =
(machine == MACHINE_S48)?
(vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48)) :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
(vc >= (V_AREA + V_BBORDER_S128)) && (vc < (V_AREA + V_BBORDER_S128 + V_SYNC_S128)) :
// Pentagon
(vc >= (V_AREA + V_BBORDER_PENT)) && (vc < (V_AREA + V_BBORDER_PENT + V_SYNC_PENT)) ;
wire blank =
(machine == MACHINE_S48)?
((vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48))) ||
((hc >= (H_AREA + H_RBORDER_S48)) &&
(hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48 + H_BLANK2_S48))) :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
((vc >= (V_AREA + V_BBORDER_S128)) && (vc < (V_AREA + V_BBORDER_S128 + V_SYNC_S128))) ||
((hc >= (H_AREA + H_RBORDER_S128)) &&
(hc < (H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128 + H_BLANK2_S128))) :
// Pentagon
((vc >= (V_AREA + V_BBORDER_PENT)) && (vc < (V_AREA + V_BBORDER_PENT + V_SYNC_PENT))) ||
((hc >= (H_AREA + H_RBORDER_PENT)) &&
(hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT + H_BLANK2_PENT))) ;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
hc0 <= 0;
vc <= 0;
end
else if (hc0_reset) begin
hc0 <= 0;
if (vc_reset) begin
vc <= 0;
end
else begin
vc <= vc + 1'b1;
end
end
else begin
hc0 <= hc0 + 1'b1;
end
end
reg [4:0] blink_cnt;
wire blink = blink_cnt[$bits(blink_cnt)-1];
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
blink_cnt <= 0;
else if (hc0_reset && vc_reset)
blink_cnt <= blink_cnt + 1'b1;
end
reg hsync0_delayed;
always @(posedge clk28)
hsync0_delayed <= hsync0;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
even_line <= 0;
else if (hsync0 && !hsync0_delayed)
even_line <= ~even_line;
end
/* SCREEN CONTROLLER */
wire screen_show = (vc < V_AREA) && (hc0 >= (SCREEN_DELAY<<2) - 1) && (hc0 < ((H_AREA + SCREEN_DELAY)<<2) - 1);
wire screen_update = hc0[4:0] == 5'b10011;
wire border_update = (hc0[4:0] == 5'b10011) || (machine == MACHINE_PENT && ck7);
wire bitmap_shift = hc0[1:0] == 2'b11;
wire next_addr = hc0[4:0] == 5'b10000;
reg screen_read, up_read;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
screen_read <= 0;
up_read <= 0;
end
else begin
screen_read <= (vc < V_AREA) && (hc0 > 15) && (hc0 < (H_AREA<<2) + 17);
up_read <= screen_read && (screen_update || up_read);
end
end
reg [7:0] vaddr;
reg [7:3] haddr;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
vaddr <= 0;
haddr <= 0;
end
else if (next_addr) begin
vaddr <= vc[7:0];
haddr <= hc[7:3];
end
end
reg [7:0] bitmap, attr, bitmap_next, attr_next;
reg [7:0] up_ink, up_paper;
reg [1:0] read_cnt;
localparam READ_CYCLES = 2'd2;
assign read_req_next = screen_read && (read_allow || (|read_cnt && read_cnt != READ_CYCLES && turbo == TURBO_14));
reg read_step;
assign read_req_addr = (read_step == 1'd0)?
{ 2'b10, vaddr[7:6], vaddr[2:0], vaddr[5:3], haddr[7:3] } :
{ 5'b10110, vaddr[7:3], haddr[7:3] };
assign up_ink_addr = up_read? { attr_next[7:6], 1'b0, attr_next[2:0] } : { 3'b0, border[2:0] };
assign up_paper_addr = up_read? { attr_next[7:6], 1'b1, attr_next[5:3] } : { 3'b0, border[2:0] };
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
read_req <= 0;
read_step <= 0;
read_cnt <= 0;
attr_next <= 0;
bitmap_next <= 0;
end
else begin
read_req <= read_req_next;
if (read_cnt == READ_CYCLES) begin
if (read_step == 1'd1)
attr_next <= read_data;
if (read_step == 1'd0)
bitmap_next <= read_data;
read_step <= read_step + 1'b1;
read_cnt <= 0;
end
else if (read_req && read_req_next && !next_addr) begin
read_cnt <= read_cnt + 1'b1;
end
else begin
read_cnt <= 0;
end
end
end
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
attr <= 0;
bitmap <= 0;
up_ink <= 0;
up_paper <= 0;
end
else begin
if (screen_show && screen_update)
attr <= attr_next;
else if (!screen_show && border_update)
attr <= {2'b00, border[2:0], border[2:0]};
if (screen_update)
bitmap <= bitmap_next;
else if (bitmap_shift)
bitmap <= {bitmap[6:0], 1'b0};
if (screen_update)
up_ink <= up_ink_data;
if (screen_update)
up_paper <= up_paper_data;
end
end
/* ATTRIBUTE PORT */
wire port_ff_attr = (machine == MACHINE_PENT) || hc[3:1] == 3'h6 || hc[3:1] == 3'h0;
wire port_ff_bitmap = (hc[3] && hc[1]);
assign port_ff_active = screen_read && (port_ff_attr || port_ff_bitmap);
assign port_ff_data =
port_ff_attr? attr_next :
port_ff_bitmap? bitmap_next :
8'hFF;
assign contention = (vc < V_AREA) && (hc < H_AREA) && (hc[2] || hc[3]);
/* RGBS OUTPUT */
wire pixel = bitmap[7];
always @(posedge clk28) begin
if (blank)
{g, r, b} = 0;
else if (up_en) begin
g[5:3] = pixel? up_ink[7:5] : up_paper[7:5];
r[5:3] = pixel? up_ink[4:2] : up_paper[4:2];
b[5:4] = pixel? up_ink[1:0] : up_paper[1:0];
g[2:0] = g[5:3];
r[2:0] = r[5:3];
b[3:0] = {b[5:4], b[5:4]};
end
else begin
{g[5], r[5], b[5]} = (pixel ^ (attr[7] & blink))? attr[2:0] : attr[5:3];
{g[4], r[4], b[4]} = attr[6]? {g[5], r[5], b[5]} : 3'b000;
{g[3], r[3], b[3]} = {g[5], r[5], b[5]};
{g[2], r[2], b[2]} = {g[4], r[4], b[4]};
{g[1], r[1], b[1]} = {g[4], r[4], b[4]};
{g[0], r[0], b[0]} = {g[5], r[5], b[5]};
end
end
always @(posedge clk28) begin
csync = ~(vsync0 ^ hsync0);
vsync = ~vsync0;
hsync = ~hsync0;
end
endmodule