`timescale 1ns / 1ps module sprite(CLK_50M, VGA_R, VGA_G, VGA_B, VGA_HSYNC, VGA_VSYNC, LED, ROT_CENTER, RS232_DCE_RXD); input CLK_50M; output [3:0] VGA_R; output [3:0] VGA_G; output [3:0] VGA_B; output VGA_HSYNC; output VGA_VSYNC; output [7:0] LED; input ROT_CENTER; input RS232_DCE_RXD; wire reset; assign reset = ROT_CENTER; wire rxd; assign rxd = RS232_DCE_RXD; reg [1:0] clock_count; wire clk; wire nclk; assign clk = clock_count[0]; assign nclk = ~clk; reg [9:0] hcount_start; reg [9:0] vcount_start; reg [9:0] hcount_out; reg [9:0] vcount_out; reg [9:0] hcount[0:15]; // reg [3:0] vga_r_out; // reg [3:0] vga_g_out; // reg [3:0] vga_b_out; reg vga_r_out; reg vga_g_out; reg vga_b_out; reg vga_hsync_out; reg vga_vsync_out; // assign VGA_R = vga_r_out; // assign VGA_G = vga_g_out; // assign VGA_B = vga_b_out; assign VGA_R[3:0] = { vga_r_out, vga_r_out, vga_r_out, vga_r_out }; assign VGA_G[3:0] = { vga_g_out, vga_g_out, vga_g_out, vga_g_out }; assign VGA_B[3:0] = { vga_b_out, vga_b_out, vga_b_out, vga_b_out }; assign VGA_HSYNC = vga_hsync_out; assign VGA_VSYNC = vga_vsync_out; parameter H_ACTIVE_PIXEL_LIMIT = 10'd640; parameter H_FPORCH_PIXEL_LIMIT = 10'd656; // 640+16 parameter H_SYNC_PIXEL_LIMIT = 10'd752; // 640+16+96 parameter H_BPORCH_PIXEL_LIMIT = 10'd800; // 640+16+96+48 parameter V_ACTIVE_LINE_LIMIT = 10'd480; parameter V_FPORCH_LINE_LIMIT = 10'd490; // 480+10 parameter V_SYNC_LINE_LIMIT = 10'd492; // 480+10+2 parameter V_BPORCH_LINE_LIMIT = 10'd521; // 480+10+2+29 reg [3:0] spreg_himage [0:15]; reg [63:0] spreg_vimage [0:15]; reg [2:0] spreg_image[0:15]; reg spreg_enable[0:15]; reg [9:0] spreg_dx[0:15]; // 位置 reg [9:0] spreg_dy[0:15]; reg [1:0] spreg_mx[0:15]; // 拡大率 reg [1:0] spreg_my[0:15]; reg spreg_tx[0:15]; // タイリング reg spreg_ty[0:15]; reg spreg_rx[0:15]; // 反転 reg spreg_ry[0:15]; reg [1:0] spreg_rot[0:15]; // 回転(時計回り) wire [7:0] rch; wire rcv; reg rcv_old; rx rx(CLK_50M, rxd, rch, rcv, reset); reg [15:0] rcv_cmd; reg [79:0] rcv_data; reg [7:0] led_out; assign LED = led_out; function [3:0] a2b4; input [7:0] a; begin if ((a >= 8'h30) && (a <= 8'h39)) a2b4 = (a - 8'h30); else if ((a >= 8'h61) && (a <= 8'h66)) a2b4 = (a - 8'h57); else if ((a >= 8'h41) && (a <= 8'h46)) a2b4 = (a - 8'h37); else a2b4 = 8'd0; end endfunction function [7:0] a2b8; input [15:0] a; begin a2b8[7:4] = a2b4(a[15:8]); a2b8[3:0] = a2b4(a[ 7:0]); end endfunction always @(posedge CLK_50M) begin clock_count <= clock_count + 1; end reg [63:0] mem_din; wire [63:0] mem_dout; reg mem_en; reg mem_wr; reg mem_enb; reg mem_rx; reg mem_ry; reg [1:0] mem_rot; reg [5:0] mem_addr; // 画面描画はクロックの立ち上がりで動作するので、 // うまく同期でォるように、メモリヘクロックのァ下りで動作させる。 memory memory(nclk, mem_din, mem_dout, mem_en, mem_wr, mem_enb, mem_rx, mem_ry, mem_rot, mem_addr); reg ycalc_en; reg [9:0] ycalc_y; reg [9:0] ycalc_dy; reg [1:0] ycalc_my; reg ycalc_ty; wire ycalc_enb; wire [3:0] ycalc_addr; ycalc ycalc(nclk, ycalc_en, ycalc_y, ycalc_dy, ycalc_my, ycalc_ty, ycalc_enb, ycalc_addr); reg [3:0] ycalc_index; reg [3:0] mem_index; reg [3:0] vimage_index; function h_inrange; input [9:0] x; input [9:0] dx; input [1:0] mx; input tx; begin if (x < H_ACTIVE_PIXEL_LIMIT) begin if ((tx == 1'b1) || ((x >= dx) && (((x - dx) >> mx) < 16))) h_inrange = 1'b1; else h_inrange = 1'b0; end else h_inrange = 1'b0; end endfunction always @(posedge clk) begin hcount[ 0] <= hcount_start; hcount[ 1] <= hcount[ 0]; hcount[ 2] <= hcount[ 1]; hcount[ 3] <= hcount[ 2]; hcount[ 4] <= hcount[ 3]; hcount[ 5] <= hcount[ 4]; hcount[ 6] <= hcount[ 5]; hcount[ 7] <= hcount[ 6]; hcount[ 8] <= hcount[ 7]; hcount[ 9] <= hcount[ 8]; hcount[10] <= hcount[ 9]; hcount[11] <= hcount[10]; hcount[12] <= hcount[11]; hcount[13] <= hcount[12]; hcount[14] <= hcount[13]; hcount[15] <= hcount[14]; hcount_out <= hcount[15]; if (hcount_start < H_BPORCH_PIXEL_LIMIT) hcount_start <= hcount_start + 10'd1; else hcount_start <= 10'd0; // 水平方向の描画の開始タイミングに失敗しないように、 // 垂直同期のカウントタCミ塔Oを微妙に早゚るた゚ H_BPORCH から減算している。 if (hcount_start == H_BPORCH_PIXEL_LIMIT - 8) begin if (vcount_start < V_BPORCH_LINE_LIMIT) begin vcount_start <= vcount_start + 10'd1; end else begin vcount_start <= 10'd0; end vcount_out <= vcount_start; end if ((hcount_out >= H_FPORCH_PIXEL_LIMIT) && (hcount_out < H_FPORCH_PIXEL_LIMIT + 16 + 3)) begin if (hcount_out < H_FPORCH_PIXEL_LIMIT + 16) begin ycalc_index <= hcount_out - H_FPORCH_PIXEL_LIMIT; end if ((hcount_out >= H_FPORCH_PIXEL_LIMIT + 1) && (hcount_out < H_FPORCH_PIXEL_LIMIT + 16 + 1)) begin mem_index <= ycalc_index; ycalc_en <= spreg_enable[ycalc_index]; ycalc_y <= vcount_start; ycalc_dy <= spreg_dy[ycalc_index]; ycalc_my <= spreg_my[ycalc_index]; ycalc_ty <= spreg_ty[ycalc_index]; end if ((hcount_out >= H_FPORCH_PIXEL_LIMIT + 2) && (hcount_out < H_FPORCH_PIXEL_LIMIT + 16 + 2)) begin vimage_index <= mem_index; mem_en <= ~mem_en; mem_wr <= 1'b0; mem_enb <= ycalc_enb; mem_rx <= spreg_rx[mem_index]; mem_ry <= spreg_ry[mem_index]; mem_rot <= spreg_rot[mem_index]; mem_addr[5:4] <= spreg_image[mem_index]; mem_addr[3:0] <= ycalc_addr; end if (hcount_out >= H_FPORCH_PIXEL_LIMIT + 3) begin spreg_vimage[vimage_index] <= mem_dout; end end else begin // シリアル受信モジュール(rx)はクロックの立下りで動作するので、 // クロックの立ち上がりで受信文字を読み込む。 // rcvとrchの立ち上がりがタイミング的にクれている場合が考えられるので。 if (rcv_old != rcv) begin rcv_old <= rcv; led_out <= rch; case (rch) 8'h24 : // '$' begin rcv_cmd <= 16'd0; // rcv_data <= 0; end 8'h2b : // '+' begin case (rcv_cmd) 16'h6478 : // dx spreg_dx[rcv_data[19:16]] <= rcv_data[9:0]; 16'h6479 : // dy spreg_dy[rcv_data[19:16]] <= rcv_data[9:0]; 16'h6d78 : // mx spreg_mx[rcv_data[11:8]] <= rcv_data[1:0]; 16'h6d79 : // my spreg_my[rcv_data[11:8]] <= rcv_data[1:0]; 16'h7278 : // rx spreg_rx[rcv_data[11:8]] <= rcv_data[0]; 16'h7279 : // ry spreg_ry[rcv_data[11:8]] <= rcv_data[0]; 16'h7478 : // tx spreg_tx[rcv_data[11:8]] <= rcv_data[0]; 16'h7479 : // ty spreg_ty[rcv_data[11:8]] <= rcv_data[0]; 16'h7274 : // rt spreg_rot[rcv_data[11:8]] <= rcv_data[1:0]; 16'h696d : // im spreg_image[rcv_data[11:8]] <= rcv_data[2:0]; 16'h656e : // en spreg_enable[rcv_data[11:8]] <= rcv_data[0]; 16'h6964 : //id begin mem_en <= ~mem_en; mem_wr <= 1'b1; mem_addr[5:4] <= rcv_data[73:72]; mem_addr[3:0] <= rcv_data[67:64]; // 左右を反転させて保存 mem_din[63:60] <= rcv_data[ 3: 0]; mem_din[59:56] <= rcv_data[ 7: 4]; mem_din[55:52] <= rcv_data[11: 8]; mem_din[51:48] <= rcv_data[15:12]; mem_din[47:44] <= rcv_data[19:16]; mem_din[43:40] <= rcv_data[23:20]; mem_din[39:36] <= rcv_data[27:24]; mem_din[35:32] <= rcv_data[31:28]; mem_din[31:28] <= rcv_data[35:32]; mem_din[27:24] <= rcv_data[39:36]; mem_din[23:20] <= rcv_data[43:40]; mem_din[19:16] <= rcv_data[47:44]; mem_din[15:12] <= rcv_data[51:48]; mem_din[11: 8] <= rcv_data[55:52]; mem_din[ 7: 4] <= rcv_data[59:56]; mem_din[ 3: 0] <= rcv_data[63:60]; end default : ; endcase end default : begin if (rcv_cmd[15:8] == 8'b00000000) begin rcv_cmd[15:8] <= rcv_cmd[7:0]; rcv_cmd[ 7:0] <= rch; end else begin rcv_data[79:4] <= rcv_data[75:0]; rcv_data[ 3:0] <= a2b4(rch); end end endcase end end if (h_inrange(hcount[0], spreg_dx[0], spreg_mx[0], spreg_tx[0])) spreg_himage[0] <= (spreg_vimage[0] >> {((hcount[0] - spreg_dx[0]) >> spreg_mx[0]) & 4'b1111, 2'b00}); else spreg_himage[0] <= 4'b1111; if (h_inrange(hcount[1], spreg_dx[1], spreg_mx[1], spreg_tx[1]) && (spreg_himage[0][3] == 1'b1)) spreg_himage[1] <= (spreg_vimage[1] >> {((hcount[1] - spreg_dx[1]) >> spreg_mx[1]) & 4'b1111, 2'b00}); else spreg_himage[1] <= spreg_himage[0]; if (h_inrange(hcount[2], spreg_dx[2], spreg_mx[2], spreg_tx[2]) && (spreg_himage[1][3] == 1'b1)) spreg_himage[2] <= (spreg_vimage[2] >> {((hcount[2] - spreg_dx[2]) >> spreg_mx[2]) & 4'b1111, 2'b00}); else spreg_himage[2] <= spreg_himage[1]; if (h_inrange(hcount[3], spreg_dx[3], spreg_mx[3], spreg_tx[3]) && (spreg_himage[2][3] == 1'b1)) spreg_himage[3] <= (spreg_vimage[3] >> {((hcount[3] - spreg_dx[3]) >> spreg_mx[3]) & 4'b1111, 2'b00}); else spreg_himage[3] <= spreg_himage[2]; if (h_inrange(hcount[4], spreg_dx[4], spreg_mx[4], spreg_tx[4]) && (spreg_himage[3][3] == 1'b1)) spreg_himage[4] <= (spreg_vimage[4] >> {((hcount[4] - spreg_dx[4]) >> spreg_mx[4]) & 4'b1111, 2'b00}); else spreg_himage[4] <= spreg_himage[3]; if (h_inrange(hcount[5], spreg_dx[5], spreg_mx[5], spreg_tx[5]) && (spreg_himage[4][3] == 1'b1)) spreg_himage[5] <= (spreg_vimage[5] >> {((hcount[5] - spreg_dx[5]) >> spreg_mx[5]) & 4'b1111, 2'b00}); else spreg_himage[5] <= spreg_himage[4]; if (h_inrange(hcount[6], spreg_dx[6], spreg_mx[6], spreg_tx[6]) && (spreg_himage[5][3] == 1'b1)) spreg_himage[6] <= (spreg_vimage[6] >> {((hcount[6] - spreg_dx[6]) >> spreg_mx[6]) & 4'b1111, 2'b00}); else spreg_himage[6] <= spreg_himage[5]; if (h_inrange(hcount[7], spreg_dx[7], spreg_mx[7], spreg_tx[7]) && (spreg_himage[6][3] == 1'b1)) spreg_himage[7] <= (spreg_vimage[7] >> {((hcount[7] - spreg_dx[7]) >> spreg_mx[7]) & 4'b1111, 2'b00}); else spreg_himage[7] <= spreg_himage[6]; if (h_inrange(hcount[8], spreg_dx[8], spreg_mx[8], spreg_tx[8]) && (spreg_himage[7][3] == 1'b1)) spreg_himage[8] <= (spreg_vimage[8] >> {((hcount[8] - spreg_dx[8]) >> spreg_mx[8]) & 4'b1111, 2'b00}); else spreg_himage[8] <= spreg_himage[7]; if (h_inrange(hcount[9], spreg_dx[9], spreg_mx[9], spreg_tx[9]) && (spreg_himage[8][3] == 1'b1)) spreg_himage[9] <= (spreg_vimage[9] >> {((hcount[9] - spreg_dx[9]) >> spreg_mx[9]) & 4'b1111, 2'b00}); else spreg_himage[9] <= spreg_himage[8]; if (h_inrange(hcount[10], spreg_dx[10], spreg_mx[10], spreg_tx[10]) && (spreg_himage[9][3] == 1'b1)) spreg_himage[10] <= (spreg_vimage[10] >> {((hcount[10] - spreg_dx[10]) >> spreg_mx[10]) & 4'b1111, 2'b00}); else spreg_himage[10] <= spreg_himage[9]; if (h_inrange(hcount[11], spreg_dx[11], spreg_mx[11], spreg_tx[11]) && (spreg_himage[10][3] == 1'b1)) spreg_himage[11] <= (spreg_vimage[11] >> {((hcount[11] - spreg_dx[11]) >> spreg_mx[11]) & 4'b1111, 2'b00}); else spreg_himage[11] <= spreg_himage[10]; if (h_inrange(hcount[12], spreg_dx[12], spreg_mx[12], spreg_tx[12]) && (spreg_himage[11][3] == 1'b1)) spreg_himage[12] <= (spreg_vimage[12] >> {((hcount[12] - spreg_dx[12]) >> spreg_mx[12]) & 4'b1111, 2'b00}); else spreg_himage[12] <= spreg_himage[11]; if (h_inrange(hcount[13], spreg_dx[13], spreg_mx[13], spreg_tx[13]) && (spreg_himage[12][3] == 1'b1)) spreg_himage[13] <= (spreg_vimage[13] >> {((hcount[13] - spreg_dx[13]) >> spreg_mx[13]) & 4'b1111, 2'b00}); else spreg_himage[13] <= spreg_himage[12]; if (h_inrange(hcount[14], spreg_dx[14], spreg_mx[14], spreg_tx[14]) && (spreg_himage[13][3] == 1'b1)) spreg_himage[14] <= (spreg_vimage[14] >> {((hcount[14] - spreg_dx[14]) >> spreg_mx[14]) & 4'b1111, 2'b00}); else spreg_himage[14] <= spreg_himage[13]; if (h_inrange(hcount[15], spreg_dx[15], spreg_mx[15], spreg_tx[15]) && (spreg_himage[14][3] == 1'b1)) spreg_himage[15] <= (spreg_vimage[15] >> {((hcount[15] - spreg_dx[15]) >> spreg_mx[15]) & 4'b1111, 2'b00}); else spreg_himage[15] <= spreg_himage[14]; if (hcount_out < H_ACTIVE_PIXEL_LIMIT && vcount_out < V_ACTIVE_LINE_LIMIT) // active video begin if (spreg_himage[15][3] == 1'b1) begin if ((hcount_out == 10'd0) || (hcount_out == 10'd639) || (vcount_out == 10'd0) || (vcount_out == 10'd479)) begin vga_b_out <= 1'b1; vga_r_out <= 1'b1; vga_g_out <= 1'b1; end else begin vga_b_out <= 1'b0; vga_r_out <= 1'b0; vga_g_out <= 1'b0; end end else begin vga_b_out <= spreg_himage[15][0]; vga_r_out <= spreg_himage[15][1]; vga_g_out <= spreg_himage[15][2]; end end else case (hcount_out) H_ACTIVE_PIXEL_LIMIT : // front porch begin vga_b_out <= 1'b0; vga_r_out <= 1'b0; vga_g_out <= 1'b0; end H_FPORCH_PIXEL_LIMIT : // sync pulse vga_hsync_out <= 1'b0; H_SYNC_PIXEL_LIMIT : // back porch vga_hsync_out <= 1'b1; endcase case (vcount_out) V_ACTIVE_LINE_LIMIT : // front porch ; V_FPORCH_LINE_LIMIT : // sync pulse vga_vsync_out <= 1'b0; V_SYNC_LINE_LIMIT : // back porch vga_vsync_out <= 1'b1; default : ; endcase end endmodule