mirror of
https://github.com/UzixLS/zx-sizif-xxs.git
synced 2025-07-18 23:01:40 +03:00
316 lines
9.5 KiB
Systemverilog
316 lines
9.5 KiB
Systemverilog
import common::*;
|
|
module video(
|
|
input rst_n,
|
|
input clk28,
|
|
|
|
input machine_t machine,
|
|
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,
|
|
|
|
output read_req,
|
|
output [14:0] read_req_addr,
|
|
input read_req_ack,
|
|
input read_data_valid,
|
|
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'b10001;
|
|
|
|
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 > 17) && (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 read_step, read_step_cur;
|
|
assign read_req = 1'b1; // just to simplify logic
|
|
assign read_req_addr = (read_step == 1'd1)?
|
|
{ 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_step <= 0;
|
|
read_step_cur <= 0;
|
|
attr_next <= 0;
|
|
bitmap_next <= 0;
|
|
end
|
|
else begin
|
|
if (next_addr)
|
|
read_step <= 0;
|
|
else if (read_req_ack)
|
|
read_step <= read_step + 1'd1;
|
|
|
|
if (read_req_ack)
|
|
read_step_cur <= read_step;
|
|
|
|
if (read_data_valid && read_step_cur == 2'd0 && screen_read)
|
|
attr_next <= read_data;
|
|
else if (!screen_read && hc0[0])
|
|
attr_next <= {2'b00, border[2:0], border[2:0]};
|
|
|
|
if (read_data_valid && read_step_cur == 2'd1 && screen_read)
|
|
bitmap_next <= read_data;
|
|
else if (!screen_read && hc0[0])
|
|
bitmap_next <= 0;
|
|
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
|