Integrate Aznable codebase

This commit is contained in:
jimmystones
2021-12-22 17:11:57 +00:00
parent 2aab758881
commit 8a93d6fdb2
169 changed files with 17233 additions and 2032 deletions

View File

@@ -19,46 +19,26 @@
// Input clock must be 24 MHz
// Generates various clock enable signals
// Modifed by Jim Gregory - @mrjimmystones to remove redundant signals and add 2Mhz enable
module jtframe_cen24(
input clk, // 24 MHz
output reg cen12,
output cen8,
output reg cen6,
output reg cen4,
output reg cen3,
output reg cen3q, // 1/4 advanced with respect to cen3
output reg cen1p5,
// 180 shifted signals
output reg cen12b,
output reg cen6b,
output reg cen3b,
output reg cen3qb,
output reg cen1p5b
output reg cen2
);
reg [3:0] cencnt =4'd0;
reg [2:0] cencnt3=3'd0;
reg [2:0] cencnt8=3'd1;
assign cen8 = cencnt8[2];
reg [3:0] cencnt2=4'd0;
always @(posedge clk) begin
cencnt <= cencnt+4'd1;
cencnt3 <= cencnt3==3'd5 ? 3'd0 : (cencnt3+3'd1);
cencnt8 <= { cencnt8[1:0], cencnt8[2] };
cencnt2 <= cencnt2==4'd12 ? 4'd0 : (cencnt2+4'd1);
end
always @(posedge clk) begin
cen12 <= cencnt[0] == 1'd0;
cen12b <= cencnt[0] == 1'd1;
cen4 <= cencnt3 == 3'd0;
cen6 <= cencnt[1:0] == 2'd0;
cen6b <= cencnt[1:0] == 2'd2;
cen3 <= cencnt[2:0] == 3'd0;
cen3b <= cencnt[2:0] == 3'h4;
cen3q <= cencnt[2:0] == 3'b110;
cen3qb <= cencnt[2:0] == 3'b010;
cen1p5 <= cencnt[3:0] == 4'd0;
cen1p5b<= cencnt[3:0] == 4'b1000;
cen2 <= cencnt2 == 4'd0;
end
endmodule

View File

@@ -0,0 +1,108 @@
/* This file is part of JT_FRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 25-9-2019 */
module jtframe_resync(
input clk,
input pxl_cen,
input hs_in,
input vs_in,
input LVBL,
input LHBL,
input [3:0] hoffset,
input [3:0] voffset,
output reg hs_out,
output reg vs_out
);
parameter CNTW = 10; // max 1024 pixels/lines
reg [CNTW-1:0] hs_pos[0:1], vs_hpos[0:1], vs_vpos[0:1],// relative positions of the original sync pulses
hs_len[0:1], vs_len[0:1], // count the length of the original sync pulses
hs_cnt, vs_cnt, // count the position of the original sync pulses
hs_hold, vs_hold;
reg last_LHBL, last_LVBL, last_hsin, last_vsin;
wire hb_edge, hs_edge, hs_n_edge, vb_edge, vs_edge, vs_n_edge;
reg field;
wire [CNTW-1:0] hpos_off = { {CNTW-4{hoffset[3]}}, hoffset[3:0] };
wire [CNTW-1:0] htrip = hs_pos[field] + hpos_off;
wire [CNTW-1:0] vs_htrip = vs_hpos[field] + hpos_off;
wire [CNTW-1:0] vs_vtrip = vs_vpos[field] + { {CNTW-4{voffset[3]}}, voffset[3:0] };
assign hb_edge = LHBL && !last_LHBL;
assign hs_edge = hs_in && !last_hsin;
assign hs_n_edge = !hs_in && last_hsin;
assign vb_edge = LVBL && !last_LVBL;
assign vs_edge = vs_in && !last_vsin;
assign vs_n_edge = !vs_in && last_vsin;
always @(posedge clk) if(pxl_cen) begin
last_LHBL <= LHBL;
last_LVBL <= LVBL;
last_hsin <= hs_in;
last_vsin <= vs_in;
hs_cnt <= hb_edge ? {CNTW{1'b0}} : hs_cnt+1'b1;
if( vb_edge ) begin
vs_cnt <= {CNTW{1'b0}};
field <= ~field;
end else if(hb_edge)
vs_cnt <= vs_cnt+1'b1;
// Horizontal
if( hs_edge ) hs_pos[field] <= hs_cnt;
if( hs_n_edge ) hs_len[field] <= hs_cnt - hs_pos[field];
if( hs_cnt == htrip ) begin
hs_out <= 1;
hs_hold <= hs_len[field] - 1'b1;
end else begin
if( |hs_hold ) hs_hold <= hs_hold - 1'b1;
if( hs_hold == 0 ) hs_out <= 0;
end
// Vertical
if( vs_edge ) begin
vs_hpos[field] <= hs_cnt;
vs_vpos[field] <= vs_cnt;
end
if( vs_n_edge ) vs_len[field] <= vs_cnt - vs_vpos[field];
if( hs_cnt == vs_htrip ) begin
if( vs_cnt == vs_vtrip ) begin
vs_hold <= vs_len[field] - 1'b1;
vs_out <= 1;
end else begin
if( |vs_hold ) vs_hold <= vs_hold - 1'b1;
if( vs_hold == 0 ) vs_out <= 0;
end
end
end
`ifdef SIMULATION
initial begin
hs_cnt = {CNTW{1'b0}};
vs_cnt = {CNTW{1'b0}};
hs_out = 0;
vs_out = 0;
end
`endif
endmodule

57
rtl/charmap.v Normal file
View File

@@ -0,0 +1,57 @@
`timescale 1ns / 1ps
/*============================================================================
Aznable (custom 8-bit computer system) - Casval (character map)
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-10-20
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module charmap (
input clk,
input reset,
input [8:0] hcnt,
input [8:0] vcnt,
input [7:0] chrom_data_out,
input [7:0] fgcolram_data_out,
input [7:0] bgcolram_data_out,
input [7:0] chmap_data_out,
output [11:0] chram_addr,
output [11:0] chrom_addr,
output [7:0] r,
output [7:0] g,
output [7:0] b,
output a
);
// Character map
wire [3:0] chpos_x = 4'd7 - hcnt[2:0];
wire [2:0] chpos_y = vcnt[2:0];
wire [5:0] chram_x = hcnt[8:3];
wire [5:0] chram_y = vcnt[8:3];
assign chram_addr = {chram_y, chram_x};
assign chrom_addr = {1'b0, chmap_data_out[7:0], chpos_y};
assign a = chrom_data_out[chpos_x[2:0]];
wire [2:0] r_temp = a ? fgcolram_data_out[2:0] : bgcolram_data_out[2:0];
wire [2:0] g_temp = a ? fgcolram_data_out[5:3] : bgcolram_data_out[5:3];
wire [1:0] b_temp = a ? fgcolram_data_out[7:6] : bgcolram_data_out[7:6];
assign r = {{2{r_temp}},2'b0};
assign g = {{2{g_temp}},2'b0};
assign b = {{3{b_temp}},2'b0};
endmodule

View File

@@ -40,8 +40,8 @@ module dpram #(
initial begin
if (init_file>0)
begin
$display("Loading dpram from file:");
$display(init_file);
// $display("Loading dpram from file:");
// $display(init_file);
$readmemh(init_file, mem);
end
end

59
rtl/dpram_w1r2.v Normal file
View File

@@ -0,0 +1,59 @@
/*============================================================================
Dual-port RAM module with single-width write port and double-width read port
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-10-29
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module dpram_w1r2 #(
parameter address_width = 10,
parameter data_width = 8,
parameter init_file= ""
) (
input wire clock_a,
input wire wren_a,
input wire [address_width-1:0] address_a,
input wire [data_width-1:0] data_a,
input wire clock_b,
input wire [address_width-1:0] address_b,
output reg [(data_width*2)-1:0] q_b
);
initial begin
if (init_file>0)
begin
// $display("Loading dpram from file:");
// $display(init_file);
$readmemh(init_file, mem);
end
end
localparam ramLength = (2**address_width);
reg [data_width-1:0] mem [ramLength-1:0];
always @(posedge clock_a) begin
if(wren_a) begin
mem[address_a] <= data_a;
end
end
always @(posedge clock_b) begin
q_b <= {mem[address_b], mem[address_b + 1'b1]};
end
endmodule

56
rtl/generic_timer.v Normal file
View File

@@ -0,0 +1,56 @@
`timescale 1ns / 1ps
/*============================================================================
Aznable (custom 8-bit computer system) - Generic timer
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-10-20
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module generic_timer #(
parameter COUNTER_WIDTH = 16,
parameter DIVIDER_WIDTH = 15,
parameter INTERVAL = 15'd24000
)(
input clk,
input reset,
output reg [COUNTER_WIDTH-1:0] counter
);
reg [DIVIDER_WIDTH-1:0] divider = {DIVIDER_WIDTH{1'b0}};
always @(posedge clk or posedge reset)
begin
if(reset)
begin
counter <= {COUNTER_WIDTH{1'b0}};
divider <= {DIVIDER_WIDTH{1'b0}};
end
else
begin
if(divider==INTERVAL)
begin
counter <= counter + 1'b1;
divider <= {DIVIDER_WIDTH{1'b0}};
end
else
begin
divider <= divider + 1'b1;
end
end
end
endmodule

View File

@@ -0,0 +1,56 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// DC removal filter
// input is unsigned
// output is signed
module jt49_dcrm(
input clk,
input cen,
input rst,
input [7:0] din,
output reg signed [7:0] dout
);
wire signed [7:0] ave0, ave1;
jt49_mave u_mave0(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( {1'b0, din[7:1] } ),
.dout ( ave0 )
);
jt49_mave u_mave1(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( ave0 ),
.dout ( ave1 )
);
always @(posedge clk)
if( cen )
dout <= ({1'b0,din} - {ave1,1'b0})>>>1;
endmodule

View File

@@ -0,0 +1,64 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// DC removal filter
// input is unsigned
// output is signed
module jt49_dcrm2 #(parameter sw=8) (
input clk,
input cen,
input rst,
input [sw-1:0] din,
output signed [sw-1:0] dout
);
localparam dw=10; // width of the decimal portion
reg signed [sw+dw:0] integ, exact, error;
//reg signed [2*(9+dw)-1:0] mult;
// wire signed [sw+dw:0] plus1 = { {sw+dw{1'b0}},1'b1};
reg signed [sw:0] pre_dout;
// reg signed [sw+dw:0] dout_ext;
reg signed [sw:0] q;
always @(*) begin
exact = integ+error;
q = exact[sw+dw:dw];
pre_dout = { 1'b0, din } - q;
//dout_ext = { pre_dout, {dw{1'b0}} };
//mult = dout_ext;
end
assign dout = pre_dout[sw-1:0];
always @(posedge clk)
if( rst ) begin
integ <= {sw+dw+1{1'b0}};
error <= {sw+dw+1{1'b0}};
end else if( cen ) begin
/* verilator lint_off WIDTH */
integ <= integ + pre_dout; //mult[sw+dw*2:dw];
/* verilator lint_on WIDTH */
error <= exact-{q, {dw{1'b0}}};
end
endmodule

View File

@@ -0,0 +1,67 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// Delay stage
// use for long delays
module jt49_dly #(parameter dw=8, depth=10)(
input clk,
input cen,
input rst,
input [7:0] din,
output reg [7:0] dout,
output reg [7:0] pre_dout
);
reg [depth-1:0] rdpos, wrpos;
// memory
reg [dw-1:0] ram[0:2**depth-1];
always @(posedge clk)
if(rst)
pre_dout <= {dw{1'b0}};
else begin
pre_dout <= ram[rdpos];
if( cen ) ram[wrpos] <= din;
end
`ifdef SIMULATION
integer k;
initial begin
for(k=0;k<=2**depth-1;k=k+1)
ram[k] = 0;
end
`endif
always @(posedge clk)
if( rst ) begin
rdpos <= { {depth-1{1'b0}}, 1'b1};
wrpos <= {depth{1'b1}};
dout <= {dw{1'b0}};
end else if(cen) begin
dout <= pre_dout;
rdpos <= rdpos+1'b1;
wrpos <= wrpos+1'b1;
end
endmodule // jt49_dly

View File

@@ -0,0 +1,60 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// Moving averager
module jt49_mave #(parameter depth=8, dw=8)(
input clk,
input cen,
input rst,
input signed [dw-1:0] din,
output signed [dw-1:0] dout
);
wire [dw-1:0] dly0;
wire [dw-1:0] pre_dly0;
jt49_dly #(.depth(depth),.dw(dw)) u_dly0(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( din ),
.dout ( dly0 ),
.pre_dout ( pre_dly0 )
);
// moving average
// D=2048
reg signed [dw:0] diff;
reg signed [dw+depth-1:0] sum;
always @(posedge clk)
if( rst ) begin
diff <= {dw+1{1'd0}};
sum <= {dw+depth+1{1'd0}};
end else if(cen) begin
diff <= {1'b0,din } - { 1'b0, dly0 };
sum <= { {depth{diff[dw]}}, diff } + sum;
end
assign dout = sum[dw+depth-1:depth];
endmodule

7
rtl/jt49/jt49.qip Normal file
View File

@@ -0,0 +1,7 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_bus.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_cen.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_exp.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_noise.v ]

248
rtl/jt49/jt49.v Normal file
View File

@@ -0,0 +1,248 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49 ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en /* synthesis direct_enable = 1 */,
input [3:0] addr,
input cs_n,
input wr_n, // write
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output reg [7:0] dout,
output reg [9:0] sound, // combined channel output
output reg [7:0] A, // linearised channel output
output reg [7:0] B,
output reg [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
input [7:0] IOB_in,
output [7:0] IOB_out
);
parameter [1:0] COMP=2'b00;
parameter CLKDIV=3;
wire [1:0] comp = COMP;
reg [7:0] regarray[15:0];
wire [7:0] port_A, port_B;
wire [4:0] envelope;
wire bitA, bitB, bitC;
wire noise;
reg Amix, Bmix, Cmix;
wire cen16, cen256;
assign IOA_out = regarray[14];
assign IOB_out = regarray[15];
assign port_A = !regarray[7][6] ? IOA_in : IOA_out;
assign port_B = !regarray[7][7] ? IOB_in : IOB_out;
assign sample = cen16;
jt49_cen #(.CLKDIV(CLKDIV)) u_cen(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( clk_en ),
.sel ( sel ),
.cen16 ( cen16 ),
.cen256 ( cen256 )
);
// internal modules operate at clk/16
jt49_div #(12) u_chA(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[1][3:0], regarray[0][7:0] } ),
.div ( bitA )
);
jt49_div #(12) u_chB(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[3][3:0], regarray[2][7:0] } ),
.div ( bitB )
);
jt49_div #(12) u_chC(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[5][3:0], regarray[4][7:0] } ),
.div ( bitC )
);
jt49_noise u_ng(
.clk ( clk ),
.cen ( cen16 ),
.rst_n ( rst_n ),
.period ( regarray[6][4:0] ),
.noise ( noise )
);
// envelope generator
wire eg_step;
wire [15:0] eg_period = {regarray[4'hc],regarray[4'hb]};
wire null_period = eg_period == 16'h0;
jt49_div #(16) u_envdiv(
.clk ( clk ),
.cen ( cen256 ),
.rst_n ( rst_n ),
.period ( eg_period ),
.div ( eg_step )
);
reg eg_restart;
jt49_eg u_env(
.clk ( clk ),
.cen ( cen256 ),
.step ( eg_step ),
.rst_n ( rst_n ),
.restart ( eg_restart ),
.null_period( null_period ),
.ctrl ( regarray[4'hD][3:0] ),
.env ( envelope )
);
reg [4:0] logA, logB, logC, log;
wire [7:0] lin;
jt49_exp u_exp(
.clk ( clk ),
.comp ( comp ),
.din ( log ),
.dout ( lin )
);
wire [4:0] volA = { regarray[ 8][3:0], regarray[ 8][3] };
wire [4:0] volB = { regarray[ 9][3:0], regarray[ 9][3] };
wire [4:0] volC = { regarray[10][3:0], regarray[10][3] };
wire use_envA = regarray[ 8][4];
wire use_envB = regarray[ 9][4];
wire use_envC = regarray[10][4];
wire use_noA = regarray[ 7][3];
wire use_noB = regarray[ 7][4];
wire use_noC = regarray[ 7][5];
reg [3:0] acc_st;
always @(posedge clk) if( clk_en ) begin
Amix <= (noise|use_noA) & (bitA|regarray[7][0]);
Bmix <= (noise|use_noB) & (bitB|regarray[7][1]);
Cmix <= (noise|use_noC) & (bitC|regarray[7][2]);
logA <= !Amix ? 5'd0 : (use_envA ? envelope : volA );
logB <= !Bmix ? 5'd0 : (use_envB ? envelope : volB );
logC <= !Cmix ? 5'd0 : (use_envC ? envelope : volC );
end
reg [9:0] acc;
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
acc_st <= 4'b1;
acc <= 10'd0;
A <= 8'd0;
B <= 8'd0;
C <= 8'd0;
sound <= 10'd0;
end else if(clk_en) begin
acc_st <= { acc_st[2:0], acc_st[3] };
acc <= acc + {2'b0,lin};
case( acc_st )
4'b0001: begin
log <= logA;
acc <= 10'd0;
sound <= acc;
end
4'b0010: begin
A <= lin;
log <= logB;
end
4'b0100: begin
B <= lin;
log <= logC;
end
4'b1000: begin // last sum
C <= lin;
end
default:;
endcase
end
end
reg [7:0] read_mask;
always @(*)
case(addr)
4'h0,4'h2,4'h4,4'h7,4'hb,4'hc,4'he,4'hf:
read_mask = 8'hff;
4'h1,4'h3,4'h5,4'hd:
read_mask = 8'h0f;
4'h6,4'h8,4'h9,4'ha:
read_mask = 8'h1f;
endcase // addr
// register array
wire write;
reg last_write;
wire wr_edge = write & ~last_write;
assign write = !wr_n && !cs_n;
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
dout <= 8'd0;
last_write <= 0;
eg_restart <= 0;
regarray[0]<=8'd0; regarray[4]<=8'd0; regarray[ 8]<=8'd0; regarray[12]<=8'd0;
regarray[1]<=8'd0; regarray[5]<=8'd0; regarray[ 9]<=8'd0; regarray[13]<=8'd0;
regarray[2]<=8'd0; regarray[6]<=8'd0; regarray[10]<=8'd0; regarray[14]<=8'd0;
regarray[3]<=8'd0; regarray[7]<=8'd0; regarray[11]<=8'd0; regarray[15]<=8'd0;
end else begin
last_write <= write;
// Data read
case( addr )
4'he: dout <= port_A;
4'hf: dout <= port_B;
default: dout <= regarray[ addr ] & read_mask;
endcase
// Data write
if( write ) begin
regarray[addr] <= din;
if ( addr == 4'hD && wr_edge ) eg_restart <= 1;
end else begin
eg_restart <= 0;
end
end
end
endmodule

101
rtl/jt49/jt49_bus.v Normal file
View File

@@ -0,0 +1,101 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 28-Jan-2019
Based on sqmusic, by the same author
*/
// This is a wrapper with the BDIR/BC1 pins
module jt49_bus ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en /* synthesis direct_enable = 1 */,
// bus control pins of original chip
input bdir,
input bc1,
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output [7:0] dout,
output [9:0] sound, // combined channel output
output [7:0] A, // linearised channel output
output [7:0] B,
output [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
input [7:0] IOB_in,
output [7:0] IOB_out
);
parameter [1:0] COMP=2'b00;
reg wr_n, cs_n;
reg [3:0] addr;
reg addr_ok;
reg [7:0] din_latch;
always @(posedge clk)
if( !rst_n ) begin
wr_n <= 1'b1;
cs_n <= 1'b1;
addr <= 4'd0;
addr_ok <= 1'b1;
end else begin // I/O cannot use clk_en
// addr must be
case( {bdir,bc1} )
2'b00: { wr_n, cs_n } <= 2'b11;
2'b01: { wr_n, cs_n } <= addr_ok ? 2'b10 : 2'b11;
2'b10: begin
{ wr_n, cs_n } <= addr_ok ? 2'b00 : 2'b11;
din_latch <= din;
end
2'b11: begin
{ wr_n, cs_n } <= 2'b11;
addr <= din[3:0];
addr_ok <= din[7:4] == 4'd0;
end
endcase // {bdir,bc1}
end
jt49 #(.COMP(COMP)) u_jt49( // note that input ports are not multiplexed
.rst_n ( rst_n ),
.clk ( clk ), // signal on positive edge
.clk_en ( clk_en ), // clock enable on negative edge
.addr ( addr[3:0] ),
.cs_n ( cs_n ),
.wr_n ( wr_n ), // write
.din ( din_latch ),
.sel ( sel ), // if sel is low, the clock is divided by 2
.dout ( dout ),
.sound ( sound ), // combined channel output
.sample ( sample ),
.A ( A ), // linearised channel output
.B ( B ),
.C ( C ),
.IOA_in ( IOA_in ),
.IOA_out( IOA_out ),
.IOB_in ( IOB_in ),
.IOB_out( IOB_out )
);
endmodule // jt49_bus

55
rtl/jt49/jt49_cen.v Normal file
View File

@@ -0,0 +1,55 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_cen(
input clk,
input rst_n,
input cen, // base clock enable signal
input sel, // when low, divide by 2 once more
output reg cen16,
output reg cen256
);
reg [9:0] cencnt;
parameter CLKDIV = 3; // use 3 for standalone JT49 or 2
localparam eg = CLKDIV; //8;
wire toggle16 = sel ? ~|cencnt[CLKDIV-1:0] : ~|cencnt[CLKDIV:0];
wire toggle256= sel ? ~|cencnt[eg-2:0] : ~|cencnt[eg-1:0];
always @(posedge clk, negedge rst_n) begin
if(!rst_n)
cencnt <= 10'd0;
else begin
if(cen) cencnt <= cencnt+10'd1;
end
end
always @(posedge clk) begin
cen16 <= cen & toggle16;
cen256 <= cen & toggle256;
end
endmodule // jt49_cen

52
rtl/jt49/jt49_div.v Normal file
View File

@@ -0,0 +1,52 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_div #(parameter W=12 )(
(* direct_enable *) input cen,
input clk, // this is the divided down clock from the core
input rst_n,
input [W-1:0] period,
output reg div
);
reg [W-1:0]count;
wire [W-1:0] one = { {W-1{1'b0}}, 1'b1};
always @(posedge clk, negedge rst_n ) begin
if( !rst_n) begin
count <= one;
div <= 1'b0;
end
else if(cen) begin
if( count>=period ) begin
count <= one;
div <= ~div;
end
else
/*if( period!={W{1'b0}} )*/ count <= count + one ;
end
end
endmodule

88
rtl/jt49/jt49_eg.v Normal file
View File

@@ -0,0 +1,88 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_eg(
(* direct_enable *) input cen,
input clk, // this is the divided down clock from the core
input step,
input null_period,
input rst_n,
input restart,
input [3:0] ctrl,
output reg [4:0]env
);
reg inv, stop;
reg [4:0] gain;
wire CONT = ctrl[3];
wire ATT = ctrl[2];
wire ALT = ctrl[1];
wire HOLD = ctrl[0];
wire will_hold = !CONT || HOLD;
always @(posedge clk)
if( cen ) env <= inv ? ~gain : gain;
reg last_step;
wire step_edge = (step && !last_step) || null_period;
wire will_invert = (!CONT&&ATT) || (CONT&&ALT);
reg rst_latch, rst_clr;
always @(posedge clk) begin
if( restart ) rst_latch <= 1;
else if(rst_clr ) rst_latch <= 0;
end
always @( posedge clk, negedge rst_n )
if( !rst_n) begin
gain <= 5'h1F;
inv <= 0;
stop <= 0;
rst_clr <= 0;
end
else if( cen ) begin
last_step <= step;
if( rst_latch ) begin
gain <= 5'h1F;
inv <= ATT;
stop <= 1'b0;
rst_clr <= 1;
end
else begin
rst_clr <= 0;
if (step_edge && !stop) begin
if( gain==5'h00 ) begin
if( will_hold )
stop <= 1'b1;
else
gain <= gain-5'b1;
if( will_invert ) inv<=~inv;
end
else gain <= gain-5'b1;
end
end
end
endmodule

174
rtl/jt49/jt49_exp.v Normal file
View File

@@ -0,0 +1,174 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
// Compression vs dynamic range
// 0 -> 43.6dB
// 1 -> 29.1
// 2 -> 21.8
// 3 -> 13.4
module jt49_exp(
input clk,
input [1:0] comp, // compression
input [4:0] din,
output reg [7:0] dout
);
reg [7:0] lut[0:127];
always @(posedge clk)
dout <= lut[ {comp,din} ];
initial begin
lut[0] = 8'd0;
lut[1] = 8'd1;
lut[2] = 8'd1;
lut[3] = 8'd1;
lut[4] = 8'd2;
lut[5] = 8'd2;
lut[6] = 8'd3;
lut[7] = 8'd3;
lut[8] = 8'd4;
lut[9] = 8'd5;
lut[10] = 8'd6;
lut[11] = 8'd7;
lut[12] = 8'd9;
lut[13] = 8'd11;
lut[14] = 8'd13;
lut[15] = 8'd15;
lut[16] = 8'd18;
lut[17] = 8'd22;
lut[18] = 8'd26;
lut[19] = 8'd31;
lut[20] = 8'd37;
lut[21] = 8'd45;
lut[22] = 8'd53;
lut[23] = 8'd63;
lut[24] = 8'd75;
lut[25] = 8'd90;
lut[26] = 8'd107;
lut[27] = 8'd127;
lut[28] = 8'd151;
lut[29] = 8'd180;
lut[30] = 8'd214;
lut[31] = 8'd255;
lut[32] = 8'd0;
lut[33] = 8'd7;
lut[34] = 8'd8;
lut[35] = 8'd10;
lut[36] = 8'd11;
lut[37] = 8'd12;
lut[38] = 8'd14;
lut[39] = 8'd15;
lut[40] = 8'd17;
lut[41] = 8'd20;
lut[42] = 8'd22;
lut[43] = 8'd25;
lut[44] = 8'd28;
lut[45] = 8'd31;
lut[46] = 8'd35;
lut[47] = 8'd40;
lut[48] = 8'd45;
lut[49] = 8'd50;
lut[50] = 8'd56;
lut[51] = 8'd63;
lut[52] = 8'd71;
lut[53] = 8'd80;
lut[54] = 8'd90;
lut[55] = 8'd101;
lut[56] = 8'd113;
lut[57] = 8'd127;
lut[58] = 8'd143;
lut[59] = 8'd160;
lut[60] = 8'd180;
lut[61] = 8'd202;
lut[62] = 8'd227;
lut[63] = 8'd255;
lut[64] = 8'd0;
lut[65] = 8'd18;
lut[66] = 8'd20;
lut[67] = 8'd22;
lut[68] = 8'd24;
lut[69] = 8'd26;
lut[70] = 8'd29;
lut[71] = 8'd31;
lut[72] = 8'd34;
lut[73] = 8'd37;
lut[74] = 8'd41;
lut[75] = 8'd45;
lut[76] = 8'd49;
lut[77] = 8'd53;
lut[78] = 8'd58;
lut[79] = 8'd63;
lut[80] = 8'd69;
lut[81] = 8'd75;
lut[82] = 8'd82;
lut[83] = 8'd90;
lut[84] = 8'd98;
lut[85] = 8'd107;
lut[86] = 8'd116;
lut[87] = 8'd127;
lut[88] = 8'd139;
lut[89] = 8'd151;
lut[90] = 8'd165;
lut[91] = 8'd180;
lut[92] = 8'd196;
lut[93] = 8'd214;
lut[94] = 8'd233;
lut[95] = 8'd255;
lut[96] = 8'd0;
lut[97] = 8'd51;
lut[98] = 8'd54;
lut[99] = 8'd57;
lut[100] = 8'd60;
lut[101] = 8'd63;
lut[102] = 8'd67;
lut[103] = 8'd70;
lut[104] = 8'd74;
lut[105] = 8'd78;
lut[106] = 8'd83;
lut[107] = 8'd87;
lut[108] = 8'd92;
lut[109] = 8'd97;
lut[110] = 8'd103;
lut[111] = 8'd108;
lut[112] = 8'd114;
lut[113] = 8'd120;
lut[114] = 8'd127;
lut[115] = 8'd134;
lut[116] = 8'd141;
lut[117] = 8'd149;
lut[118] = 8'd157;
lut[119] = 8'd166;
lut[120] = 8'd175;
lut[121] = 8'd185;
lut[122] = 8'd195;
lut[123] = 8'd206;
lut[124] = 8'd217;
lut[125] = 8'd229;
lut[126] = 8'd241;
lut[127] = 8'd255;
end
endmodule

62
rtl/jt49/jt49_noise.v Normal file
View File

@@ -0,0 +1,62 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_noise(
(* direct_enable *) input cen,
input clk,
input rst_n,
input [4:0] period,
output reg noise
);
reg [5:0]count;
reg [16:0]poly17;
wire poly17_zero = poly17==17'b0;
wire noise_en;
reg last_en;
wire noise_up = noise_en && !last_en;
always @(posedge clk ) if(cen) begin
noise <= ~poly17[0];
end
always @( posedge clk, negedge rst_n )
if( !rst_n )
poly17 <= 17'd0;
else if( cen ) begin
last_en <= noise_en;
if( noise_up )
poly17 <= { poly17[0] ^ poly17[3] ^ poly17_zero, poly17[16:1] };
end
jt49_div #(5) u_div(
.clk ( clk ),
.cen ( cen ),
.rst_n ( rst_n ),
.period ( period ),
.div ( noise_en )
);
endmodule

4
rtl/jt5205/jt5205.qip Normal file
View File

@@ -0,0 +1,4 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt5205.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt5205_adpcm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt5205_timing.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt5205_interpol2x.v ]

92
rtl/jt5205/jt5205.v Normal file
View File

@@ -0,0 +1,92 @@
/* This file is part of JT5205.
JT5205 program 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.
JT5205 program 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 JT5205. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 30-10-2019 */
module jt5205(
input rst,
input clk,
input cen /* direct_enable */,
input [ 1:0] sel, // s pin
input [ 3:0] din,
output signed [11:0] sound,
output sample,
// This output pin is not part of MSM5205 I/O
// It helps integrating the system as it produces
// a strobe
// at the internal clock divider pace
output irq,
output vclk_o
`ifdef JT5205_DEBUG
,
output signed [11:0] debug_raw,
output debug_cen_lo
`endif
);
// Enabling the interpolator changes the sound of Chun Li's beat in
// SF2 too much. So I decided to disable it
parameter INTERPOL=0; // 1 for simple linear interpolation. 0 for raw output
wire cen_lo, cen_mid;
wire signed [11:0] raw;
assign irq=cen_lo; // Notice that irq is active even if rst is high. This is
// important for games such as Tora e no michi.
`ifdef JT5205_DEBUG
assign debug_raw = raw;
assign debug_cen_lo = cen_lo;
`endif
jt5205_timing u_timing(
.clk ( clk ),
.cen ( cen ),
.sel ( sel ),
.cen_lo ( cen_lo ),
.cen_mid( cen_mid ),
.cenb_lo( ),
.vclk_o (vclk_o )
);
jt5205_adpcm u_adpcm(
.rst ( rst ),
.clk ( clk ),
.cen_lo ( cen_lo ),
.cen_hf ( cen ),
.din ( din ),
.sound ( raw )
);
generate
if( INTERPOL == 1 ) begin
jt5205_interpol2x u_interpol(
.rst ( rst ),
.clk ( clk ),
.cen_mid( cen_mid ),
.din ( raw ),
.dout ( sound )
);
assign sample=cen_mid; // 2x the original sampling freq. because of interpolator
end else begin
assign sound = raw;
assign sample = cen_lo;
end
endgenerate
endmodule

120
rtl/jt5205/jt5205_adpcm.v Normal file
View File

@@ -0,0 +1,120 @@
/* This file is part of JT5205.
JT5205 program 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.
JT5205 program 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 JT5205. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 30-10-2019 */
module jt5205_adpcm(
input rst,
input clk,
(* direct_enable *) input cen_hf,
(* direct_enable *) input cen_lo,
input [ 3:0] din,
output reg signed [11:0] sound
);
reg [ 5:0] delta_idx, idx_inc;
reg [10:0] delta[0:48];
reg [11:0] dn;
reg [12:0] qn;
reg up;
reg [ 2:0] factor;
reg [ 3:0] din_copy;
reg [ 5:0] next_idx;
reg signed [13:0] unlim;
`ifdef SIMULATION
initial begin
sound = -12'd2;
end
`endif
always @(posedge clk, posedge rst) begin
if( rst ) begin
factor <= 3'd0;
up <= 1'b0;
next_idx <= 6'd0;
dn <= 12'd0;
qn <= 13'd0;
end else if(cen_hf) begin
up <= cen_lo;
if( up ) begin
factor <= din_copy[2:0];
dn <= { 1'b0, delta[delta_idx] };
qn <= { 2'd0, delta[delta_idx]>>3};
next_idx <= din_copy[2] ? (delta_idx+idx_inc) : (delta_idx-6'd1);
end else begin
if(factor[2]) begin
qn <= qn + {1'b0, dn };
end
dn <= dn>>1;
factor <= factor<<1;
if( next_idx>6'd48)
next_idx <= din_copy[2] ? 6'd48 : 6'd0;
end
end
end
always @(posedge clk ) if(cen_lo) begin
if( rst ) begin
// sound fades away after a rst but the rest level must be -2
// otherwise noises can be heard (e.g. intro scene of Double Dragon)
if( sound>12'd0 || sound < -12'd2 )
sound <= sound >>> 1;
else
sound <= -12'd2;
end else begin
sound <= unlim[13:12]!={2{unlim[11]}} ? { unlim[13], {11{~unlim[13]}}} : unlim[11:0];
end
end
function signed [13:0] extend;
input signed [11:0] a;
extend = { {2{a[11]}}, a };
endfunction
always @(*) begin
unlim = din_copy[3] ? extend(sound) - {1'b0, qn} :
extend(sound) + {1'b0, qn};
end
always @(posedge clk, posedge rst) begin
if( rst ) begin
delta_idx <= 6'd0;
din_copy <= 4'd0;
end else if(cen_lo) begin
case( din[1:0] )
2'd0: idx_inc <= 6'd2;
2'd1: idx_inc <= 6'd4;
2'd2: idx_inc <= 6'd6;
2'd3: idx_inc <= 6'd8;
endcase
din_copy <= din;
delta_idx <= next_idx;
end
end
initial begin
delta[ 0] = 11'd0016; delta[ 1] = 11'd0017; delta[ 2] = 11'd0019; delta[ 3] = 11'd0021; delta[ 4] = 11'd0023; delta[ 5] = 11'd0025; delta[ 6] = 11'd0028;
delta[ 7] = 11'd0031; delta[ 8] = 11'd0034; delta[ 9] = 11'd0037; delta[10] = 11'd0041; delta[11] = 11'd0045; delta[12] = 11'd0050; delta[13] = 11'd0055;
delta[14] = 11'd0060; delta[15] = 11'd0066; delta[16] = 11'd0073; delta[17] = 11'd0080; delta[18] = 11'd0088; delta[19] = 11'd0097; delta[20] = 11'd0107;
delta[21] = 11'd0118; delta[22] = 11'd0130; delta[23] = 11'd0143; delta[24] = 11'd0157; delta[25] = 11'd0173; delta[26] = 11'd0190; delta[27] = 11'd0209;
delta[28] = 11'd0230; delta[29] = 11'd0253; delta[30] = 11'd0279; delta[31] = 11'd0307; delta[32] = 11'd0337; delta[33] = 11'd0371; delta[34] = 11'd0408;
delta[35] = 11'd0449; delta[36] = 11'd0494; delta[37] = 11'd0544; delta[38] = 11'd0598; delta[39] = 11'd0658; delta[40] = 11'd0724; delta[41] = 11'd0796;
delta[42] = 11'd0876; delta[43] = 11'd0963; delta[44] = 11'd1060; delta[45] = 11'd1166; delta[46] = 11'd1282; delta[47] = 11'd1411; delta[48] = 11'd1552;
end
endmodule

View File

@@ -0,0 +1,43 @@
/* This file is part of JT5205.
JT5205 program 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.
JT5205 program 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 JT5205. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 30-12-2019 */
// Simple 2x interpolator
// Reduces HF content without altering too much the
// original sound
module jt5205_interpol2x(
input rst,
input clk,
(* direct_enable *) input cen_mid,
input signed [11:0] din,
output reg signed [11:0] dout
);
reg signed [11:0] last;
always @(posedge clk, posedge rst) begin
if(rst) begin
last <= 12'd0;
dout <= 12'd0;
end else if(cen_mid) begin
last <= din;
dout <= (last>>>1)+(din>>>1);
end
end
endmodule

View File

@@ -0,0 +1,69 @@
/* This file is part of JT5205.
JT5205 program 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.
JT5205 program 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 JT5205. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 30-10-2019 */
module jt5205_timing(
input clk,
(* direct_enable *) input cen,
input [ 1:0] sel, // s pin
output cen_lo, // sample rate
output cenb_lo, // sample rate (opposite phase)
output cen_mid, // 2x sample rate
output reg vclk_o
);
reg [6:0] cnt=7'd0;
reg pre=1'b0, preb=1'b0;
reg [6:0] lim;
always @(posedge clk) begin
case(sel)
2'd0: lim <= 7'd95;
2'd1: lim <= 7'd63;
2'd2: lim <= 7'd47;
2'd3: lim <= 7'd1;
endcase
end
always @(posedge clk) begin
if (sel == 2'd3) begin
cnt <= 7'd0;
vclk_o <= 1'b0;
end
if(cen) begin
if (sel != 2'd3) cnt <= cnt + 7'd1;
pre <= 1'b0;
preb <= 1'b0;
if(cnt==lim) begin
vclk_o <= 1'b1;
cnt <= 7'd0;
pre <= 1'b1;
end
if(cnt==(lim>>1)) begin
preb <=1'b1;
vclk_o <= 1'b0;
end
end
end
assign cen_lo = pre &cen;
assign cenb_lo = preb&cen;
assign cen_mid = (pre|preb)&cen;
endmodule

41
rtl/lfsr.v Normal file
View File

@@ -0,0 +1,41 @@
/*============================================================================
Aznable (custom 8-bit computer system) - Linear-feedback shift register
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-11-06
Based on Project F: Ad Astra - Starfield
(C)2021 Will Green, open source hardware released under the MIT License
Learn more at https://projectf.io
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module lfsr #(
parameter LEN=8, // shift register length
parameter TAPS=8'b10111000 // XOR taps
) (
input wire clk, // clock
input wire rst, // reset
input wire en, // enable
input wire [LEN-1:0] seed,
output reg [LEN-1:0] sreg // lfsr output
);
always @(posedge clk) begin
if (en) sreg <= {1'b0, sreg[LEN-1:1]} ^ (sreg[0] ? TAPS : {LEN{1'b0}});
if (rst) sreg <= seed;
end
endmodule

4096
rtl/music.hex Normal file

File diff suppressed because it is too large Load Diff

443
rtl/music.v Normal file
View File

@@ -0,0 +1,443 @@
`timescale 1ns / 1ps
/*============================================================================
Aznable (custom 8-bit computer system) - Deikun (music engine)
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 0.1
Date: 2021-11-20
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module music #(
parameter ROM_WIDTH = 17
)(
input clk,
input ce_2,
input reset,
input [1:0] addr,
input [7:0] data_in,
output [7:0] data_out,
input write,
input [7:0] musicrom_data_out,
output reg [ROM_WIDTH-1:0] musicrom_addr,
output [9:0] audio_out
);
// Music system state machine (ym player)
// - Currently recognises YM5/YM6 formats
// - Handles interleaved/non-interleaved data
// - Ignores DigiDrum samples completely
// - Variable play rate (50/60hz)
// - Recognises loop point
reg [7:0] regarray[3:0];
// Music control registers
// 0 - 1 = play, 2 = loop, 3 = stop
// 1-3 - Start address of music to play in ROM
assign data_out = { 6'b0, ymp_loop, ymp_playing };
// YM2149 audio_out generator
reg [7:0] snd_data_in;
reg snd_wr;
jt49 jt49_music(
.clk(clk),
.clk_en(ce_2),
.rst_n(~(reset || ymp_state == YM_INIT || ymp_state == YM_STOPPED )), // Hold YM2149 in reset while player state is initialising or stopped
.addr(ymp_register),
.din(snd_data_in),
.dout(),
.sound(audio_out),
.sample(),
.A(),
.B(),
.C(),
.sel(1'b1),
.cs_n(1'b0),
.wr_n(~snd_wr),
.IOA_in(),
.IOA_out(),
.IOB_in(),
.IOB_out()
);
localparam YM_INIT = 0;
localparam YM_WAIT = 1;
localparam YM_GETMODE = 2;
localparam YM_GETLENGTH_0 = 3;
localparam YM_GETLENGTH_1 = 4;
localparam YM_GETFREQUENCY = 5;
localparam YM_GETLOOP_0 = 6;
localparam YM_GETLOOP_1 = 7;
localparam YM_SKIPSTRINGS = 8;
localparam YM_STOPPED = 9;
localparam YM_WAITFORFRAME = 12;
localparam YM_GETREGISTER = 13;
localparam YM_SETREGISTER = 14;
localparam YM_NEXTREGISTER = 15;
localparam YM_REGCOUNT = 16;
reg [ROM_WIDTH-1:0] ymp_trackoffset;
reg ymp_playing;
reg ymp_loop;
reg [3:0] ymp_state;
reg [3:0] ymp_state_next;
reg [ROM_WIDTH-1:0] ymp_frame;
reg [3:0] ymp_register;
reg ymp_interleave;
reg ymp_is_50hz;
reg [2:0] ymp_skipstringindex = 3'b0;
reg [ROM_WIDTH-1:0] ymp_firstframe;
reg [ROM_WIDTH-1:0] ymp_length;
reg [ROM_WIDTH-1:0] ymp_looppoint;
reg [(YM_REGCOUNT * 8)-1:0] ymp_registermask = {
8'b00000000,
8'b00000000,
8'b00001111,
8'b11111111,
8'b11111111,
8'b00011111,
8'b00011111,
8'b00011111,
8'b11111111,
8'b00011111,
8'b00001111,
8'b11111111,
8'b00001111,
8'b11111111,
8'b00001111,
8'b11111111
};
reg [19:0] frame_timer_50;
reg [19:0] frame_timer_60;
localparam [19:0] frame_timer_max_50 = 20'd480000;
localparam [19:0] frame_timer_max_60 = 20'd400000;
reg frame_ready;
//`define YM_DEBUG
always @(posedge clk)
begin
// Frame timers
frame_timer_50 <= frame_timer_50 + 20'd1;
if(frame_timer_50 == frame_timer_max_50)
begin
frame_timer_50 <= 20'd0;
if(ymp_is_50hz) frame_ready <= 1'b1;
end
frame_timer_60 <= frame_timer_60 + 20'd1;
if(frame_timer_60 == frame_timer_max_60)
begin
frame_timer_60 <= 20'd0;
if(!ymp_is_50hz) frame_ready <= 1'b1;
end
if( reset ) begin
regarray[0]<=8'd0;
regarray[1]<=8'd0;
regarray[2]<=8'd0;
regarray[3]<=8'd0;
ymp_state <= YM_INIT;
ymp_skipstringindex <= 3'b0;
end
else
begin
if( write ) begin
`ifdef YM_DEBUG
$display("YM->RAM->WRITE %x %x", addr, data_in);
`endif
regarray[addr] <= data_in;
end
else
begin
case(regarray[0])
8'd1:
begin
`ifdef YM_DEBUG
$display("YM->PLAY-TRACK %d %d", {regarray[1], regarray[2], regarray[3]}, regarray[0][1:0]);
`endif
regarray[0] <= 8'd0;
/* verilator lint_off WIDTH */
ymp_trackoffset <= {{regarray[1], regarray[2], regarray[3]}};
/* verilator lint_on WIDTH */
ymp_playing <= 1'b1;
ymp_loop <= 1'b0;
ymp_state <= YM_INIT;
end
8'd2:
begin
`ifdef YM_DEBUG
$display("YM->LOOP-TRACK %d %d", {regarray[1], regarray[2], regarray[3]}, regarray[0][1:0]);
`endif
regarray[0] <= 8'd0;
/* verilator lint_off WIDTH */
ymp_trackoffset <= {{regarray[1], regarray[2], regarray[3]}};
/* verilator lint_on WIDTH */
ymp_playing <= 1'b1;
ymp_loop <= 1'b1;
ymp_state <= YM_INIT;
end
8'd3:
begin
`ifdef YM_DEBUG
$display("YM->STOP-TRACK");
`endif
ymp_playing <= 0;
regarray[0]<=8'd0;
regarray[1]<=8'd0;
regarray[2]<=8'd0;
regarray[3]<=8'd0;
ymp_state <= YM_STOPPED;
end
default:
begin
end
endcase
end
case (ymp_state)
YM_INIT:
begin
if(ymp_playing)
begin
`ifdef YM_DEBUG
$display("YM_INIT");
`endif
// Reset player frame and register
ymp_frame <= {ROM_WIDTH{1'b0}};
ymp_register <= 4'b0;
ymp_skipstringindex <= 3'b0;
// Set address to read first song attribute byte
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h13};
ymp_state_next <= YM_GETMODE;
ymp_state <= YM_WAIT;
end
end
YM_WAIT:
begin
ymp_state <= ymp_state_next;
end
YM_GETMODE:
begin
`ifdef YM_DEBUG
$display("YM_GETMODE %x %x", musicrom_addr, musicrom_data_out);
`endif
ymp_interleave <= musicrom_data_out[0];
// Set address to read song length byte 0
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h0f};
ymp_state <= YM_WAIT;
ymp_state_next <= YM_GETLENGTH_0;
end
// Get song length
YM_GETLENGTH_0:
begin
`ifdef YM_DEBUG
$display("YM_GETLENGTH_0 %x %x", musicrom_addr, musicrom_data_out);
`endif
// Read song length byte 0
ymp_length[7:0] <= musicrom_data_out;
// Set address to read song length byte 1
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h0e};
ymp_state <= YM_WAIT;
ymp_state_next <= YM_GETLENGTH_1;
end
YM_GETLENGTH_1:
begin
`ifdef YM_DEBUG
$display("YM_GETLENGTH_1 %x %x", musicrom_addr, musicrom_data_out);
`endif
// Read song length byte 1
ymp_length[14:8] <= musicrom_data_out[6:0];
// Set address to frequency point
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h1b};
ymp_state <= YM_WAIT;
ymp_state_next <= YM_GETFREQUENCY;
end
// Get song playback frequency
YM_GETFREQUENCY:
begin
`ifdef YM_DEBUG
$display("YM_GETFREQUENCY %x %x", musicrom_addr, musicrom_data_out);
`endif
// Read song length byte 1
ymp_is_50hz <= musicrom_data_out[7:0] == 8'd50;
// Set address to loop point
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h1f};
ymp_state <= YM_WAIT;
ymp_state_next <= YM_GETLOOP_0;
end
// Get song loop point
YM_GETLOOP_0:
begin
`ifdef YM_DEBUG
$display("YM_GETLOOP_0 %x %x", musicrom_addr, musicrom_data_out);
`endif
// Read song loop point byte 0
ymp_looppoint[7:0] <= musicrom_data_out;
// Set address to read song length byte 1
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h1e};
ymp_state <= YM_WAIT;
ymp_state_next <= YM_GETLOOP_1;
end
YM_GETLOOP_1:
begin
`ifdef YM_DEBUG
$display("YM_GETLOOP_1 %x %x", musicrom_addr, musicrom_data_out);
`endif
// Read song loop point byte 1
ymp_looppoint[14:8] <= musicrom_data_out[6:0];
// Set address to read past NT-string data
musicrom_addr <= ymp_trackoffset + {{ROM_WIDTH-8{1'b0}},8'h22};
ymp_state <= YM_WAIT;
ymp_state_next <= YM_SKIPSTRINGS;
end
// Skip past null terminated strings to find first frame data point
YM_SKIPSTRINGS:
begin
`ifdef YM_DEBUG
$display("YM_SKIPSTRINGS %x %x", musicrom_addr, musicrom_data_out);
`endif
if(musicrom_data_out == 8'b0)
begin
if(ymp_skipstringindex == 3'd2)
begin
ymp_firstframe <= musicrom_addr - ymp_trackoffset;
ymp_state <= YM_WAITFORFRAME;
end
else
begin
ymp_skipstringindex <= ymp_skipstringindex + 3'b1;
end
end
musicrom_addr <= musicrom_addr + {{ROM_WIDTH-1{1'b0}},1'b1};
end
// Main loop - wait for next vertical blank
YM_WAITFORFRAME:
begin
if(!ymp_playing)
begin
`ifdef YM_DEBUG
$display("ymp_playing %d - STOPPING MUSIC", ymp_playing);
`endif
ymp_state <= YM_INIT;
end
if(frame_ready)
begin
`ifdef YM_DEBUG
$display("YM_WAITFORFRAME f=%d l=%d ff=%d", ymp_frame, ymp_length, ymp_firstframe);
`endif
frame_ready <= 1'b0;
ymp_register <= 4'b0;
ymp_state <= YM_WAIT;
ymp_state_next <= YM_GETREGISTER;
end
end
YM_GETREGISTER:
begin
// Calculate address for this frame+register combo in ROM
// - If ymp_interleave=1 then position is (register * length) + frame
// - If ymp_interleave=0 then position is (frame * 16) + register
`ifdef YM_DEBUG
$display("YM_GETREGISTER I %d F %d / %d R %d - A %x D %x", ymp_interleave, ymp_frame, ymp_length, ymp_register, musicrom_addr, musicrom_data_out);
`endif
if(ymp_interleave)
begin
musicrom_addr <= ymp_trackoffset + (ymp_register * ymp_length) + ymp_frame + ymp_firstframe;
end
else
begin
musicrom_addr <= ymp_trackoffset + {ymp_frame[11:0], 4'b0} + ymp_firstframe;
end
ymp_state <= YM_WAIT;
ymp_state_next <= YM_SETREGISTER;
end
YM_SETREGISTER:
begin
`ifdef YM_DEBUG
$display("YM_SETREGISTER I %d F %d / %d R %d - A %x D %x", ymp_interleave,ymp_frame, ymp_length, ymp_register, musicrom_addr, musicrom_data_out);
`endif
snd_data_in <= musicrom_data_out & ymp_registermask[{ymp_register, 3'b0}+:8];
snd_wr <= 1'b1;
ymp_state <= YM_NEXTREGISTER;
end
YM_NEXTREGISTER:
begin
`ifdef YM_DEBUG
$display("YM_NEXTREGISTER I %d F %d / %d R %d - A %x D %x", ymp_interleave,ymp_frame, ymp_length, ymp_register, musicrom_addr, musicrom_data_out);
`endif
snd_wr <= 1'b0;
if(ymp_register == 4'd13)
begin
ymp_frame <= ymp_frame + 16'd1;
ymp_state <= YM_WAITFORFRAME;
if((ymp_frame + 16'd1)== ymp_length )
begin
if(ymp_loop)
begin
// Set frame back to loop start
`ifdef YM_DEBUG
$display("YM LOOP I %d F %d / %d R %d - A %x D %x", ymp_interleave,ymp_frame, ymp_length, ymp_register, musicrom_addr, musicrom_data_out);
`endif
ymp_frame <= ymp_looppoint;
end
else
begin
// Stop playing
ymp_playing <= 0;
regarray[0]<=8'd0;
regarray[1]<=8'd0;
regarray[2]<=8'd0;
regarray[3]<=8'd0;
ymp_state <= YM_STOPPED;
end
end
end
else
begin
ymp_register <= ymp_register + 4'b1;
ymp_state <= YM_GETREGISTER;
end
end
endcase
end
end
endmodule

16
rtl/palette.hex Normal file
View File

@@ -0,0 +1,16 @@
00 00 d6 b5 a9 4a bd ef 94 a5 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
00 00 80 0f 80 1f 81 bf 83 7f fe 40 ff e0 ff ff
fc 80 bc 40 82 a6 81 e4 81 83 81 02 fd 16 fc 10
bd ff fe eb d5 80 80 07 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
00 00 83 ff 83 7f 82 df 81 b6 80 8d 80 00 ff ff
d7 3f 90 9b 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
00 00 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0
83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0 83 e0

100
rtl/pause.v Normal file
View File

@@ -0,0 +1,100 @@
//============================================================================
// Generic pause handling for MiSTer cores.
//
// https://github.com/JimmyStones/Pause_MiSTer
//
// Copyright (c) 2021 Jim Gregory
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//============================================================================
/*
Features:
- Pause can be triggered by user input, hiscore module or OSD opening (optionally controlled by setting in OSD)
- When paused the RGB outputs will be halved after 10 seconds to reduce burn-in (optionally controlled by setting in OSD)
- Reset signal will cancel user triggered pause
Version history:
0001 - 2021-03-15 - First marked release
0002 - 2021-08-28 - Add optional output of dim_video signal (currently used by Galaga)
============================================================================
*/
module pause #(
parameter RW=8, // Width of red channel
parameter GW=8, // Width of green channel
parameter BW=8, // Width of blue channel
parameter CLKSPD = 12 // Main clock speed in MHz
)
(
input clk_sys, // Core system clock (should match HPS module)
input reset, // CPU reset signal (active-high)
input user_button, // User pause button signal (active-high)
input pause_request, // Pause requested by other code (active-high)
input [1:0] options, // Pause options from OSD
// [0] = pause in OSD (active-high)
// [1] = dim video (active-high)
input OSD_STATUS, // OSD is open (active-high)
input [(RW-1):0] r, // Red channel
input [(GW-1):0] g, // Green channel
input [(BW-1):0] b, // Blue channel
output pause_cpu, // Pause signal to CPU (active-high)
`ifdef PAUSE_OUTPUT_DIM
output dim_video, // Dim video requested (active-high)
`endif
output [(RW+GW+BW-1):0] rgb_out // RGB output to arcade_video module
);
// Option constants
localparam pause_in_osd = 1'b0;
localparam dim_video_timer= 1'b1;
reg pause_toggle = 1'b0; // User paused (active-high)
reg [31:0] pause_timer = 32'b0; // Time since pause
reg [31:0] dim_timeout = (CLKSPD*10000000); // Time until video output dim (10 seconds @ CLKSPD Mhz)
`ifndef PAUSE_OUTPUT_DIM
wire dim_video; // Dim video requested (active-high)
`endif
assign pause_cpu = (pause_request | pause_toggle | (OSD_STATUS & options[pause_in_osd])) & !reset;
assign dim_video = (pause_timer >= dim_timeout);
always @(posedge clk_sys) begin
// Track user pause button down
reg user_button_last;
user_button_last <= user_button;
if(!user_button_last & user_button) pause_toggle <= ~pause_toggle;
// Clear user pause on reset
if(pause_toggle & reset) pause_toggle <= 0;
if(pause_cpu & options[dim_video_timer])
begin
// Track pause duration for video dim
if((pause_timer<dim_timeout))
begin
pause_timer <= pause_timer + 1'b1;
end
end
else
begin
pause_timer <= 32'b0;
end
end
assign rgb_out = dim_video ? {r >> 1,g >> 1, b >> 1} : {r,g,b};
endmodule

View File

@@ -1,4 +0,0 @@
set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*"

File diff suppressed because it is too large Load Diff

722
rtl/sound.hex Normal file
View File

@@ -0,0 +1,722 @@
08 81 98 08 18 08 91 90 1b 3b 2b 4d 23 d1 82 a1
d2 8a 09 86 99 10 9a 5a 23 78 48 88 b1 1a 07 08
32 f3 93 7a f0 2a 01 a8 31 00 cc c8 42 8b 3e 88
51 98 96 12 8a 95 9a e8 80 6b 0a 11 98 58 02 a9
80 a1 58 83 f8 28 c1 99 9a 18 1f 20 a2 29 91 72
e3 a8 58 8a 01 d2 39 09 11 a9 2d 81 01 00 3a 70
92 a3 0a 20 c5 8e a3 1a 12 90 fc 09 22 e8 29 90
29 3a 68 c2 99 01 90 c3 93 c3 8c 78 92 19 2a 1c
12 81 04 ab 79 a4 91 90 19 90 08 a6 98 84 c9 70
0e 18 80 91 80 0a 0b b8 04 08 cb 18 39 86 c1 08
39 b4 d3 18 5b 09 83 92 6e 29 28 a7 89 80 01 00
b4 0d 10 30 ae 20 82 00 c0 1a 03 b2 d2 b0 89 f0
49 8c 1b 68 80 88 a3 88 0a d1 a1 8d 82 84 93 3f
00 91 84 81 8f 18 19 04 89 89 12 01 c6 28 29 81
a1 04 83 59 0c a0 d1 88 3a 8f 02 1e 10 1a d1 05
a1 08 81 89 e1 3e 38 89 28 0b 3b b7 a9 11 91 8a
02 b0 18 1c 12 b8 bf 0b 18 1a f0 c8 40 90 2a d7
0a 18 19 08 30 22 80 a4 04 cb 21 0b 75 98 0c d5
09 19 19 28 09 08 90 c4 b3 05 8a 28 4c 29 20 d0
11 a8 1b 82 cc 02 9f 28 98 a2 c9 03 4d 00 d0 8a
00 2f a2 70 98 a3 99 58 09 02 84 ab 49 83 80 91
60 4c 90 39 9a c2 a5 90 90 b2 89 09 12 78 08 0e
88 20 2d 43 3c 03 e3 b2 9a 28 b0 9a da 28 88 b8
ad 7a 18 d8 49 90 95 90 90 12 b9 0c 48 80 39 b5
a8 2a 03 32 5d 02 2b 94 0b 11 58 c5 9c 08 82 90
20 c4 29 01 1c 38 73 b3 78 90 80 2b 10 05 c2 b8
18 3a 80 99 1e 11 b3 0e a6 b4 be 22 8b 8c 18 a0
c2 00 b0 3a ba 18 78 25 80 90 1d 80 02 9e 80 11
88 85 90 b1 12 72 0b 79 01 99 21 29 90 21 3f d1
80 d0 a3 0a 1a 14 b3 b0 4a 4d 29 18 08 9b 3a 7e
a7 89 81 82 b2 88 e8 12 a0 5b 18 18 14 9c 18 18
88 d8 10 88 b0 b0 e9 02 9a 99 3c 79 a4 00 68 91
38 91 b7 90 3b d2 22 ba 11 88 09 90 7a 88 98 7a
a6 09 82 88 81 0e 91 10 a9 22 d8 83 83 93 ef 30
80 11 ab 4c 00 83 81 c9 a3 11 5e 18 90 30 0a 94
a6 a9 83 29 09 8c a0 6a 92 8a 58 a9 e8 88 88 a2
1f 12 18 90 58 37 c8 90 21 18 02 80 26 19 4d 80
a9 31 f3 1b 29 a8 10 c9 3a 8a 97 9a 16 d0 89 2a
00 10 b3 18 bb 10 68 b9 e9 52 1a 93 9e 40 18 90
a1 12 e8 10 09 01 c2 2a d1 10 39 4b aa 17 3a 02
89 a0 49 c7 4b 19 00 c1 12 9a 2a 6a aa 13 f2 29
ab a7 2b a3 80 9e 28 92 a9 09 10 6c 92 9a 4a 10
88 c6 98 39 e3 00 80 b1 49 01 8a 5a a5 8c 30 8e
80 08 b5 b8 10 19 a4 88 b7 82 4c 80 11 23 aa 6d
18 18 01 91 d9 41 a2 c8 89 59 92 99 80 90 1b 16
12 b0 12 7c 11 c9 48 88 28 0b a8 a4 b1 f8 88 80
c8 31 f0 91 3b 5b 10 b3 8d 81 2c 08 20 b9 03 5b
13 f2 a0 b1 21 4a d9 2b 59 49 c4 00 aa 58 a2 08
5a 49 80 a1 25 01 81 a9 87 b2 91 88 69 4d 18 91
0a 32 b9 13 3d d0 03 92 18 18 d2 99 8f 8a b6 10
0b d2 4b b6 8c 08 a3 0b 2a 3d 29 99 13 b2 c4 a8
82 b5 d0 20 0c 3a 82 3e 40 b0 85 8a 80 03 94 a9
4b 20 b2 38 d1 85 19 9d 53 81 31 c9 50 89 a8 10
00 79 aa 58 89 a4 c0 00 82 b0 85 bb 48 a9 3b 23
c8 90 c1 6b 0b 22 c0 1a 3e 31 a9 f0 02 0b d8 19
84 2a c2 3b c0 19 49 01 87 22 0c 08 61 ca 11 01
bb 37 90 01 d9 49 20 aa 02 90 8c 10 4d 19 a1 80
8a 95 a8 94 c8 6a 91 88 28 c4 aa 22 0b 27 09 8a
68 19 01 2e 82 08 9b d3 b9 27 1d 81 09 81 80 88
c3 80 2a 2e 4b 48 c8 11 08 b0 82 94 87 a2 1b 2a
1a 58 91 59 98 08 30 dd 42 90 c3 82 a9 e0 98 32
69 81 9a 0c 27 89 88 09 5a 0a 83 14 ba 88 49 a5
bc 18 a5 00 b0 aa 99 7a b1 01 41 bf 10 3a 83 b5
ca 40 9a 2a 83 84 1c 09 85 b2 85 bb 39 28 40 8d
04 83 98 09 50 9a 58 9c 95 13 ca 11 28 b0 3a c3
2d 02 d3 1d 21 99 1b 32 c8 8d d4 81 0b a9 51 8b
01 90 b1 06 8c 09 61 b1 b0 2c 31 08 19 f1 18 41
a0 8a 40 8b 5a b5 88 11 c0 b1 69 02 bb 00 3f 01
0a 92 a8 28 95 d0 3b 82 ba 71 c9 1a 40 91 a9 e3
98 03 1c 1f 19 22 b9 18 3a f4 b1 09 20 68 a9 94
29 82 90 94 3d 11 a9 39 e2 49 2c 12 90 91 d4 0b
86 1b 10 82 ab 4f 20 02 b1 08 e2 0c 03 11 1d 2a
18 9c 97 18 81 a8 28 0b 93 86 ea 39 09 b0 05 2a
bc 18 2b 8c 03 e0 82 c2 b4 0f 28 a1 09 83 1a ae
33 0a 12 f8 88 11 91 18 61 ac 84 10 d0 29 a2 30
83 e3 8e 2a 41 98 83 10 10 ab 78 00 a4 98 14 c3
3c 09 82 00 b1 f9 7b 11 89 00 a2 a2 9b 5a 4b 93
c1 c4 a2 8f 3b 01 99 16 b8 b3 4a 8a 02 0a 11 0c
07 9a 38 09 88 86 d8 89 23 81 1a f2 0e 11 2b 01
88 05 b0 a9 58 8b 82 93 f1 20 0d 02 19 1b a5 a6
9b 28 0a 32 d2 c1 91 1a 21 7b a1 12 a9 a8 6c 20
03 a5 aa d3 1c 09 21 19 99 f2 18 0c 29 92 f9 10
99 23 00 4c 02 c4 9b 14 0a 29 82 00 10 7a 85 c8
81 28 a4 42 f0 19 2a 94 01 00 a2 cc 58 81 18 a0
80 30 0c 39 f9 31 b9 94 2f 02 1b b5 80 99 01 3d
9b 26 9b 09 06 88 0b 99 94 23 dc 28 01 11 a5 a8
bc 0b 93 1a 15 2c 12 20 93 8a a0 91 75 b0 0b 13
3c d0 92 6b d1 1a 21 13 1e a2 cb 22 09 33 da 08
83 22 df 00 11 09 8a a0 12 bd 23 45 cd 10 81 81
58 d9 00 89 23 9f 83 99 10 2c 11 c9 41 a0 61 a0
18 94 0b 58 a2 0b 84 90 60 a1 89 2a 91 91 aa 75
b0 8a 61 aa 92 11 8a 50 d8 12 90 93 3c 82 0e 28
9a a5 21 ab 80 94 0d a3 91 9e 34 bf 82 8a 9a 12
b0 8a 2a 07 d8 29 00 18 09 b7 2b d2 1a a1 09 33
88 4e 05 8a 30 03 a2 18 d8 63 1a 88 a1 12 c8 10
58 23 9f e0 31 a9 08 12 9f 92 0d 81 10 99 83 2d
91 81 8a 08 e0 48 a0 40 9a 00 98 2b 87 2f 18 b8
11 30 90 1a 81 88 07 bf 28 a4 9a 52 00 1a b8 88
46 8c 81 13 1a ca 34 8a 02 2b a0 90 76 09 89 00
02 1a b2 9f 32 b0 30 5a e9 82 1c c2 3b 92 18 b1
a0 ae 88 9a 58 90 3f b5 0a 02 0c 91 00 ba c8 30
cc 82 88 71 fa 80 21 19 89 13 88 13 9e ab a7 78
88 89 00 33 01 2c e9 22 01 88 89 24 9a 8b d1 10
02 39 92 2b 27 1c 92 3e a5 0a 84 1a a4 39 f9 8a
98 30 03 4b a3 8e 98 32 a4 3f a4 9a 85 10 88 99
9a 92 71 9a 13 0a c8 21 91 ca 30 91 26 4a d1 21
80 89 19 86 2a 84 31 04 2f e0 18 a1 31 98 19 a0
48 b9 10 10 ba 83 fa 21 61 ca 0a b9 40 c2 40 aa
09 fc 82 01 29 c9 38 b4 2b ca a3 82 11 8d 9b 93
70 92 98 51 c1 30 fc 10 03 78 b8 03 1b 90 cb 33
9a 07 3a a2 0c c2 41 88 80 88 08 93 73 9c 33 ac
83 71 a9 80 21 8b 24 0a 02 0d 91 04 48 fb 02 18
89 a4 2c a2 0a 80 bb aa 17 38 bc 98 80 54 9b 88
82 28 fa 0c d1 61 9a 03 10 9a a0 50 bc 83 31 80
01 81 8b fb a3 71 1b 91 92 2a f0 11 18 45 8d 80
11 1c d0 00 08 08 89 a9 14 b9 53 9a c9 84 39 dd
98 80 80 53 19 8a b1 19 de a1 00 45 11 28 a9 cb
db 37 19 80 88 38 bb 12 33 40 91 d8 1b b0 28 88
f9 03 78 b8 22 bc 84 31 1a 86 30 ba 81 11 bf 80
9b b1 73 09 b8 21 ca 44 21 1a 90 f8 80 43 9d 96
29 b0 10 81 0a c8 08 54 8c ca 04 29 91 89 89 be
92 11 11 88 38 f9 8a 17 41 0a a1 9b 88 88 02 71
00 85 8b 04 34 ad b0 60 89 9b 04 10 99 00 84 20
99 88 88 14 79 b3 61 8b ea 80 12 29 a2 29 cd aa
92 51 cb 15 20 88 ad c0 54 08 98 99 98 9b a1 21
a8 54 18 91 0d ab 82 12 78 a0 02 31 9c c1 19 03
10 52 21 ff a3 51 98 89 a8 91 41 08 d9 00 19 18
a9 1a a8 d0 55 1b eb 80 23 28 98 00 88 ae bb 84
41 9b a1 22 0f ea 04 38 99 01 08 18 fc 82 40 b8
81 52 98 80 39 fc 84 21 89 01 39 cc 01 11 11 03
9f c0 11 22 01 b9 80 28 ad a4 70 88 01 00 02 88
20 59 c8 55 8b a8 00 11 40 98 30 b1 82 9a e8 18
9a 1d 42 2b fd 92 22 8a d9 23 8d a0 42 0b fb 92
32 8c 02 3b fc 11 01 02 89 cc 91 42 88 91 31 21
de 11 01 82 13 30 db 80 24 28 13 33 70 ac a5 32
90 8b 91 21 c0 1c 33 28 cf e8 03 88 0a c0 1b a9
94 8d 89 89 af 81 14 3c f8 01 80 89 21 2a bc a2
01 94 8a 2a 83 20 f0 1b b0 19 61 10 a1 aa b8 14
70 99 90 a2 73 21 39 c9 12 51 08 72 a0 2c a8 03
42 a9 10 fa 33 51 ca 30 8a 8b 02 25 0c da ca 48
0a b2 80 bc 02 00 10 c0 8c 98 04 8d 88 74 08 0d
a9 15 11 aa a0 03 73 8a 8c 90 34 11 ab 81 44 22
b8 18 0a d9 91 73 28 9a 91 9b 99 80 10 07 11 ab
e9 14 50 1c b3 71 89 99 99 15 91 01 ae 89 33 0a
92 33 af d8 90 81 90 97 29 09 8a 9a a1 91 07 38
0f a8 03 1a 00 ca 93 23 08 50 03 22 4b db bb 43
56 11 81 39 be 98 12 80 08 04 11 32 73 9a fa 10
03 29 9e a0 80 a9 32 98 87 0b ed aa 89 01 10 8c
89 90 bc b0 22 52 08 da e9 88 21 11 11 19 cc c8
02 31 2b aa b0 92 8c ab 57 50 09 9a 91 22 27 2b
27 31 9c 02 04 32 88 18 13 24 1c c8 14 22 a9 72
02 8b bd 89 01 09 a1 27 a9 c8 0b c9 33 3c c0 91
19 fc a9 85 08 42 8c e9 00 11 28 10 99 23 a9 94
26 22 09 ac ab 89 10 11 33 40 8a 97 44 20 ad 98
80 a0 26 32 89 a0 33 62 29 a9 90 37 08 99 04 54
bb da 0a 26 34 9b ec 80 82 28 ba a8 b9 31 ad 1a
99 bb a8 dc 98 93 01 59 98 14 80 dc eb b9 00 33
32 20 53 42 aa b0 03 01 a9 ec eb aa 13 42 10 a9
91 23 53 70 a4 19 0a f0 35 30 88 80 85 43 40 8b
ba 90 22 8b a0 17 1b bc 93 57 13 09 bc bb b8 21
43 28 18 ba fb ab 89 90 43 50 1a c0 25 13 8e ba
ba 12 8a 14 91 60 cd a9 00 11 19 b9 12 72 98 08
8c ba 19 91 01 15 75 00 00 88 02 31 00 23 9c 81
87 31 28 41 50 a4 34 8b db a1 28 43 08 da 0c 90
b8 c9 18 27 19 9b 0b 01 16 98 a0 39 62 18 09 80
9c 98 a0 93 82 30 44 72 21 ab cd ba 23 23 1d b0
04 51 89 bd 36 23 28 aa ca 98 27 31 21 8b 90 11
45 18 8b 02 03 81 3c f1 21 bc b9 2c da 30 d1 1f
b8 b9 18 0b da 9a a8 65 18 9c c9 9a 80 08 9a c9
10 42 10 88 ea 81 40 18 bf a0 11 52 8b ba 91 64
12 09 b9 00 31 08 33 a8 01 77 21 12 b9 a9 33 27
68 00 18 aa ad 91 82 62 28 10 b9 81 80 e8 28 09
40 99 d8 00 9e aa e9 91 30 8a 1a e8 a2 19 9a 54
21 1b b2 18 64 10 99 88 cd 01 c9 54 43 18 a9 cb
a2 24 50 8a 88 83 51 80 9d 09 15 31 98 bd b0 26
10 11 80 10 a2 73 18 09 a9 b8 4a a2 a9 98 12 44
0d ca aa b9 12 cf 80 03 08 a8 fc 9e 90 41 98 91
02 ad ab cb 98 13 50 10 00 a9 61 b9 93 11 40 bf
b8 a8 26 18 a8 83 2c 89 9d 06 32 08 98 86 09 88
0b b2 35 2e 99 21 81 27 19 98 aa 00 cf 08 99 14
08 98 43 19 aa 9a ba d8 af 9a b1 44 80 41 19 aa
a9 b4 ba 0f a8 09 41 82 48 bb d8 a1 55 50 01 9b
ab a2 90 40 35 8a 82 44 51 01 01 9d 82 33 31 02
01 32 ce 52 80 a2 0b 91 cf a8 88 02 0a 28 9d a8
1a 92 a9 db 28 f0 8c db 01 23 3a fa 20 90 0d d0
8a 12 2a ba ba a9 54 93 98 a9 42 80 37 4c 99 a9
08 c9 13 05 3b 23 ea 11 32 10 88 01 12 74 10 01
08 82 48 b0 9a a8 81 52 43 50 23 39 58 f8 99 80
12 34 ae 98 9d a0 28 ab c9 ba da b9 92 ea 09 8d
80 c1 11 76 0a 90 99 90 94 41 88 98 06 08 2a a8
32 30 37 20 61 22 08 26 8a b0 74 01 11 00 19 98
a8 24 51 09 81 88 11 12 21 35 42 1a bb 99 85 73
18 89 bb c9 08 88 09 99 9a bf ba ce a8 10 12 28
be db 88 99 aa bf c9 88 00 88 98 9b aa 57 12 29
9b 00 89 d1 0b ba b1 47 51 00 a9 92 60 21 31 02
c0 dc a3 72 32 10 00 9b b3 43 73 01 ad ca 90 90
22 10 9d 9b 9b 06 0b db b0 9d c8 11 08 89 ac ad
c9 98 c8 28 80 0c b9 d9 80 82 32 0a ac bc d9 25
48 03 2a 8a 93 91 8b 2a b2 77 18 34 1a 82 51 d9
36 1a 02 01 43 18 09 00 00 e9 d9 10 14 41 21 32
91 ad ab cd 04 02 21 48 80 8a 9a a8 ff a8 23 32
38 11 af b8 cb 90 38 09 db b9 b8 3b 48 82 9b bf
fb 10 04 11 88 8b 89 ea 12 25 32 10 20 90 23 02
45 20 21 8f 05 03 34 43 10 98 aa 29 24 81 17 1a
9a 80 21 83 72 28 ca 99 bd 9b 8b c0 93 13 41 4a
b1 19 fc fa 8a 21 89 80 82 a1 4c d9 ac ba 02 31
73 20 8d ca ab c0 08 12 44 10 23 88 aa 83 8a ba
4b f8 23 36 33 1a 32 80 d1 8e 01 46 13 28 10 b9
8b 98 80 bd 9a 35 04 1a 01 89 34 18 e5 2a c9 1c
8a a2 0a 11 cf ab ea 00 80 08 ba b9 88 a1 8b 53
aa 49 df 98 13 21 23 0c 98 99 8c e0 bc 98 53 1a
a8 15 80 1c 24 82 10 62 00 81 31 01 74 80 9b 88
a8 02 71 81 42 82 80 1b b9 9b 07 3a 80 2a ff 88
a0 09 a8 49 10 d1 31 a0 1e ab aa b0 52 03 37 1a
00 92 0b 28 02 60 ad 09 03 00 20 c6 10 bf 91 9a
04 89 27 28 28 08 00 40 81 01 21 33 9e 37 12 80
ab ca 22 1a 87 31 01 08 98 80 11 bf da 91 42 80
41 90 31 91 4a 10 85 40 aa fd ac 00 10 b8 bc 88
b0 29 20 8a fa 9f a9 81 01 c8 8a cb a1 82 41 28
86 8d 88 8b ba 81 87 53 18 82 2b a8 28 14 0c 85
18 12 36 09 19 e0 11 51 82 12 0a 02 c8 36 1b b6
48 90 98 9c 00 02 8a 0b 99 d1 dc bb bb 92 ce 89
9a aa 13 bf a9 9a aa 09 0b c9 c8 80 08 80 9b c8
08 88 24 53 26 52 98 10 00 31 04 43 0a 34 80 92
21 62 12 27 50 88 29 aa 45 01 88 33 76 18 03 18
12 3d b2 19 40 19 c1 92 3b ca 29 00 39 fb 15 cb
51 12 81 9f a0 13 28 12 89 a8 08 9a da e9 21 92
20 cd 80 09 28 ab b3 2c 97 60 aa ba 45 80 00 09
b3 71 18 98 89 93 60 12 98 75 80 31 a0 23 30 08
b8 d0 9f 19 a2 09 cd 99 b1 09 db c8 ba 61 89 a9
9d 8a ca 91 11 8a be ab ca a8 19 b8 32 ec 00 80
10 68 d9 8b aa a9 98 98 01 33 43 34 20 18 14 50
be 91 02 38 13 25 47 54 08 24 00 03 11 52 81 39
8d c9 12 40 14 08 04 51 88 19 9c 92 29 a4 41 01
3d b8 80 08 11 10 8f f0 11 00 0b c9 a8 8c 89 8b
91 da a2 1c b8 c9 de 9a 02 21 ca 13 20 2b b8 37
4a 23 8c a9 27 88 98 50 25 10 31 80 21 98 28 85
20 60 81 05 88 02 3c da 9a fc 81 10 01 03 20 01
bc ba e8 02 cd 82 ad 91 39 a9 39 d0 0b 8a c0 22
1b f9 99 19 b9 cd 99 e8 89 92 22 89 23 19 0b e9
8c 8a a9 14 71 88 e8 81 05 20 35 1a 08 89 13 b3
75 00 98 31 0b a5 42 11 00 18 2a e9 02 8a 88 27
61 81 39 80 9a c9 b0 88 d1 71 08 22 90 1a 06 2a
b9 19 da 2a aa 1a f3 28 a9 c3 81 2a 9a 9a ab fc
48 80 80 00 01 03 22 22 01 01 80 99 88 08 11 32
54 35 33 33 39 54 8a 92 05 20 11 23 04 30 31 11
10 18 01 11 11 21 12 20 01 c0 18 8b d8 be a8 98
fd 90 19 aa 88 8f da 9c a0 9a d0 09 99 91 0e 88
ab 8a db bc a1 01 51 80 03 23 bf c9 19 b9 1a 04
13 18 12 01 22 43 89 32 44 33 34 23 42 12 23 23
22 22 11 22 10 10 23 11 11 22 21 00 88 09 0b 9a
ab 9a c9 81 f9 2b 0a fc 09 89 91 90 8c f9 88 b9
9b 00 cc 08 89 99 10 ac 98 90 10 98 05 51 8a 86
8b 00 12 2b 07 52 13 21 73 12 12 01 91 74 22 22
89 13 01 17 18 41 23 20 a0 40 0a c8 43 b9 35 09
14 2f a2 32 28 09 9a 8b 99 aa ba bb bb bb ca ca
9a a9 a9 a9 aa ab ab 9a aa 99 99 9b 0a d8 a9 9a
9d a0 81 42 02 be ab c1 42 53 09 15 11 10 00 02
88 34 3c 97 61 11 00 08 23 02 01 91 0a 72 11 09
24 f8 31 8b 1a ea 99 ca 99 b9 cb 1b ea 0b 98 fc
98 8a 99 08 d8 29 bb 2f a0 aa c9 91 21 8c 19 ca
12 ae a1 0a be 04 0d 82 13 31 08 b3 3f b9 34 22
28 15 11 52 ab 22 99 73 21 11 c8 34 88 80 62 83
49 03 a0 29 0c 93 0c d1 58 40 80 99 a1 13 8c c8
35 3b c1 9f 80 82 11 ad b9 0c 88 23 8b f8 09 cb
9a 99 28 d1 ae a0 a0 23 80 3a fb 89 9b e8 aa 31
24 99 28 92 8c 35 29 1c b1 17 38 90 88 21 a1 23
13 71 00 10 22 92 18 11 40 82 40 71 98 30 c9 24
a1 25 18 15 19 12 18 14 2c 90 0a 73 19 be a0 04
21 1b 92 ca 89 a8 bb aa 00 90 98 20 dd 80 89 00
8a fb 18 1a c3 1a 89 e9 a9 92 24 33 78 a0 1a 83
29 c9 07 28 aa 80 42 24 80 3b e1 32 23 23 89 90
2c c9 89 36 30 8b a9 a0 9d d9 1a 90 24 90 1d bb
bb d0 1b 8c a8 b9 9c 90 89 a8 1c 01 11 f0 9a 81
33 9b 43 31 bd 18 d0 2c 99 43 53 25 18 a8 99 30
58 a8 a4 41 02 20 b0 41 c8 8d 14 10 10 22 1b 95
0b 93 34 1b 31 ba 10 9a d3 39 26 10 ac 90 40 a9
28 35 91 40 aa a0 88 b8 5b aa ab a0 83 d0 8a 31
2b 80 3a c2 03 3a 92 cc 09 d1 42 22 88 a9 0a cc
83 50 14 00 08 aa 83 23 32 1a 01 20 01 99 83 50
99 90 16 30 0b 94 81 22 29 b4 38 0c a1 12 1e 01
11 00 1c 90 89 c0 31 01 bb ca 08 ab cd 02 01 8f
81 3a a0 0a cb 8b fa 11 9b b8 03 2e 93 40 8a 09
ba 11 90 e9 03 9a 02 19 01 3c d9 09 98 04 00 89
18 b9 92 42 98 22 08 02 18 03 24 2b 08 02 32 32
02 b8 13 99 88 20 10 21 01 01 a9 c9 89 49 80 a2
19 bc 0b bb 99 9a 90 13 ab da 89 88 8a b0 cb b8
04 22 8b 22 9b ba 19 93 11 1a 80 29 84 14 04 00
98 10 21 1a 91 80 20 20 81 33 00 21 98 02 8b 01
23 31 01 b8 03 20 01 10 18 b1 22 30 b0 30 b9 21
90 0a 80 81 19 08 9b 80 81 99 ba 10 da aa a1 8b
10 0a 12 9c 9a b0 88 00 88 ab 93 41 9b 10 90 21
9a 10 91 08 84 28 80 99 02 22 30 08 00 92 20 08
01 18 21 00 81 20 81 11 10 88 00 08 01 00 00 01
08 08 89 01 89 11 88 88 80 9a 81 89 9a 10 99 c8
0a 98 8b b8 98 99 8a 19 91 88 90 9a 80 a9 99 88
80 80 09 28 a8 80 08 90 90 00 00 80 20 81 91 08
21 00 01 00 01 01 99 01 09 08 89 12 10 88 08 08
80 89 02 00 10 80 90 09 09 90 00 88 09 18 80 00
89 00 80 88 08 88 08 80 88 00 08 80 09 08 80 09
08 88 88 88 00 00 00 89 00 09 01 08 08 10 98 00
80 08 88 01 08 00 00 88 00 80 09 81 01 80 08 80
00 80 08 08 80 08 00 08 08 80 00 88 00 80 90 80
08 00 88 08 08 08 08 08 80 08 80 80 08 08 08 08
80 09 00 80 80 80 80 80 80 80 80 80 80 09 00 08
09 00 08 80 80 80 08 00 09 2a 18 94 e6 d4 c3 a0
3f 5c 28 a6 c2 8a 5b 03 d2 1c 20 c3 0c 30 d2 2d
12 b8 49 b3 3e 84 9b 23 bb 43 cb 51 ba 42 bb 26
9b 85 0a a1 48 ba 43 9d 93 38 d9 24 0b c0 42 9c
91 41 ab a2 51 9c 90 42 8a c9 24 29 bc 82 42 8b
ca 14 32 ac c9 14 31 9b da 03 43 0a bd a0 24 32
9b db 91 34 41 9a bc a0 14 33 29 cb ca 91 34 42
09 ab cb 90 23 53 20 8a cb bb 90 34 34 32 0a bb
db aa 82 24 34 32 08 ab cb ca a8 01 34 33 33 20
8b cc bb bb a9 01 43 43 33 41 10 9a bb bb aa b9
90 00 12 12 11 01 10 80 88 98 89 88 88 80 80 80
00 08 00 08 80 08 80 80 88 00 80 80 88 00 80 80
80 80 80 08 08 99 11 21 88 92 e8 a0 18 37 3a 00
2f d8 a3 50 20 e9 8c 15 08 18 09 a8 61 a0 ba 22
a1 00 1f da 24 79 a2 08 19 a0 91 82 34 f8 9c 90
34 3a b0 1d 40 83 49 ba b0 59 f8 10 82 10 9c 02
41 b4 1c 80 aa a0 44 1d 08 b1 59 30 d8 80 03 b2
0e 38 48 ab e4 98 22 1a 8c a3 c0 12 62 00 eb 81
20 28 8d a8 00 17 8a 22 1b 98 8c 07 1a 9b 80 11
80 a3 49 a5 26 a9 2e 99 02 93 b0 1b 1a 27 07 0a
09 b9 11 ab 00 e0 52 13 0b 98 c8 32 ea 81 01 2c
09 41 38 e8 26 8b 8e 82 82 03 e0 08 00 18 28 8b
82 d2 0e 81 a2 88 72 89 ac 40 00 91 d0 a0 82 11
ca 70 32 bb bb 41 a8 2b 89 21 64 93 88 e0 a9 89
9f 32 32 18 bb 84 8c b8 48 b3 c2 79 b3 87 0c 88
00 09 a1 30 80 81 58 b3 b9 c8 ca 58 12 79 00 b9
b5 19 81 b5 c9 3a a7 28 09 3f 98 b5 18 2b 99 86
09 03 ab 94 2c 28 b3 aa 50 9b a8 07 3a 88 89 13
a0 d6 28 9f 08 a8 13 49 94 8a 2b 02 9c 09 06 2a
98 d0 08 a3 c2 47 09 0a 98 1e 88 33 10 d8 98 38
95 8a 00 a9 3a 00 b7 32 1f 9b 19 a7 18 11 8d 80
a1 a0 36 20 9b 9a 49 b8 28 0a 11 97 13 fa 12 00
99 40 c0 12 99 dc 02 39 10 b1 34 9f 82 13 d9 78
a8 08 89 82 a1 48 98 82 9e 46 8a 19 8a 80 09 00
0b d1 24 10 44 b0 ba 9a 83 40 99 3b 0f 9b c6 05
28 09 fa 11 23 89 1f a2 99 32 20 d2 8d 80 29 25
08 9b a1 b9 61 8a 21 da 38 85 12 bd 0a 34 91 99
0d 82 91 3a 9b aa 17 70 21 db 98 84 22 99 ad 98
24 03 1c 08 a3 a0 4d 0b 88 d5 12 1a 90 b0 22 4a
cd 93 22 08 ce 20 b3 62 1e 99 00 13 99 a8 92 04
13 8a e9 80 48 8c 1b 10 72 90 d9 20 12 bd 09 04
97 8c 10 91 10 99 9b 14 13 9d 90 3b 58 10 e9 10
82 18 8f 03 08 92 c0 81 5b 9a 93 16 93 0d a9 23
8d 81 00 71 9a 9b 92 29 03 52 2b f8 c8 30 03 2a
c1 95 9d 89 40 28 89 89 93 41 e0 b0 20 a1 78 18
9b d8 32 94 89 08 39 fc 04 02 3b 9b c0 12 0a 21
52 bf 09 81 13 00 da 30 1c 00 81 18 06 e0 19 0d
14 80 2c a8 81 33 9b 96 d8 39 92 20 9c 90 51 c9
28 19 00 23 ba bf b7 21 99 9a 90 33 21 28 ff 91
42 09 d0 0a 28 12 4a e9 18 24 a0 88 0e 82 02 1a
9b 58 90 28 e2 81 08 a2 bb 50 41 8f 99 32 82 03
df 81 11 18 88 bb b7 30 0d 80 81 89 50 8c 88 23
80 d8 01 b4 03 8c cb 61 3b 88 c1 a9 73 0c a0 00
92 32 bc d1 20 18 28 0f b1 35 8b 01 98 c3 23 af
81 2a 11 1c 9b 17 00 9a 80 a0 71 98 9b 01 02 60
bb b4 80 22 29 eb 21 81 83 09 fa 50 80 93 ad 00
50 99 18 d9 25 1a 90 8c 10 35 9c 80 98 15 1a a9
2b 01 54 d9 83 1d 21 9a a0 68 92 19 ba 95 1a 32
b9 e8 49 85 00 ca 10 89 64 bd 21 a8 31 c9 11 81
08 09 f0 48 89 4a d0 40 a1 2a c8 48 a3 2a b9 01
48 03 cd 02 8b 71 aa 11 c0 40 a0 1b 80 02 3c 80
b1 07 8d 20 c2 29 80 99 02 82 0f 83 a8 51 aa 0e
13 02 d0 a0 32 0e 09 00 7a 90 82 01 e0 08 38 90
b9 51 1d 09 83 29 89 d1 24 a9 aa 61 2d 99 33 99
e0 25 99 b1 21 2f 92 10 0e 10 01 a8 83 8a 88 32
f1 80 1a 82 99 12 03 fb 51 0e 82 3a b8 25 ba 03
4a f1 20 8e 12 09 a9 42 ba 11 4b b2 15 bb 13 1b
c1 50 bb 44 ad 13 0b a3 3a d1 38 b8 21 8b 97 0a
a2 38 d8 32 c9 21 9b 30 0b 04 99 81 09 81 09 80
08 80 80 80 08 08 08 00 99 39 00 98 2c 22 ad 07
8c 22 99 95 b0 10 b6 f5 3f 84 aa 22 aa 48 b3 1d
03 9a 21 d0 59 c2 2a 92 0c 14 c8 39 91 09 04 9f
22 a9 18 00 90 03 da 68 b2 28 ba 43 e8 31 bb 50
a8 12 8d 4e 59 a3 90 88 93 1d 02 90 b7 99 18 19
90 20 af 58 90 81 89 6d 12 a8 83 ac 50 c2 00 a8
20 a1 91 09 19 0b 53 f8 39 2e 02 89 1a 49 88 00
18 d3 1b 01 a4 f3 1e 03 a8 82 8d 32 ba 13 1e 00
2a 19 08 5a 8d 42 d8 21 a8 03 d1 18 c3 19 b2 28
c1 4f 03 8b 18 4b 90 20 0e 11 88 93 a1 09 97 c2
91 89 20 d2 80 3d 19 18 18 8f 79 90 11 9b 11 2a
c5 a1 00 b0 24 f1 08 92 99 82 3e 81 3b 1a 10 3f
2a 82 2c e4 3c b5 09 a4 99 12 b8 20 a9 38 91 1e
18 3c 29 01 2f 12 9b 15 c0 38 e2 2a b6 0a 93 8a
96 8c 21 99 19 28 9a 69 91 1b 95 0c 21 b1 01 e1
29 b2 03 c1 08 00 92 d0 7a b1 7a 91 2b 3a 80 28
c2 09 08 c6 88 a3 09 c4 8a 14 ae 23 ad 22 9b 49
19 81 1d 28 80 08 00 b1 b5 83 f1 2b a5 18 f3 1d
11 89 82 1d 28 89 3a 88 28 0a 84 09 f4 88 80 b3
05 f8 30 b8 38 c0 4b 83 1c 80 5a 91 09 10 8b 17
a9 94 09 92 90 a6 b9 42 c9 22 8d 20 8a 59 90 49
b0 6a 92 a1 81 8c 25 c8 94 1d 93 1a b3 4c 82 1d
03 1f 10 00 90 19 01 b2 a3 8a a7 a9 22 f2 2b b2
69 b0 49 0b 48 89 19 02 1b b5 2a e2 19 a4 8a b7
8a 85 8a 94 1c 81 2b 93 3e 08 4b 80 3b d7 9a 40
d2 1a 09 30 f2 09 00 08 a2 1a 92 3c 00 80 8b 7e
22 c1 92 1d 04 a0 08 98 30 c9 50 b0 18 1a 96 a9
5a 80 03 ca 68 a1 08 92 1b c5 1a b6 98 09 3a b7
8b 20 1b 94 1c 11 9a 32 d9 33 e9 48 a3 a8 1a 49
c3 1a 09 24 f0 2a 01 0a 81 29 d3 3f 02 a1 a1 4d
83 80 c1 4a a3 1d 02 9a 21 8d 23 e0 3b 10 a4 a9
48 a1 10 d1 3a c2 4b b5 08 a9 79 a2 90 2b 20 b4
0b 81 39 d2 2c 94 8c 21 90 a5 8d 48 b2 18 8c 32
c0 81 2b 88 80 60 f0 49 a8 41 d0 29 88 12 c0 18
8b 31 a9 83 a0 7e 03 99 91 6b 83 c1 29 99 34 d9
30 c1 4c 82 00 e1 3b 00 92 88 1c 21 0b c5 2a a8
6a 02 ba 78 8b 16 a8 b7 a8 2a 11 aa 32 b8 85 9d
59 88 29 89 30 b8 38 d6 c2 89 5b 93 91 b8 7a 94
a0 19 2b 96 99 00 2b 10 91 94 9f 30 90 b5 0c 28
a3 81 c8 41 d0 28 88 91 1a 3d 84 8a 1d 40 a0 80
18 8c 24 9b b7 0b 21 b3 b5 ab 60 a0 93 8a 18 88
5a b9 70 9d 41 a9 18 29 80 d5 0a a2 20 d1 00 81
9c 33 9c b7 2d 00 01 a0 1b 40 aa 23 9c 03 8b 31
f1 28 c9 43 f0 01 89 18 a3 2c a3 4c 80 10 90 0d
40 a8 03 8b 1a 24 b8 e4 2b a1 31 f0 10 2b 81 b5
88 b9 70 c0 20 98 1b 33 da 15 9b 29 32 f1 88 2b
01 b7 9a 20 98 11 c1 2a c1 7a a2 00 2e 10 18 c1
3a 3e 85 8a 93 1b 93 88 03 f8 59 a1 02 d1 2b a4
2b a2 4b 0c 23 0d 93 2c 1a 04 89 d3 4c 93 98 04
ca 42 c9 13 a8 88 38 80 e2 6b 88 21 ab 30 2d 00
83 9e 02 2a c2 84 a9 3c 24 d8 03 9c 31 c1 29 c2
3c 88 31 da 70 e3 0c 20 a3 9b 6a 18 a5 9a 39 81
a2 9a 48 0a 86 c2 90 4f 20 b3 98 1b 58 c3 0b 11
a2 89 2b 12 b9 5a 12 f2 1e 20 a2 a0 3c 03 a9 28
a3 82 9f 41 f1 1a 2b 23 f2 0b 28 01 b1 29 90 08
4b 93 d4 1f 12 a0 90 4d 13 e0 28 a0 11 9b 31 b2
9c 79 93 b0 4c 10 93 9b 5a 94 8a 83 89 b2 6c 85
b8 3a 2a a7 99 19 39 b2 2b 03 ba 79 90 85 c8 6b
83 a0 91 3d 83 88 98 21 d8 5a 92 91 99 6a a7 9a
30 a9 32 e8 30 b0 29 88 95 a9 4b 02 c5 9b 69 92
98 82 0b 85 0d 02 90 0b 59 a4 b8 49 0a 87 a9 12
8b 11 8a 32 f8 5a 80 83 ab 59 94 a8 00 2b 92 82
b0 93 9c 7a b7 0a 09 4a 93 c1 4a 98 48 8a b7 b8
69 92 a0 19 2a a7 a1 8a 28 80 0a 41 d9 69 92 b3
8b 7b 02 90 b2 7c 82 88 81 92 a2 0f 22 c1 80 1a
00 a4 8a 81 4b 0b 60 c0 3d 4a 01 c4 8b 20 88 a5
99 10 a0 21 f2 80 0d 48 a2 a3 99 4b 81 2a 90 7b
80 4b 94 a8 3b 2a 87 c0 20 9b 41 e1 28 d2 29 b1
38 d1 19 19 08 02 9f 30 1d 03 99 0a 5b 28 c4 08
a9 79 91 81 91 88 91 00 f5 8a 82 2d 83 99 10 0e
30 9b 78 99 5a 80 18 a2 1b 93 08 f3 08 b2 29 d5
a0 82 9d 50 c1 10 9a 49 88 19 00 2e 11 2e 02 0b
00 3d 02 a0 85 aa 24 d0 83 c2 09 a5 89 b4 2c 08
29 09 2d 5a 09 48 a8 20 9a 38 82 b1 a7 a9 85 89
b5 88 b5 90 82 c2 88 0c 32 c8 29 2d 5a 09 4c 11
0b 00 4b 92 2b a6 c2 01 e1 12 e0 11 a9 11 93 f1
2c 28 a4 1f 10 1b 85 99 10 8b 69 90 03 d8 49 a1
10 a8 5b 83 a0 82 8c 83 4f 11 b2 88 1c 58 b1 20
ba 68 a0 28 c5 9a 11 1b b7 8a 28 08 95 b8 38 b9
79 90 02 c0 5c 02 90 a2 2e 12 9a 03 9a 12 9e 40
d2 18 a9 68 b2 08 a3 0c 20 89 a7 8c 20 1b 96 99
2a 08 38 c0 31 e8 49 91 92 b3 2f 04 a9 95 0c 10
09 18 80 1a 1b 78 c2 18 9a 40 c2 88 84 ab 24 ab
87 9a 38 0b 23 e0 3a a0 6b 80 39 c3 1c 28 81 c5
9a 22 b9 23 e0 11 aa 79 b4 88 98 6a 92 0a 84 a9
30 ba 70 c0 28 98 21 d1 19 92 0c 15 aa 05 9d 30
98 84 b0 3b 81 3e 83 0b 91 7b 81 1a 01 99 50 d0
30 f0 30 d1 10 b8 7a 93 99 10 90 01 b0 6c 01 1a
a4 90 a0 6c 12 d1 2b 00 12 f1 18 98 12 b9 5b 04
c8 38 8b 17 b8 11 8c 38 a2 08 c4 1c 01 2c 94 0b
03 a9 3a 89 60 f1 3b a3 2a c4 0a 83 9b 32 d8 31
e0 49 a0 13 e8 39 88 2b 22 c8 06 ab 33 bd 24 b8
10 98 3c 96 8b 96 0c 03 9a 04 a9 39 98 6a b5 0b
83 1c 83 88 a3 99 6c 00 11 f1 28 b8 69 91 80 81
b0 59 b0 58 d1 3a 98 5a 81 90 01 c0 59 b0 58 c1
10 a9 48 90 81 00 ba 70 aa 35 d9 48 98 29 92 1d
05 aa 22 ac 24 b9 31 b9 5a 82 8a 97 9b 32 bb 52
d0 11 c0 3a 82 9a 06 ab 42 bc 42 c9 22 b8 3b 02
99 87 9d 23 9d 13 9b 04 8c 20 90 08 a6 0c 03 8e
13 aa 12 8b 4a 95 0d 04 9b 14 9b 05 9a 02 88 0a
12 0e 05 8d 12 8b 05 9a 02 92 d1 4e 11 a1 1b 84
0c 03 9a 04 aa 38 80 82 e2 2d 02 1e 03 99 93 1e
28 83 e2 88 2b 02 0d 03 0b a5 0b 20 b4 a8 1a 7a
a3 2b c5 1b 80 4b 95 b1 19 a0 58 d2 2a c4 0a 08
3b 95 b0 5a a1 49 c1 38 e2 1a 08 10 c3 9a 79 98
30 e1 10 b1 3c 82 80 a3 aa 68 b0 59 b2 20 d0 4a
88 10 92 c8 58 b9 60 c1 10 b8 5a 81 88 82 aa 60
ba 78 a0 21 d8 49 81 99 22 d9 41 c9 58 b1 28 b0
39 81 a8 50 d0 30 c9 58 b1 39 b0 59 a1 1b 23 f8
40 ba 78 b1 28 b2 2b 01 9a 51 f1 29 b0 69 a1 29
b3 09 18 c1 59 e2 3b b3 4b 92 2b a4 90 1c 10 3c
b6 1a b2 5b b7 98 00 92 9a 49 0a 22 d1 01 b0 4e
39 81 b5 b8 31 f1 2b 18 11 d2 89 4c 11 a2 a0 29
b6 9a 39 19 b7 a0 1a 3b 18 83 b0 11 9f 58 99 23
e8 20 99 3c 39 92 c7 b0 3a 98 59 a1 38 f2 89 29
08 10 e2 29 d2 2b 80 5c 03 b0 18 98 5b 94 1d 85
9b 22 9c 22 b0 28 b4 0b 04 9c 23 f0 20 b0 5a b4
1b 84 9a 20 9a 59 90 2a 94 8c 22 9c 24 c0 83 ab
31 89 0b 61 c8 23 cc 42 ba 31 c1 a4 90 a8 7a a3
08 d2 3a a0 7b 01 88 82 a9 5b 19 4b 95 a8 95 9a
20 0b 22 c2 a2 a4 ae 78 a1 18 b2 1a a4 2f 03 9b
16 b8 3a 88 4d 03 9a 05 9c 48 99 30 d1 18 b3 2d
11 98 12 f1 2a b3 5c 82 0b 85 a8 3b 82 2e 03 9b
07 aa 31 aa 48 90 29 b5 8a 11 99 05 f2 09 92 1a
92 2d 84 b1 1a 00 3e 02 0d 04 9b 24 c9 6a 94 a8
02 a0 0c 58 a1 83 d0 4a a3 0a 00 18 c3 0c 5c 20
91 c4 8b 31 b9 38 8b 17 d1 2b 2a 28 a5 a9 31 e1
2a 90 48 d2 1a 00 09 2b 11 96 f2 0b 28 3c 95 9a
13 d1 1b 3b 4a a7 9a 21 aa 50 b8 31 f2 09 08 1a
03 ba 68 c2 3d 00 3c a6 99 20 99 28 a2 2a c5 8c
21 8b 24 c8 20 b1 3e 11 98 97 b9 40 b0 28 a0 39
d4 8a 39 89 22 e0 39 b3 2e 10 1a a5 9a 38 80 88
92 3a f6 9b 40 9a 14 b9 48 a1 1b 28 2b d7 9b 40
9b 42 c8 21 e2 0a 29 2b 13 f1 18 a2 2d 01 1b a7
98 01 99 4a 80 19 c7 a8 20 9b 58 a0 39 c3 1b 18
2e 22 d0 20 c1 2a a4 1c 85 a9 12 a8 1c 5b 28 94
b9 31 9d 33 e0 02 b9 69 a2 08 92 b1 3a 0c 7a a4
1a b4 0a 02 9a 49 91 19 c7 aa 40 a8 21 e0 39 90
29 a1 3c 03 d2 0a 95 1f 03 9b 23 c9 31 c8 59 a2
1b 86 b9 40 b8 48 b0 49 b3 2b 90 5b 18 80 2b d7
8b 22 ab 34 d8 21 c1 19 80 3e 12 c1 18 b2 3d 93
2d 95 8a 83 8b 39 2a 1c 87 aa 41 c8 30 c0 38 c1
28 c2 1a 18 a3 2a f5 0c 83 0c 13 ab 34 d8 20 9a
4a 11 b8 33 f0 3a b2 4b a4 2c a4 0b 11 88 1b 97
9b 34 cb 60 a9 30 c0 30 c0 4a 91 00 92 c1 3d 82
2d 03 9c 13 ac 41 aa 48 a4 b0 22 f8 49 a1 3b a5
0b 84 8b 13 9c 21 b2 0a 97 9c 58 a8 48 c1 3a b3
3c 92 2b 94 a0 08 81 2f 14 c9 31 d0 38 c0 49 b2
3a b3 80 1c 84 1f 04 9b 14 ab 33 c9 31 d0 28 a1
19 1a 80 5b b5 2b d3 3b e5 0c 20 98 02 b3 c2 2d
18 28 c4 8a 83 8c 38 1d 13 e3 a0 2c 29 3a c3 2b
b7 89 80 4c 02 a1 a2 0a 29 90 6e 11 98 83 9b 48
a8 59 a4 a1 a1 2e 4a 81 19 b5 89 93 1e 12 a9 05
a9 18 09 3f 30 d2 00 98 4a a2 2c 83 88 c4 0c 39
81 89 04 ba 16 aa 31 c8 40 c1 19 92 0c 7a a4 88
b4 0b 03 0e 12 a8 84 aa 49 09 10 92 f2 29 d3 2d
82 1b 85 9b 22 a9 3b 28 09 b7 a9 58 a0 4a b2 5b
b5 0a 81 1b 39 a4 1c 87 aa 42 d8 30 d0 39 b3 1c
02 8c 48 a1 2b 97 9a 13 ab 41 b9 50 c0 39 c2 2c
18 80 01 f3 0b 85 9a 12 8c 31 c8 38 99 4b 14 c9
24 d8 38 b0 59 b2 3a d4 8a 4b 10 08 b5 8b 06 aa
32 c9 40 c0 39 a0 28 8c 40 9b 26 ba 32 ba 42 c9
31 d0 30 d0 39 9a 40 a8 06 c9 32 ca 50 a9 31 d1
10 c1 19 0a 49 0b 17 b9 23 bb 51 c8 30 c0 38 c2
2b 91 3b 01 d5 9a 05 9c 33 cb 51 d0 20 c2 08 88
29 89 13 ca 35 ca 41 ba 41 c8 48 b1 4a a2 3b a1
11 c0 05 ba 50 b9 50 d1 28 c2 2a b2 5c 00 18 b2
84 c9 58 a9 58 b1 28 c2 2a b3 4c 82 1b a5 80 c2
1a a2 5b b4 3d a5 0b 04 9b 23 9e 21 99 84 9a 12
8d 13 9d 22 aa 25 ba 32 bd 41 ab 35 c9 22 bb 60
aa 50 b0 30 d0 38 c0 49 a0 38 d1 39 b0 59 a0 38
e2 2a b3 4d 83 0c 85 99 83 99 82 2d 83 1d 94 0b
85 8c 22 ab 41 b8 30 d1 29 98 28 0d 25 c8 13 d0
3d 11 a2 9a 32 e8 4a 94 99 11 9c 50 c1 2b 84 a9
38 b1 39 d4 1d 02 99 12 b9 5a 93 0b 11 8c 33 f1
2c 02 99 03 ba 68 b2 3e 02 89 83 ab 41 c1 3d 01
0b 07 b8 38 c3 1c 02 0d 14 c0 29 a3 0b 12 0f 20
b3 1c 03 9c 23 d9 59 b5 8a 03 ab 51 d0 3a a5 8b
13 ab 50 b0 4b 83 9b 32 d8 48 b1 3d 02 0b 04 b8
39 a3 1e 30 c1 10 e3 1c 84 9b 40 99 21 d1 2a 92
1c 28 88 4b 97 a9 13 d9 58 b1 3b a5 8a 03 b8 49
a2 2e 21 b8 48 d2 3d 94 0c 12 b9 59 a2 1a 84 aa
59 a2 2c 84 9b 32 d0 4b 83 8c 30 b0 49 b4 0c 05
b8 39 a1 4c 03 c8 38 c3 0a 96 b0 4e 12 a8 28 b3
0c 5c 12 a8 83 9d 23 e1 2b 81 2b 82 2b a7 b3 c1
2b 02 0b 94 2f 12 d1 29 a1 3c 95 9b 59 91 19 a4
8a 12 d3 9b 69 92 0b 03 1f 12 c0 3a a3 2d 83 8c
48 b3 0a 00 92 a1 c4 0f 48 b2 2c 11 8a 14 e0 3a
94 a8 18 0a 49 92 99 4a a7 a9 21 c1 29 b4 1e 20
a8 39 a2 2b b7 a0 19 10 b3 3f 11 9c 50 d1 2b 04
aa 31 c8 49 a4 8c 30 b0 3a 93 8b 21 d5 a8 3b a7
8b 30 a9 59 a3 0d 13 c1 19 a3 0c 13 d1 2c 3a a5
8b 31 c8 59 b4 8b 32 e0 3a 93 0d 21 c0 4b 84 a9
20 b3 8a 11 d3 1f 30 c1 2c 03 9c 31 d2 2c 84 a9
38 b3 2e 03 a9 4a 82 a0 2c 04 c0 3a b6 8b 31 d1
3c 83 9b 50 c1 2b 85 aa 40 c2 1b 03 b9 39 80 08
0d 58 b2 3d 85 a9 38 d4 0c 12 b8 49 b5 8b 31 c0
4b 84 aa 48 a1 18 b6 b0 3d 21 c0 3b 85 b9 5a 83
9b 31 d2 1c 13 d1 1a 94 9a 59 a3 0d 30 b1 3d 03
b0 2a b7 99 38 c2 1c 21 c1 2c 12 b9 59 a4 8b 30
d3 0c 22 d0 3a 94 9b 48 b3 1d 21 b0 3b 85 b8 4a
a6 a9 49 a3 0c 21 c1 2d 12 a9 5b 84 a9 49 a3 0c
21 d2 1b 13 d0 3c 03 b9 5a 94 9a 49 a3 0c 30 d3
0c 13 d1 2b 03 c8 4a 93 8c 30 c2 2e 20 a1 2c 03
c1 1a 84 c1 2b 96 a8 3b 83 9b 79 a3 8b 48 c3 0b
30 d2 1c 13 d0 3b 84 b8 4a 83 c8 4a 83 b8 4a a5
9a 49 a4 9a 49 a4 8a 20 c3 0c 21 d3 0c 20 b3 8a
30 d2 1c 21 c2 0b 40 c2 0b 59 a3 8c 48 b3 1e 38
b4 8b 49 a5 9a 49 a4 9a 49 a4 8b 38 b5 9a 49 a4
8b 48 b4 9a 49 a4 a8 4a 93 a8 3b 84 c0 4b 03 d0
3d 21 b1 2d 21 c2 0b 31 d2 8a 49 a4 9a 4a 84 c0
3c 12 c1 1b 22 e2 1c 11 b4 8b 30 d3 0b 38 c3 8b
6b 03 c0 4c 11 c3 0c 30 c2 0c 48 b4 99 39 a5 a8
3c 03 c0 3c 12 d2 0b 49 a4 99 4b 84 b0 3d 11 b3
0d 49 a4 99 3c 12 c1 2c 20 b3 9a 6a 83 b8 4c 21
d2 89 3b 04 d1 1b 38 a3 9a 4a 01 91 98 3d 12 d3
8b 6b 04 c1 1b 39 a6 b0 2c 20 b4 99 4b 84 c1 2c
39 b6 a0 2c 20 b4 b1 2d 38 b5 a8 3c 11 b4 9a 49
94 b1 1c 39 94 c1 1c 49 a5 a8 3c 28 a4 a8 3c 11
b4 9a 5b 02 b2 1c 4a 83 e3 8b 5a 82 b2 0b 5a 83
c2 0c 49 81 a2 8b 5a 02 d3 8b 5a 84 c1 1c 39 83
d2 0b 4a 01 a3 b0 4e 20 b4 99 4b 84 c2 0a 3a 94
c2 8a 5b 28 a4 b1 2d 39 82 b2 99 49 a4 b1 1c 49
94 c2 0c 5b 03 d3 a8 4c 28 a3 a1 0a 29 09 02 c4
a0 2a 00 0a 4a 95 f3 8c 5a 02 d3 a8 4c 28 93 c2
89 4c 20 b4 b1 1b 20 91 89 28 b5 a0 2f 38 a4 a0
08 0a 4c 12 d4 a8 4c 28 b6 a8 3c 28 92 98 00 91
0b 30 b1 3c 03 c3 c1 3f 30 e4 a8 3c 20 a2 a1 0b
49 00 93 c1 09 2b 06 d2 0c 38 93 c1 3f 11 b3 99
5c 11 b2 88 00 90 3f 21 d3 99 4b 03 d1 1a 3b 84
c1 1b 38 b5 9a 30 a8 3b 12 f4 9b 7a 02 c2 0b 4a
02 c2 0b 38 90 09 82 b3 1f 39 b7 99 4b 03 d2 0b
4a 01 b3 98 1a 39 c3 08 a5 a9 6c 21 c2 0c 48 b3
99 3a 08 a7 b8 5b 03 c1 1a 11 c2 2f 20 c4 8a 3b
11 c4 99 3a a4 98 19 01 a1 1d 5a 83 c0 2a 83 b0
2c 48 b4 99 29 84 d2 8b 59 93 b1 2f 38 b5 a8 3c
12 d3 8b 48 b5 99 3b 84 b1 2c 02 b1 2c 2a 28 b7
a9 5b 03 d1 2b 01 92 b2 2f 39 93 aa 6a 94 a8 3a
94 a9 3a 0a 23 f3 9b 5a 84 b0 3b 08 3a b7 9a 59
b5 99 4c 11 99 4b 12 f4 b2 0b 5a 00 88 82 a1 a2
1f 4a 02 c2 88 82 b2 0c 5b 12 d4 a9 4b 10 80 09
85 d2 0b 4b 29 83 d3 99 2a 2a 29 08 01 f5 b2 1d
4a 83 b0 2a 02 d2 8a 5b 11 a2 a2 b2 08 91 2f 5b
13 f3 a9 4b 29 02 c2 90 82 b1 3f 4a 95 c2 89 3b
02 c1 2c 28 93 c1 1c 38 a3 a0 3f 38 b4 b3 a9 6b
12 c1 09 10 b3 8c 5c 4a 03 e3 a8 3b 01 88 08 19
a7 c3 99 3c 29 96 b1 2e 3a 2a 2a 02 e5 c3 a0 1b
4b 3a 18 93 e4 a0 1b 5b 28 93 d3 b2 88 1b 3b 4c
39 84 e3 99 29 09 2a 29 00 93 d5 c3 8b 5b 29 08
01 e5 b2 8a 5c 28 93 c2 90 1a 4c 28 a4 b3 b2 0c
6c 28 93 c2 89 2a 18 82 b2 89 3d 20 b6 a0 80 0b
7c 39 a6 b2 89 3d 28 92 b4 a0 1a 4d 39 93 d3 99
3c 4a 02 d3 a0 1b 5a 01 a1 92 a0 3f 39 93 d3 99
4c 3a 84 c3 a0 1b 3b 28 a6 c3 a8 4d 3a 02 c3 98
00 89 28 a4 b2 98 3e 49 b6 a8 3c 39 92 b2 88 2a
03 e0 2a 12 e3 8d 49 93 a8 3c 20 a2 b4 8d 5a 83
d3 98 19 81 89 3a b7 99 3a 2c 20 c4 98 2b 20 b3
98 01 f4 8b 49 81 c6 b0 4d 28 92 b3 98 1a 4a 93
99 22 e2 99 6c 28 94 c1 1b 49 93 a0 09 2a 00 88
19 a7 d2 1c 4a 01 b4 c3 8c 5a 01 a0 08 09 10 98
20 c5 b1 2f 4a 84 c2 88 1b 4a 00 80 82 d3 90 98
4b 08 03 f2 0b 4a 01 b2 89 3b 10 b1 7c 03 c2 90
1b 3c 48 d5 a1 0a 5b 20 b3 98 08 03 e8 6c 11 b3
b2 0c 4a 01 91 a2 89 5c 04 c1 1c 28 a5 99 2a 29
b6 98 19 1a 02 c2 99 7c 12 c2 88 2c 20 b3 89 19
2a 21 f4 9b 48 81 a2 0d 39 08 84 d8 4c 10 08 a5
b0 3b 11 a1 0a 3b a7 b1 1a 5f 38 b4 8a 01 1c 04
c1 1a 3c 10 91 89 29 20 f7 b0 2a 09 28 09 3c 28
c7 b3 a8 3d 3a 11 b2 8a 39 95 d4 b1 2d 3a 01 99
3a 18 b7 d3 99 4b 01 88 00 09 01 d5 b1 2e 38 91
80 8a 3b 30 e5 a0 09 4d 39 92 a0 01 b5 b3 c4 a0
1b 4c 2b 5a 02 c3 c3 9a 4b 3b 19 28 a7 b2 88 95
c1 1c 4a 18 08 91 09 84 b2 a0 3f 4b 38 b5 a0 19
01 b3 8e 4a 00 a4 b2 8a 6c 12 d3 99 4c 29 83 c3
99 2b 11 90 2d 5b 12 f3 b2 0b 6b 28 92 a1 0b 5a
95 b1 09 3d 11 b3 8c 5b 20 c6 b1 1c 3a 10 92 b2
0a 21 d4 9a 5c 28 93 c3 99 5d 28 a4 b2 0a 3b 10
a2 8a 49 a7 c2 89 3e 39 94 c3 a8 3c 39 92 a0 19
18 94 c1 1c 5b 12 e3 a1 0a 4c 11 a2 90 09 19 80
80 3d 4a b7 b1 2c 4a 18 a4 b2 0c 5a 01 b3 a1 0a
3a a6 a9 5c 28 94 d3 99 3d 39 93 b2 89 19 01 b5
9b 7b 11 a3 c2 0c 4a 02 d3 98 19 2b 20 c5 99 3b
11 b4 a8 4c 2a 03 f3 99 4b 20 b4 b1 1b 4b 01 92
b1 3e 38 a4 b1 1e 4a 01 a2 a1 0a 4c 03 c3 99 3d
38 a4 c2 0b 4b 20 b5 b0 2c 3b 96 b1 08 1a 2c 31
f3 8b 49 80 81 91 0b 5b 31 d3 98 92 89 29 d4 0b
10 9a 68 93 1c 82 8a 18 0c b6 c2 1a 28 a2 80 09
6e 28 b4 b3 0b 4a 49 d3 0b 12 ba 4a 02 90 0b 3c
27 b4 9a 4d 10 a2 08 81 a1 a8 6c 39 92 e4 99 3a
2a 81 b5 b0 6b 10 82 b4 8a 3a 49 b2 81 d2 2c 02
2a a3 8d 83 4a f3 0d 28 93 a8 2b 96 aa 21 8a 3a
05 c2 0b 28 9d 32 a8 25 d8 38 09 38 b9 95 b8 21
8e 12 c9 32 d8 49 b1 6a 93 8a 22 9a 01 c2 bb 6b
04 d3 1e 21 a0 00 8a 12 a0 31 ac 68 a2 2b e3 0b
12 99 02 d0 7a 00 09 02 9a 32 9b 12 f2 0b 22 b5
d2 88 b7 b2 19 80 4f 3a 1a 5c 28 93 b3 c4 c2 88
81 0c 3b 18 80 83 e4 8a 5b 2a 2a 01 c3 b2 b4 b3
b4 a9 5b 19 10 a1 a4 9c 7c 4a 29 02 b4 b3 a1 92
b2 8a 82 83 b8 1b 84 bf 5d 3c 3b 20 a4 c2 a2 90
00 80 20 c6 b0 2b 10 99 22 1b 6e 5c 20 80 93 c2
89 39 a2 88 c5 b1 8b 30 d2 0a 18 3d 5b 29 94 b2
0b 3c 1a 38 f4 a0 81 92 b1 12 e4 1c 3a 3d 22 f2
88 88 1b 7b 28 92 80 b5 a8 39 94 b0 08 80 10 d4
d3 b0 1a 2e 5b 29 18 a3 09 08 4d 3a 96 b1 08 02
b4 a1 d5 b1 1d 20 98 29 92 98 4a 3e 4a 00 81 9a
4a 88 87 e2 90 88 29 a3 99 85 c3 8b 5a 19 18 08
10 5f 21 c0 29 94 98 18 08 80 93 e2 a0 84 c2 8a
38 8a 79 b3 3e 20 8b 02 9a 49 1b 12 aa 37 f1 09
00 00 80 a5 b0 2c 2a 10 c6 b1 1a 19 5d 38 09 18
91 a3 c0 2b 00 0c 4a 14 f4 c1 08 19 3a 02 a1 1c
28 c4 b8 39 98 4d 01 0d 30 98 04 c1 2a c5 8b 02
99 16 c1 01 c0 3c 18 2a a5 8b 39 1a 39 99 79 a3
1c 86 c0 02 99 58 a1 93 d1 89 2b 28 19 5b 02 b1
2f 30 a9 14 d0 10 99 38 b1 02 f1 19 94 98 2a 21
f5 a8 20 aa 7a 02 a8 18 0a 20 c2 b2 c8 6b 01 2a
e6 99 20 90 2d 10 91 d4 8a 2a 4b 97 a8 18 91 1b
3a 29 82 b1 a6 b8 6c 21 b3 a1 a3 c2 1b 00 2d 38
90 08 8b 2d 14 aa 79 b2 4f 28 92 a1 01 c2 2a a7
8a 11 98 03 ab 4a 09 30 f2 0b 21 b0 5a e5 8a 28
98 19 4e 22 d1 08 88 1a 28 08 02 b2 1c 22 d0 02
a1 a5 e0 3a 2b 48 b4 a3 a9 7e 20 a1 2a 02 a0 2a
b6 ab 21 d3 89 3a 2b 09 84 c1 02 08 2d 6c 85 c0
29 81 92 bc 6a 83 a2 99 6c 21 90 0a 08 80 2b 09
3d 85 c4 a0 1a 00 4a b6 b1 2a 01 89 3f 11 c0 2a
02 a0 3d 2a 84 d1 0b 30 98 49 93 a5 8e 20 b4 99
2b 30 d3 0d 4a 12 d3 a1 09 01 8a 49 94 99 2d 2b
4a 94 b0 19 88 1b 7a 83 f4 a8 4a 00 29 11 a1 8c
03 b9 15 ea 6a 81 98 00 91 91 89 4c 04 aa 41 c2
09 4c 12 c8 4b 94 89 02 e1 2b 3a 12 d2 90 1b 34
f2 1d 20 98 18 a2 a8 4a 18 98 28 05 ba 59 a2 13
e4 b0 09 1a 49 b7 8a 11 9c 5a 82 b1 18 81 19 92
e0 02 91 a1 3c 24 ac 13 e8 5c 11 a1 18 92 0e 20
c3 98 82 a4 8b 3b 1e 58 b3 9c 59 a5 99 18 92 a0
1a 90 6b 07 a0 2a 00 89 81 80 91 91 a6 9d 48 c1
3a 91 a1 3c 50 b4 80 0a 11 d0 4c 02 b8 09 01 e4
0b 20 08 94 10 a2 2f 95 c0 2c 28 00 92 0b 30 c3
c1 b4 0e 59 a3 91 89 29 b2 18 a4 ac 5a 81 89 2a
03 b7 d2 0a 3a 29 22 f3 a9 5b 01 98 22 e2 2a a4
1f 39 a3 a8 91 9a 6b 20 a0 18 87 c1 1b 11 0a 03
a0 00 a1 2e 20 9b 30 f3 0d 5b 04 c0 3a 94 99 11
98 1b 38 c5 b1 1c 49 00 b4 0e 39 94 b1 1a 28 a3
b2 a2 1c 20 3b 17 c2 8b 5c 01 98 38 90 3b 02 c3
99 1b 27 e2 1b 38 a1 90 89 94 9c 10 b8 7c 31 c3
98 88 0d 39 c3 1b 15 b1 1a 10 09 7a 02 a8 10 91
98 80 08 91 1a 18 00 91 90 19 80 00 90 08 80 80
08 88 19 01 89 18 80 00 80 88 08 80 08 08 08 08
08 80 08 80 08 08 08 81 90 09 18 80 08 08 80 08
80 08 08 08 08

149
rtl/sound.v Normal file
View File

@@ -0,0 +1,149 @@
`timescale 1ns / 1ps
/*============================================================================
Aznable (custom 8-bit computer system) - Charles (sound engine)
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 0.1
Date: 2021-12-21
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module sound #(
parameter ROM_WIDTH
)(
input clk,
input reset,
input [3:0] addr,
input [7:0] data_in,
input write,
input [7:0] soundrom_data_out,
output reg [ROM_WIDTH-1:0] soundrom_addr,
output signed [11:0] audio_out
);
wire sample; // Is m5205 requesting sample data
reg [3:0] snd_data_in; // 4 bit data input to m5205
reg [ROM_WIDTH-1:0] soundrom_addr_target; // Current sample end position
reg [7:0] volume; // Sound output volume
reg m5205_ce; // Counter for 375KHz clock enable
reg m5205_phase; // Memory address phase counter - 0 = 4 high bits, 1 = 4 low bits
reg playing; // Is sound playing
reg [13:0] ce_counter; // Counter for 375KHz clock enable
always @(posedge clk)
begin
if(reset)
begin
// Clear all signals on reset
ce_counter <= 14'd0;
soundrom_addr <= {ROM_WIDTH{1'b0}};
soundrom_addr_target <= {ROM_WIDTH{1'b0}};
playing <= 1'b0;
end
// Generate 375Khz clock enable
m5205_ce <= (ce_counter == 14'd0);
if(ce_counter == 14'd63)
begin
ce_counter <= 14'd0;
end
else
begin
ce_counter <= ce_counter + 14'd1;
end
if(write)
begin
// Disable playback when CPU is sending commands
playing <= 1'b0;
case (addr[3:2])
2'd0:
begin
// Set initial address (sample beginning)
soundrom_addr[{addr[0],3'd0} +: 8] <= data_in;
end
2'd1:
begin
// Set target address (sample end)
soundrom_addr_target[{addr[0],3'd0} +: 8] <= data_in;
end
2'd2:
begin
// Trigger play
//$display("playing write: start=%d end=%d", soundrom_addr, soundrom_addr_target);
ce_counter <= 14'd0;
playing <= 1'b1;
end
2'd3:
begin
// Set volume
$display("set volume: %d", data_in);
volume <= data_in;
end
default:
begin
end
endcase
end
// Generate m5205 data input
if(playing)
begin
// If playing and m5205 is requesting a sample, load 4 bits from ROM and shift phase for next read
if(sample)
begin
// Shift phase for next read
m5205_phase <= m5205_phase + 1'd1;
if(m5205_phase == 1'b1)
begin
// Increment music ROM address
soundrom_addr <= soundrom_addr + {{ROM_WIDTH-1{1'b0}},1'b1};
// Get 4 low bits from ROM
snd_data_in <= soundrom_data_out[3:0];
// If target address has been reach, stop playing
if(soundrom_addr_target == soundrom_addr) playing <= 1'b0;
end
else
begin
// Get 4 high bits from ROM
snd_data_in <= soundrom_data_out[7:4];
end
end
end
else
begin
snd_data_in <= 4'd0;
end
end
// M5205
jt5205 #(.INTERPOL(0)) m5205(
.rst(~playing), // Hold reset while sound is not playing so it can return to zero
.clk(clk),
.cen(m5205_ce), // 375Khz clock enable
.sel(2'b10), // 8Khz sample rate
.din(snd_data_in),
.sound(audio_out),
.sample(sample), // Requesting a sample
.irq(),
.vclk_o()
);
endmodule

View File

@@ -36,7 +36,7 @@ reg [data_width-1:0] mem [ramLength-1:0];
always @(posedge clock) begin
q <= mem[address];
if(wren) begin
q <= data;
//q <= data;
mem[address] <= data;
end
end

865
rtl/sprite.hex Normal file
View File

@@ -0,0 +1,865 @@
00 06 10 06 35 06 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 01 02 03 04 05 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 04 00 00 00 04 01 01 01 01 02
02 02 02 02 02 03 00 00 00 00 04 02 02 01 01 01
01 02 02 02 02 02 05 00 00 04 03 03 03 03 03 03
03 03 03 03 03 03 05 00 00 00 01 03 03 03 03 03
03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00
00 00 04 03 03 04 04 00 00 00 02 03 04 05 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
04 02 02 03 04 04 05 00 00 04 03 03 05 00 00 00
00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 04
01 02 03 04 05 00 00 00 00 01 03 04 00 00 00 00
00 00 00 00 00 01 00 00 00 00 00 00 00 00 04 02
02 03 04 05 00 00 00 00 00 02 03 05 00 00 00 00
00 00 00 00 00 02 00 00 00 00 00 00 04 01 02 03
03 05 00 00 00 00 00 00 04 03 03 00 00 00 00 00
00 00 00 00 04 03 00 00 00 00 00 04 02 02 03 03
05 00 00 00 00 00 00 00 01 03 04 00 00 00 00 00
00 00 00 00 01 03 00 00 00 04 01 02 03 03 04 05
00 00 00 00 00 00 00 00 02 03 05 00 00 00 00 00
00 00 00 00 02 03 00 00 00 01 02 03 03 05 00 00
00 00 00 00 00 00 00 00 02 03 00 00 00 00 00 00
00 00 00 04 03 03 00 00 00 02 02 03 03 03 02 01
01 02 02 04 05 00 00 00 03 03 03 02 02 01 01 02
02 02 03 03 03 04 00 00 00 04 03 03 03 03 03 03
03 03 03 03 04 05 00 00 04 03 03 03 03 03 03 03
03 03 03 03 04 05 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 02 05 00 00 00 00 00 00 04 02
01 01 01 01 02 02 02 05 00 00 00 00 00 04 02 01
01 01 01 02 02 02 03 03 00 00 00 00 00 01 03 03
03 03 03 03 03 03 03 04 05 00 00 00 04 02 03 03
03 03 03 03 03 03 02 03 00 00 00 00 04 02 03 04
05 00 00 00 00 04 03 03 04 00 00 00 01 03 03 04
05 00 00 00 00 04 03 03 00 00 00 00 01 03 04 05
00 00 00 00 00 00 02 03 03 00 00 04 02 03 05 00
00 00 00 00 00 00 03 04 00 00 00 00 02 03 05 00
00 00 00 00 00 00 02 03 04 00 00 01 03 04 00 00
00 00 00 00 00 00 03 05 00 00 00 04 02 03 00 00
00 00 00 00 00 04 03 03 05 00 00 02 03 05 00 00
00 00 00 00 00 04 04 00 00 00 00 01 03 03 05 00
00 00 00 00 04 02 03 04 00 00 04 03 03 03 02 01
01 01 02 02 02 03 04 00 00 00 00 02 03 03 03 02
01 01 02 02 03 03 04 05 00 00 01 03 03 03 03 03
03 03 03 03 03 03 05 00 00 00 04 02 03 03 03 03
03 03 03 03 03 04 05 00 00 00 02 03 03 04 05 00
00 00 00 00 04 03 00 00 00 00 01 03 03 05 05 02
03 03 03 03 05 00 00 00 00 00 02 03 05 00 00 00
00 00 00 04 02 03 00 00 00 00 02 03 03 00 00 05
02 03 03 03 03 04 00 00 00 00 03 03 03 03 02 01
01 02 02 03 03 03 00 00 00 00 04 03 05 00 00 00
00 05 02 03 03 04 05 00 00 00 04 03 03 03 03 03
03 03 03 03 03 04 00 00 00 00 00 00 00 00 00 00
00 00 00 05 03 03 04 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 02
05 00 00 00 00 00 02 04 00 00 00 00 04 03 05 00
00 00 00 00 00 00 00 00 00 00 00 00 04 01 03 03
04 00 00 00 00 00 03 03 05 00 00 00 01 03 04 00
00 00 00 00 00 00 00 00 00 00 00 04 02 03 03 03
03 00 00 00 00 00 03 03 04 00 00 00 02 03 05 00
00 00 00 00 00 00 00 00 00 00 00 01 03 03 05 03
03 05 00 00 00 00 04 03 03 00 00 04 03 03 00 00
00 00 00 00 00 00 00 00 00 00 04 02 03 03 00 03
03 04 00 00 00 00 02 03 04 00 00 01 03 04 00 00
00 00 00 00 00 00 00 00 00 04 02 03 03 05 00 04
03 03 00 00 00 00 03 03 05 00 00 02 03 05 00 00
00 00 00 00 00 00 00 00 04 02 03 03 05 00 00 04
03 03 05 00 00 00 03 04 00 00 00 02 03 00 00 00
00 00 00 00 00 00 00 00 01 03 03 03 02 01 01 02
03 03 04 00 00 00 03 05 00 00 04 03 03 00 00 00
00 00 00 00 00 00 00 04 02 03 03 03 03 03 03 03
03 03 03 00 00 00 03 00 00 00 01 03 04 00 00 00
00 00 00 00 00 00 04 02 03 03 04 05 00 00 00 00
04 03 03 00 00 00 03 00 00 00 02 03 05 00 00 00
00 00 00 00 00 04 01 03 04 05 00 00 00 00 00 00
00 01 03 05 00 00 04 00 00 00 03 03 03 02 01 01
01 02 03 04 00 02 03 03 05 00 00 00 00 00 00 00
00 02 03 04 00 00 05 00 00 00 04 03 03 03 03 03
03 03 04 05 00 04 03 04 00 00 00 00 00 00 00 00
00 04 03 03 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 04 01 03 00 00 00 00 00 00 00
00 04 01 02 00 00 04 01 03 00 00 00 00 00 00 00
00 04 01 02 00 00 02 03 03 05 00 00 00 00 00 00
04 01 03 03 00 00 02 03 03 05 00 00 00 00 00 00
04 01 03 03 00 00 04 01 03 03 05 00 00 00 00 04
02 03 03 05 00 00 04 01 03 03 05 00 00 00 00 04
02 03 03 05 00 00 00 04 02 03 03 05 00 04 01 02
03 03 05 00 00 00 00 04 02 03 03 05 00 04 01 02
03 03 05 00 00 00 00 00 04 02 03 03 05 02 03 03
03 05 00 00 00 00 00 00 04 02 03 03 05 02 03 03
03 05 00 00 00 00 00 00 00 04 02 03 03 03 03 03
05 00 00 00 00 00 00 00 00 04 02 03 03 03 03 03
05 00 00 00 00 00 00 00 00 00 04 03 03 03 03 05
00 00 00 00 00 00 00 00 00 00 04 03 03 03 03 05
00 00 00 00 00 00 00 00 00 04 02 03 03 03 03 00
00 00 00 00 00 00 00 00 00 04 02 03 03 03 03 00
00 00 00 00 00 00 00 00 04 01 03 03 03 03 03 05
00 00 00 00 00 00 00 00 04 01 03 03 03 03 03 05
00 00 00 00 00 00 04 01 02 03 03 05 04 02 03 03
05 00 00 00 00 00 04 01 02 03 03 05 04 02 03 03
05 00 00 00 00 00 02 03 03 03 05 00 00 04 02 03
03 05 00 00 00 00 02 03 03 03 05 00 00 04 02 03
03 05 00 00 00 05 04 03 03 05 00 00 00 00 04 03
03 04 00 00 00 00 04 03 03 05 00 00 00 00 04 03
03 04 00 00 00 04 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 05 04 03 02 01 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 01 01 02 02
00 00 00 00 00 00 00 00 00 00 00 00 01 03 03 02
02 04 00 00 00 00 00 00 00 00 00 01 01 03 03 04
02 02 00 00 00 00 00 00 00 00 01 03 03 02 03 03
02 02 00 00 00 00 00 00 00 00 02 03 02 02 03 02
02 04 00 00 00 00 00 00 00 00 00 04 02 03 02 02
04 00 00 00 00 00 00 00 00 00 00 00 00 00 04 04
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 01 01 01 03 00
00 00 00 00 00 00 00 00 00 00 01 01 03 03 03 02
00 00 00 00 00 00 00 00 00 00 01 03 03 02 02 03
02 00 00 00 00 00 00 00 00 01 01 02 03 01 03 03
02 04 00 00 00 00 00 00 00 01 03 03 03 03 02 02
03 02 00 00 00 00 00 00 00 00 03 03 02 04 02 03
02 04 00 00 00 00 00 00 00 00 00 02 03 02 02 02
04 00 00 00 00 00 00 00 00 00 00 04 02 03 02 04
00 00 00 00 00 00 00 00 00 00 00 00 04 02 04 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 01 01 03 00 00
00 00 00 00 00 00 00 00 00 00 01 01 03 03 03 01
01 00 00 00 00 00 00 00 00 00 01 03 02 03 03 03
03 03 00 00 00 00 00 00 00 03 03 03 02 02 03 02
02 04 00 00 00 00 00 00 00 01 03 02 02 04 03 02
02 04 00 00 00 00 00 00 00 01 03 02 04 01 03 02
02 00 00 00 00 00 00 00 00 03 03 02 02 03 02 02
04 00 00 00 00 00 00 00 00 03 02 04 02 03 03 02
00 00 00 00 00 00 00 00 00 04 02 02 02 02 03 00
00 00 00 00 00 00 00 00 00 00 02 04 00 02 04 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 03 03 01 01 00
00 00 00 00 00 00 00 00 00 01 01 02 03 03 02 02
02 00 00 00 00 00 00 00 00 01 02 03 03 02 02 02
03 04 00 00 00 00 00 00 01 01 03 03 02 03 03 03
03 03 03 00 00 00 00 00 01 01 03 02 02 03 04 02
02 03 03 04 00 00 00 00 01 03 02 02 02 02 02 02
02 03 02 04 00 00 00 00 03 03 03 03 02 02 02 02
02 03 02 02 00 00 00 00 03 01 03 03 02 02 02 04
02 03 02 00 00 00 00 00 03 03 03 02 02 02 03 02
02 02 00 00 00 00 00 00 00 02 03 03 03 03 04 02
04 00 00 00 00 00 00 00 00 00 00 00 04 04 02 02
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 01
01 00 00 00 00 00 00 00 00 00 01 01 03 02 03 03
03 03 00 00 00 00 00 00 00 01 01 02 03 04 03 03
03 04 04 00 00 00 00 00 00 01 03 03 03 02 03 03
02 02 03 00 00 00 00 00 00 01 02 02 03 03 03 02
04 02 00 00 00 00 00 00 00 03 03 04 03 03 02 04
02 02 00 00 00 00 00 00 00 03 03 02 03 03 03 02
03 03 03 00 00 00 00 00 00 01 03 03 03 02 03 02
03 03 02 00 00 00 00 00 00 01 02 03 03 03 02 02
03 02 04 04 00 00 00 00 01 03 02 04 03 03 02 03
03 02 04 00 00 00 00 00 00 04 02 02 02 03 02 03
02 04 00 00 00 00 00 00 00 00 02 02 03 02 02 04
00 00 00 00 00 00 00 00 00 00 00 02 02 02 04 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
03 03 03 01 00 00 00 00 00 00 00 00 01 01 01 02
03 03 03 03 00 00 00 00 00 01 01 03 03 01 02 04
02 03 03 03 00 00 00 00 01 01 03 02 03 01 03 02
04 03 03 02 00 00 00 01 01 03 03 04 03 03 03 03
02 01 03 02 00 00 00 04 02 03 03 02 03 03 03 03
03 03 02 02 04 00 00 00 02 02 02 03 03 03 03 02
02 02 02 02 04 00 00 00 00 00 02 02 03 03 02 02
04 00 00 00 00 00 00 00 00 00 00 02 02 02 02 04
00 00 00 00 00 00 00 00 00 00 00 04 02 02 04 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 01 01 00 00 00
01 01 00 00 00 00 00 00 00 01 01 02 01 03 03 03
03 03 03 00 00 00 00 00 00 01 04 02 02 03 04 03
03 03 04 04 00 00 00 00 01 01 03 02 03 03 02 03
03 02 02 03 00 00 00 01 01 01 03 02 03 03 03 03
03 02 02 03 00 00 00 01 01 03 03 04 02 03 02 02
03 03 02 02 00 00 00 01 03 03 03 03 03 03 02 03
03 03 03 03 00 00 00 02 02 03 03 03 03 03 03 03
02 03 03 02 02 00 00 00 02 03 02 02 03 03 02 03
02 03 02 04 04 00 00 00 00 03 04 02 02 03 03 03
03 03 02 02 00 00 00 00 00 02 02 02 02 02 03 02
03 02 04 00 00 00 00 00 00 00 00 02 02 03 02 02
02 00 00 00 00 00 00 00 00 00 00 00 04 02 02 04
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 01 01 01 01 03 00 00
00 02 04 00 00 00 00 00 00 03 01 03 03 02 02 02
02 02 02 04 00 00 00 00 01 01 03 03 03 03 03 03
02 03 03 02 00 00 00 01 01 02 03 03 02 03 03 03
03 04 02 02 04 00 01 03 01 02 03 03 03 03 03 03
03 03 02 02 02 00 01 01 03 03 03 02 03 03 03 03
02 03 02 02 00 00 01 03 02 03 03 03 03 03 02 02
02 03 03 03 02 00 00 01 03 03 02 03 03 03 03 03
02 02 03 03 02 04 01 01 03 03 03 03 03 02 03 03
02 04 03 02 02 04 01 01 03 02 03 03 03 03 03 02
03 03 03 02 04 00 01 02 03 02 03 03 03 03 02 03
03 03 02 02 04 00 00 01 02 04 02 03 02 03 04 03
03 02 02 04 00 00 00 00 02 02 03 03 03 03 03 03
02 02 04 04 00 00 00 00 00 04 02 02 02 03 02 02
02 02 00 00 00 00 00 00 00 00 00 00 02 04 02 04
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 01 02 01 00
00 00 00 00 00 00 00 00 00 00 00 01 02 02 02 02
00 00 00 00 00 00 00 00 00 00 00 02 02 03 03 02
00 00 00 00 00 00 00 00 00 00 00 02 03 04 03 02
00 00 00 00 00 00 00 00 00 00 00 02 02 03 02 02
00 00 00 00 00 00 00 00 00 00 00 01 02 02 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 01 02 02 01 00
00 00 00 00 00 00 00 00 00 00 01 02 03 02 02 01
00 00 00 00 00 00 00 00 00 01 02 02 03 02 02 02
01 00 00 00 00 00 00 00 00 02 02 02 03 03 03 02
02 01 00 00 00 00 00 00 00 02 03 03 04 04 03 02
02 02 00 00 00 00 00 00 00 02 03 04 04 04 04 03
03 02 00 00 00 00 00 00 00 02 02 03 03 04 04 03
02 02 00 00 00 00 00 00 00 01 02 02 03 03 03 02
02 01 00 00 00 00 00 00 00 00 01 02 02 02 02 02
01 00 00 00 00 00 00 00 00 00 00 01 02 02 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00
00 00 00 00 00 00 00 00 00 00 01 02 02 02 02 02
02 01 00 00 00 00 00 00 00 01 02 03 03 03 03 03
03 02 01 00 00 00 00 00 01 02 03 03 04 04 03 03
03 03 02 01 00 00 00 00 02 03 03 04 04 04 04 04
03 03 02 02 01 00 00 01 02 03 04 04 00 00 04 04
04 03 03 02 02 00 00 02 03 03 04 00 00 00 00 00
04 04 03 03 02 00 00 02 03 03 04 00 00 00 00 00
00 04 04 03 02 00 00 02 03 03 04 04 00 00 00 00
04 04 03 03 02 00 00 02 02 03 03 04 04 00 00 04
04 03 03 03 02 00 00 01 02 02 03 03 04 04 04 04
03 03 03 02 02 00 00 00 01 02 02 03 03 04 04 03
03 03 02 02 01 00 00 00 00 01 02 02 03 03 03 03
02 02 02 01 00 00 00 00 00 00 01 02 02 03 03 02
02 01 00 00 00 00 00 00 00 00 00 00 02 02 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 01 02 01 00 00
00 00 00 00 00 00 00 00 00 01 02 03 03 04 04 03
03 02 01 00 00 00 00 00 01 02 03 04 04 04 04 04
04 03 02 01 00 00 00 00 02 03 04 04 04 00 00 04
04 04 03 02 01 00 00 01 03 04 04 00 00 00 00 00
04 04 04 03 02 00 00 02 03 04 00 00 00 00 00 00
00 04 04 04 03 00 00 03 04 00 00 00 00 00 00 00
00 00 04 04 03 00 00 04 04 00 00 00 00 00 00 00
00 00 00 04 04 00 00 04 04 00 00 00 00 00 00 00
00 00 04 04 04 00 00 03 04 04 00 00 00 00 00 00
00 00 04 04 03 00 00 02 03 04 04 00 00 00 00 00
00 04 04 04 03 00 00 01 02 03 04 04 04 00 00 00
04 04 04 03 02 00 00 00 01 02 03 04 04 04 00 04
04 04 03 02 01 00 00 00 00 01 02 03 04 04 04 04
03 02 01 00 00 00 00 00 00 00 00 01 02 03 03 02
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 00
00 00 00 00 00 00 00 00 00 00 00 00 01 02 02 01
00 00 00 00 00 00 00 00 00 00 00 01 02 04 03 02
00 00 00 00 00 00 00 00 00 00 00 01 02 03 02 01
00 00 00 00 00 00 00 00 00 00 00 00 01 02 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 01 02 01 00
00 00 00 00 00 00 00 00 00 00 00 00 01 02 02 01
00 00 00 00 00 00 00 00 00 00 00 01 02 03 03 02
01 00 00 00 00 00 00 00 00 00 01 02 03 04 04 03
02 02 01 00 00 00 00 00 00 01 02 02 02 03 04 02
01 00 00 00 00 00 00 00 00 00 00 01 02 02 03 02
00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 02 03 02
00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 02
01 00 00 00 00 00 00 00 00 00 00 01 02 03 04 03
02 01 00 00 00 00 00 00 00 01 02 02 03 04 00 04
03 02 01 00 00 00 00 00 00 02 03 03 04 00 00 04
03 02 02 00 00 00 00 00 00 01 02 02 03 04 04 03
02 01 00 00 00 00 00 00 00 00 00 01 02 03 04 03
02 00 00 00 00 00 00 00 00 00 00 00 01 02 03 02
01 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 02 03 02
00 00 00 00 00 00 00 00 00 00 00 00 01 02 00 02
01 00 00 00 00 00 00 00 00 00 00 01 02 03 00 03
02 01 00 00 00 00 00 00 00 01 02 02 00 00 00 00
00 02 01 00 00 00 00 00 00 02 03 00 00 00 00 00
00 02 02 00 00 00 00 00 00 01 02 02 00 00 00 00
02 01 00 00 00 00 00 00 00 00 00 01 02 00 00 03
02 00 00 00 00 00 00 00 00 00 00 00 01 02 03 02
01 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00
00 00 00 00 00 00 00 00 00 00 00 00 00 03 02 03
00 00 00 00 00 00 00 00 00 00 00 00 03 03 04 02
01 00 00 00 00 00 00 00 00 00 03 02 02 04 02 02
02 02 01 00 00 00 00 00 00 00 00 00 03 02 02 01
01 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 05 05 00
00 00 00 00 00 00 00 00 00 00 00 00 05 06 06 05
00 00 00 00 00 00 00 00 00 00 00 05 06 07 05 08
09 00 00 00 00 00 00 00 00 00 00 05 06 05 08 09
09 00 00 00 00 00 00 00 00 00 00 00 05 08 09 09
00 00 00 00 00 00 00 00 00 00 00 00 00 09 09 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 0a 0a 00
00 00 00 00 00 00 00 00 00 00 00 00 0a 07 0b 0c
00 00 00 00 00 00 00 00 00 00 00 00 0a 0b 0c 0d
00 00 00 00 00 00 00 00 00 00 00 00 00 0c 0d 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 07 0e 00
00 00 00 00 00 00 00 00 00 00 00 00 00 0e 0f 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 02 02 02 02 00 00
02 02 00 00 00 00 00 00 00 00 02 00 00 00 00 02
00 00 02 00 00 00 00 00 00 00 02 00 00 00 00 02
00 00 02 00 00 00 00 00 00 00 02 02 02 00 00 02
00 00 02 00 00 00 00 00 00 00 00 00 00 02 00 02
00 00 02 00 00 00 00 00 00 00 00 00 00 02 00 02
00 00 02 00 00 00 00 00 00 00 00 00 00 02 00 02
00 00 02 00 00 00 00 00 00 00 02 02 02 00 00 00
02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 08 00 00 08 08 00 00
00 08 08 00 00 00 00 00 08 08 00 08 00 00 08 00
08 00 00 08 00 00 00 00 00 08 00 08 00 00 08 00
08 00 00 08 00 00 00 00 00 08 00 08 00 00 08 00
08 00 00 08 00 00 00 00 00 08 00 08 00 00 08 00
08 00 00 08 00 00 00 00 00 08 00 08 00 00 08 00
08 00 00 08 00 00 00 00 00 08 00 08 00 00 08 00
08 00 00 08 00 00 00 00 00 08 00 00 08 08 00 00
00 08 08 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 0b 00 0b 0b 0b 0b 00
00 0b 0b 00 00 00 00 00 0b 0b 00 0b 00 00 00 00
0b 00 00 0b 00 00 00 00 00 0b 00 0b 00 00 00 00
0b 00 00 0b 00 00 00 00 00 0b 00 0b 0b 0b 00 00
0b 00 00 0b 00 00 00 00 00 0b 00 00 00 00 0b 00
0b 00 00 0b 00 00 00 00 00 0b 00 00 00 00 0b 00
0b 00 00 0b 00 00 00 00 00 0b 00 00 00 00 0b 00
0b 00 00 0b 00 00 00 00 00 0b 00 0b 0b 0b 00 00
00 0b 0b 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 0f 0f 00 00 00 0f 0f 00
00 00 0f 0f 00 00 00 0f 00 00 0f 00 0f 00 00 0f
00 0f 00 00 0f 00 00 00 00 00 0f 00 0f 00 00 0f
00 0f 00 00 0f 00 00 00 00 00 0f 00 0f 00 00 0f
00 0f 00 00 0f 00 00 00 00 0f 00 00 0f 00 00 0f
00 0f 00 00 0f 00 00 00 0f 00 00 00 0f 00 00 0f
00 0f 00 00 0f 00 00 0f 00 00 00 00 0f 00 00 0f
00 0f 00 00 0f 00 00 0f 0f 0f 0f 00 00 0f 0f 00
00 00 0f 0f 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 06 06 00
00 00 00 00 00 00 00 00 00 00 00 00 06 07 07 06
00 00 00 00 00 00 00 00 00 00 00 00 06 07 07 06
00 00 00 00 00 00 00 00 00 00 00 00 00 06 06 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 06 06 00
00 00 00 00 00 00 00 00 00 00 00 00 06 07 07 06
00 00 00 00 00 00 00 00 00 00 00 06 07 06 06 07
06 00 00 00 00 00 00 00 00 00 00 06 07 06 06 07
06 00 00 00 00 00 00 00 00 00 00 00 06 07 07 06
00 00 00 00 00 00 00 00 00 00 00 00 00 06 06 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 06 06 00
00 00 00 00 00 00 00 00 00 00 00 00 06 07 07 06
00 00 00 00 00 00 00 00 00 00 00 06 07 06 06 07
06 00 00 00 00 00 00 00 00 00 06 07 06 00 00 06
07 06 00 00 00 00 00 00 00 00 06 07 06 00 00 06
07 06 00 00 00 00 00 00 00 00 00 06 07 06 06 07
06 00 00 00 00 00 00 00 00 00 00 00 06 07 07 06
00 00 00 00 00 00 00 00 00 00 00 00 00 06 06 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 00 06 07 07 07 07
06 00 00 00 00 00 00 00 00 00 06 07 07 06 06 07
07 06 00 00 00 00 00 00 00 06 07 07 06 00 00 06
07 07 06 00 00 00 00 00 00 06 07 06 00 00 00 00
06 07 06 00 00 00 00 00 00 06 07 06 00 00 00 00
06 07 06 00 00 00 00 00 00 06 07 07 06 00 00 06
07 07 06 00 00 00 00 00 00 00 06 07 07 06 06 07
07 06 00 00 00 00 00 00 00 00 00 06 07 07 07 07
06 00 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 06 06 07 07 07 07
06 06 00 00 00 00 00 00 00 06 07 07 07 06 06 07
07 07 06 00 00 00 00 00 00 06 07 06 06 00 00 06
06 07 06 00 00 00 00 00 06 07 07 06 00 00 00 00
06 07 07 06 00 00 00 00 06 07 06 00 00 00 00 00
00 06 07 06 00 00 00 00 06 07 06 00 00 00 00 00
00 06 07 06 00 00 00 00 06 07 07 06 00 00 00 00
06 07 07 06 00 00 00 00 00 06 07 06 06 00 00 06
06 07 06 00 00 00 00 00 00 06 07 07 07 06 06 07
07 07 06 00 00 00 00 00 00 00 06 06 07 07 07 07
06 06 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 06 06 07 07 07 07
06 06 00 00 00 00 00 00 00 06 07 07 07 06 06 07
07 07 06 00 00 00 00 00 06 07 07 06 06 00 00 06
06 07 07 06 00 00 00 00 06 07 06 00 00 00 00 00
00 06 07 06 00 00 00 06 07 07 06 00 00 00 00 00
00 06 07 07 06 00 00 06 07 06 00 00 00 00 00 00
00 00 06 07 06 00 00 06 07 06 00 00 00 00 00 00
00 00 06 07 06 00 00 06 07 07 06 00 00 00 00 00
00 06 07 07 06 00 00 00 06 07 06 00 00 00 00 00
00 06 07 06 00 00 00 00 06 07 07 06 06 00 00 06
06 07 07 06 00 00 00 00 00 06 07 07 07 06 06 07
07 07 06 00 00 00 00 00 00 00 06 06 07 07 07 07
06 06 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 06 06 07 07 07 07
06 06 00 00 00 00 00 00 00 06 07 07 07 06 06 07
07 07 06 00 00 00 00 00 06 07 07 06 06 00 00 06
06 07 07 06 00 00 00 06 07 07 06 00 00 00 00 00
00 06 07 07 06 00 00 06 07 06 00 00 00 00 00 00
00 00 06 07 06 00 06 07 07 06 00 00 00 00 00 00
00 00 06 07 07 06 06 07 06 00 00 00 00 00 00 00
00 00 00 06 07 06 06 07 06 00 00 00 00 00 00 00
00 00 00 06 07 06 06 07 07 06 00 00 00 00 00 00
00 00 06 07 07 06 00 06 07 06 00 00 00 00 00 00
00 00 06 07 06 00 00 06 07 07 06 00 00 00 00 00
00 06 07 07 06 00 00 00 06 07 07 06 06 00 00 06
06 07 07 06 00 00 00 00 00 06 07 07 07 06 06 07
07 07 06 00 00 00 00 00 00 00 06 06 07 07 07 07
06 06 00 00 00 00 00 00 00 00 00 00 06 06 06 06
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 02 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 10 02 00
00 00 00 00 00 00 00 00 00 00 00 00 02 11 05 01
00 00 00 00 00 00 00 00 00 00 00 00 02 05 12 02
00 00 00 00 00 00 00 00 00 00 00 00 02 12 12 02
00 00 00 00 00 00 00 00 00 00 00 00 10 02 02 02
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 01
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 01
00 00 00 00 00 00 00 04 03 00 00 00 02 02 01 13
00 00 00 04 03 00 00 02 01 00 00 00 10 10 02 01
00 00 00 02 01 00 00 10 02 13 01 13 10 02 02 01
13 01 13 10 02 00 00 10 02 13 01 13 02 02 02 01
13 01 13 10 02 00 00 02 01 13 01 13 02 01 01 01
13 01 13 02 01 00 00 01 01 00 00 00 01 00 00 01
00 00 00 01 01 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 02 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 10 02 00
00 00 00 00 00 00 00 00 00 00 00 00 11 05 02 01
00 00 00 00 00 00 00 00 00 00 00 00 05 12 02 02
00 00 00 00 00 00 00 00 00 00 00 00 12 12 02 02
00 00 00 00 00 00 00 00 00 00 00 00 02 02 02 02
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 01
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 01
00 00 00 00 00 00 00 00 00 04 03 00 02 02 01 13
00 04 03 00 00 00 00 00 00 02 01 00 10 10 02 01
00 02 01 00 00 00 00 00 00 10 02 13 10 02 02 13
13 10 02 00 00 00 00 00 00 10 02 13 02 02 02 01
13 10 02 00 00 00 00 00 00 02 01 13 02 01 01 01
13 02 01 00 00 00 00 00 00 01 01 00 01 00 01 00
00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 02 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 10 02 00
00 00 00 00 00 00 00 00 00 00 00 00 02 02 05 12
00 00 00 00 00 00 00 00 00 00 00 00 10 02 12 12
00 00 00 00 00 00 00 00 00 00 00 00 10 02 12 12
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 02
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 01
00 00 00 00 00 00 00 00 00 00 00 00 10 10 02 01
00 00 00 00 00 00 00 00 00 04 03 00 02 02 01 13
00 04 03 00 00 00 00 00 00 02 01 00 10 10 02 01
00 02 01 00 00 00 00 00 00 10 02 13 10 02 02 01
13 10 02 00 00 00 00 00 00 10 02 13 02 02 02 01
13 10 02 00 00 00 00 00 00 02 01 13 02 01 01 01
13 02 01 00 00 00 00 00 00 01 01 00 00 01 00 01
00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 06 06 06 06 06 06 00 00 00 00
00 00 00 00 00 00 06 08 08 08 08 08 06 00 00 00
00 00 00 00 00 00 06 09 09 09 09 08 06 00 00 00
00 00 00 00 00 00 06 09 09 09 08 06 00 00 00 00
00 00 00 00 00 00 06 09 09 09 09 08 06 00 00 00
00 00 00 00 00 00 06 09 09 06 09 09 08 06 00 00
00 00 00 00 00 00 00 06 06 00 06 09 09 08 06 00
00 00 00 00 00 00 00 00 00 00 00 06 09 09 08 06
00 00 00 00 00 00 00 00 00 00 00 00 06 09 09 08
06 00 00 00 00 00 00 00 00 00 00 00 00 06 09 06
00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 07 04 00 00 00 00 00 00 04 03 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 04 03 00 00 00 00 00 00 03 02 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 03 02 00 00 00 00 00 00 02 01 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 02 01 00 00 00 00 00 00 01 01 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00

845
rtl/sprite_engine.v Normal file
View File

@@ -0,0 +1,845 @@
`timescale 1ns / 1ps
/*============================================================================
Aznable (custom 8-bit computer system) - Comet (sprite engine)
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 0.1
Date: 2021-10-31
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module sprite_engine #(
parameter SPRITE_RAM_WIDTH = 7,
parameter SPRITE_ROM_WIDTH = 14,
parameter SPRITE_POSITION_WIDTH = 9,
parameter SPRITE_COLRAM_WIDTH = 5,
parameter SPRITE_SIZE_WIDTH = 5 // Width of sprite size related operations
)(
input clk,
input reset,
input pause,
input hsync,
input vsync,
input vblank,
input [SPRITE_POSITION_WIDTH-1:0] hcnt,
input [SPRITE_POSITION_WIDTH-1:0] vcnt,
input [7:0] spriterom_data_out,
input [7:0] spriteram_data_out,
input [15:0] palrom_data_out,
input [15:0] spritelbram_data_out,
input spritecollisionram_data_out,
output reg [SPRITE_RAM_WIDTH-1:0] spriteram_addr,
output reg [SPRITE_COLRAM_WIDTH-1:0] spritecollisionram_addr,
output reg spritecollisionram_data_in,
output reg [SPRITE_ROM_WIDTH-1:0] sprom_addr,
output reg [7:0] palrom_addr,
output [SPRITE_POSITION_WIDTH:0] spritelbram_rd_addr,
output reg [SPRITE_POSITION_WIDTH:0] spritelbram_wr_addr,
output reg spritelbram_wr,
output reg [15:0] spritelbram_data_in,
output reg spritecollisionram_wr,
`ifdef DEBUG_SPRITE_COLLISION
output reg [16:0] spritedebugram_addr_b,
output reg [7:0] spritedebugram_data_in_b,
input [7:0] spritedebugram_data_out_b,
output reg spritedebugram_wr_b,
`endif
output [7:0] spr_r,
output [7:0] spr_g,
output [7:0] spr_b,
output spr_a
);
// State machine constants
localparam SE_INIT = 0;
localparam SE_IDLE = 1;
localparam SE_WAIT = 2;
localparam SE_RESET = 3;
localparam SE_CLEAR_BUFFER = 4;
localparam SE_SETUP_READ_Y = 5;
localparam SE_READ_Y_UPPER = 6;
localparam SE_READ_Y_LOWER = 7;
localparam SE_CHECK_Y = 8;
localparam SE_READ_X_UPPER = 9;
localparam SE_READ_X_LOWER = 10;
localparam SE_SETUP_WRITE = 11;
localparam SE_GET_PIXEL = 12;
localparam SE_STAGE_PIXEL = 13;
localparam SE_WRITE_PIXEL = 14;
localparam SE_LINE_COMPLETE = 15;
localparam SE_SETUP_LOAD_8x8_UPPER = 20;
localparam SE_SETUP_LOAD_8x8_LOWER = 21;
localparam SE_SETUP_LOAD_16x16_UPPER = 22;
localparam SE_SETUP_LOAD_16x16_LOWER = 23;
localparam SE_SETUP_LOAD_32x32_UPPER = 24;
localparam SE_SETUP_LOAD_32x32_LOWER = 25;
// Sprite line buffer has two slots - read and write. They alternate when hsync goes high.
reg spritelb_slot_rd = 1'b0;
reg spritelb_slot_wr = 1'b1;
// Track last hsync value
reg hsync_last;
// Sprite state machine control
reg [4:0] spr_state;
reg [4:0] spr_state_next;
// Sprite index counter and maximum sprite limit
reg [5:0] spr_index;
localparam spr_index_max = 6'd31;
// Sprite maximum sizes
localparam [6:0] spr_ram_item_width = 4;
localparam [SPRITE_POSITION_WIDTH-1:0] spr_line_max = 352;
reg [SPRITE_POSITION_WIDTH-1:0] spr_size; // Size of sprite in pixels (always square)
reg [SPRITE_POSITION_WIDTH-1:0] spr_x; // Sprite X position
reg [SPRITE_POSITION_WIDTH-1:0] spr_y; // Sprite Y position
reg spr_enable; // Sprite visibility enabled
reg spr_collide; // Sprite collision enabled
reg [1:0] spr_palette_index; // Sprite palette index
reg [5:0] spr_image_index; // Sprite image index
localparam [SPRITE_POSITION_WIDTH-1:0] spr_border_size = 32; // Sprite screen border width
reg [SPRITE_POSITION_WIDTH-1:0] spr_active_y; // Current active sprite engine Y
reg [SPRITE_SIZE_WIDTH:0] spr_pixel_index;// Current sprite X pixel
reg [SPRITE_ROM_WIDTH-1:0] spr_rom_offset; // Offset for current sprite size in image ROM
reg [9:0] spr_rom_y_offset; // Offset for current sprite Y line in image ROM
localparam [SPRITE_POSITION_WIDTH-1:0] spr_size_8x8 = {{SPRITE_POSITION_WIDTH-5{1'b0}}, 5'd7};
localparam [SPRITE_POSITION_WIDTH-1:0] spr_size_16x16 = {{SPRITE_POSITION_WIDTH-5{1'b0}}, 5'd15};
localparam [SPRITE_POSITION_WIDTH-1:0] spr_size_32x32 = {{SPRITE_POSITION_WIDTH-5{1'b0}}, 5'd31};
reg [SPRITE_ROM_WIDTH-1:0] spr_rom_offset_8x8;
reg [SPRITE_ROM_WIDTH-1:0] spr_rom_offset_16x16;
reg [SPRITE_ROM_WIDTH-1:0] spr_rom_offset_32x32;
//`define CASVAL_DEBUG
//`define CASVAL_DEBUG_TIMES
//`define CASVAL_DEBUG_OUTLINE
`ifdef CASVAL_DEBUG_TIMES
parameter SPR_TIMER_WIDTH = 11;
reg [SPR_TIMER_WIDTH-1:0] spr_timer_idle;
reg [SPR_TIMER_WIDTH-1:0] spr_linetime_max;
reg [SPR_TIMER_WIDTH-1:0] spr_timer_line;
`endif
// Sprite engine outputs
assign spritelbram_rd_addr = {spritelb_slot_rd, (hcnt + spr_border_size)};
assign spr_r = {spritelbram_data_out[4:0],spritelbram_data_out[4:2]};
assign spr_g = {spritelbram_data_out[9:5],spritelbram_data_out[9:7]};
assign spr_b = {spritelbram_data_out[14:10],spritelbram_data_out[14:12]};
assign spr_a = spritelbram_data_out[15];
// Collision system
localparam CP_IDLE = 0;
localparam CP_WAIT = 1;
localparam CP_STAGE_PIXEL = 2;
localparam CP_CHECK_PIXEL = 3;
localparam CP_WRITE_PIXEL = 4;
localparam CS_IDLE = 0;
localparam CS_WAIT = 1;
localparam CS_DETECT_BEGIN = 2;
localparam CS_DETECT = 3;
localparam CS_DETECT_COMPLETE = 4;
reg [3:0] col_primary_state = CP_IDLE;
reg [3:0] col_primary_state_next;
reg [3:0] col_secondary_state = CS_IDLE;
reg [3:0] col_secondary_state_next;
reg [SPRITE_POSITION_WIDTH-1:0] col_x;
reg [4:0] col_spriteindex;
reg [SPRITE_POSITION_WIDTH-1:0] col_buffer_primary_addr;
reg col_buffer_primary_wr;
reg [31:0] col_buffer_primary_data_in;
wire [31:0] col_buffer_primary_data_out;
reg [SPRITE_POSITION_WIDTH-1:0] col_buffer_secondary_addr;
reg col_buffer_secondary_wr;
reg [31:0] col_buffer_secondary_data_in;
wire [31:0] col_buffer_secondary_data_out;
reg [31:0] col_buffer_secondary_collisions;
wire [4:0] col_buffer_secondary_collisions_count1;
wire [4:0] col_buffer_secondary_collisions_count2;
count count1 (
.clk(clk),
.a(col_buffer_secondary_collisions),
.sum(col_buffer_secondary_collisions_count1)
);
count count2 (
.clk(clk),
.a(col_buffer_secondary_data_out),
.sum(col_buffer_secondary_collisions_count2)
);
reg col_buffer_primary_is_a;
//`define CASVAL_COLLISION_PRIMARY_DEBUG
//`define CASVAL_COLLISION_SECONDARY_DEBUG
reg [15:0] col_secondary_timer;
always @(posedge clk)
begin
if(reset)
begin
spr_state <= SE_IDLE;
end
hsync_last <= hsync;
if(!pause)
begin
// Primary collision state machine - Takes stage pixel instruction from sprite engine state machine
col_secondary_timer <= col_secondary_timer + 16'd1;
case (col_primary_state)
CP_IDLE:
begin
end
CP_WAIT:
begin
col_primary_state <= col_primary_state_next;
end
CP_STAGE_PIXEL:
begin
`ifdef CASVAL_COLLISION_PRIMARY_DEBUG
$display("CP_STAGE_PIXEL: x=%d i=%d", col_x, col_spriteindex);
`endif
// Set primary buffer to read existing pixel
col_buffer_primary_addr <= col_x;
col_buffer_primary_wr <= 1'b0;
//col_primary_state <= CP_CHECK_PIXEL;
col_primary_state_next <= CP_CHECK_PIXEL;
col_primary_state <= CP_WAIT;
end
CP_CHECK_PIXEL:
begin
`ifdef CASVAL_COLLISION_PRIMARY_DEBUG
$display("CP_CHECK_PIXEL: x,y=%d,%d i=%d ra=%x do=%b m=%b di=%", col_x, spr_active_y, col_spriteindex, col_buffer_primary_addr, col_buffer_primary_data_out, (32'b1 << col_spriteindex),col_buffer_primary_data_out | (32'b1 << col_spriteindex));
`endif
col_buffer_primary_data_in <= col_buffer_primary_data_out | (32'b1 << col_spriteindex);
col_buffer_primary_wr <= 1'b1;
col_primary_state <= CP_WRITE_PIXEL;
end
CP_WRITE_PIXEL:
begin
`ifdef CASVAL_COLLISION_PRIMARY_DEBUG
$display("CP_WRITE_PIXEL: x,y=%d,%d i=%d - wa=%x di=%x do=%x", col_x, spr_active_y, col_spriteindex, col_buffer_primary_addr, col_buffer_primary_data_in, col_buffer_primary_data_out);
`endif
col_buffer_primary_wr <= 1'b0;
col_buffer_primary_data_in <= 32'b0;
col_primary_state <= CP_IDLE;
end
endcase
end
// Sprite engine state machine
`ifdef CASVAL_DEBUG_TIMES
spr_timer_line <= spr_timer_line + 1'b1;
`endif
case (spr_state)
SE_INIT:
begin
`ifdef CASVAL_DEBUG_TIMES
// Reset line timer maximum
spr_linetime_max <= {{SPR_TIMER_WIDTH-1{1'b0}},1'b1};
`endif
// Start loading sprite ROM offsets
sprom_addr <= {SPRITE_ROM_WIDTH{1'b0}};
spr_state <= SE_WAIT;
spr_state_next <= SE_SETUP_LOAD_32x32_UPPER;
end
SE_SETUP_LOAD_32x32_UPPER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_LOAD_32x32_UPPER: addr=%x dout=%x", sprom_addr, spriterom_data_out);
`endif
// Load upper byte of 32x32 image offset
spr_rom_offset_32x32[SPRITE_ROM_WIDTH-1:8] <= spriterom_data_out[SPRITE_ROM_WIDTH-9:0];
// Increment sprite ROM address
sprom_addr <= sprom_addr + {{SPRITE_ROM_WIDTH-1{1'b0}},1'b1};
// Move to next state
spr_state <= SE_WAIT;
spr_state_next <= SE_SETUP_LOAD_32x32_LOWER;
end
SE_SETUP_LOAD_32x32_LOWER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_LOAD_32x32_LOWER: addr=%x dout=%x", sprom_addr, spriterom_data_out);
`endif
// Load lower byte of 32x32 image offset
spr_rom_offset_32x32[7:0] <= spriterom_data_out;
// Increment sprite ROM address
sprom_addr <= sprom_addr + {{SPRITE_ROM_WIDTH-1{1'b0}},1'b1};
// Move to next state
spr_state <= SE_WAIT;
spr_state_next <= SE_SETUP_LOAD_16x16_UPPER;
end
SE_SETUP_LOAD_16x16_UPPER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_LOAD_16x16_UPPER: addr=%x dout=%x", sprom_addr, spriterom_data_out);
`endif
// Load upper byte of 16x16 image offset
spr_rom_offset_16x16[SPRITE_ROM_WIDTH-1:8] <= spriterom_data_out[SPRITE_ROM_WIDTH-9:0];
// Increment sprite ROM address
sprom_addr <= sprom_addr + {{SPRITE_ROM_WIDTH-1{1'b0}},1'b1};
// Move to next state
spr_state <= SE_WAIT;
spr_state_next <= SE_SETUP_LOAD_16x16_LOWER;
end
SE_SETUP_LOAD_16x16_LOWER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_LOAD_16x16_LOWER: addr=%x dout=%x", sprom_addr, spriterom_data_out);
`endif
// Load lower byte of 16x16 image offset
spr_rom_offset_16x16[7:0] <= spriterom_data_out;
// Increment sprite ROM address
sprom_addr <= sprom_addr + {{SPRITE_ROM_WIDTH-1{1'b0}},1'b1};
// Move to next state
spr_state <= SE_WAIT;
spr_state_next <= SE_SETUP_LOAD_8x8_UPPER;
end
SE_SETUP_LOAD_8x8_UPPER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_LOAD_8x8_UPPER: addr=%x dout=%x", sprom_addr, spriterom_data_out);
`endif
// Load upper byte of 8x8 image offset
spr_rom_offset_8x8[SPRITE_ROM_WIDTH-1:8] <= spriterom_data_out[SPRITE_ROM_WIDTH-9:0];
// Increment sprite ROM address
sprom_addr <= sprom_addr + {{SPRITE_ROM_WIDTH-1{1'b0}},1'b1};
// Move to next state
spr_state <= SE_WAIT;
spr_state_next <= SE_SETUP_LOAD_8x8_LOWER;
end
SE_SETUP_LOAD_8x8_LOWER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_LOAD_8x8_LOWER: addr=%x dout=%x", sprom_addr, spriterom_data_out);
`endif
// Load lower byte of 8x8 image offset
spr_rom_offset_8x8[7:0] <= spriterom_data_out;
// Increment sprite ROM address
sprom_addr <= sprom_addr + {{SPRITE_ROM_WIDTH-1{1'b0}},1'b1};
// Move to next state
spr_state <= SE_IDLE;
end
SE_IDLE:
begin
// Wait for hsync to go high outside of reset
if(reset == 1'b0 && hsync && !hsync_last)
begin
// Rotate line buffer slots
spritelb_slot_rd <= spritelb_slot_rd + 1'b1;
spritelb_slot_wr <= spritelb_slot_wr + 1'b1;
// Calculate active Y line
spr_active_y <= (vcnt == 9'd255) ? spr_border_size : (vcnt + spr_border_size) + 9'd1;
spr_state <= SE_RESET;
end
`ifdef CASVAL_DEBUG_TIMES
else
begin
spr_timer_idle <= spr_timer_idle + 1'b1;
end
`endif
end
SE_WAIT:
begin
spr_state <= spr_state_next;
end
SE_RESET:
begin
// Reset sprite index
spr_index <= 6'd0;
`ifdef CASVAL_DEBUG_TIMES
$display("CASVAL->LEAVING SE_IDLE: vcnt = %d spr_active_y = %d", vcnt, spr_active_y);
$display("CASVAL->LEAVING SE_IDLE: spr_timer_idle = %d, spr_linetime_max=%d", spr_timer_idle, spr_linetime_max);
spr_timer_line <= {SPR_TIMER_WIDTH{1'b0}};
`endif
// Setup line buffer RAM for clear operation
spritelbram_wr_addr <= {spritelb_slot_wr, {SPRITE_POSITION_WIDTH{1'b0}}};
spritelbram_wr <= 1'b1;
spritelbram_data_in <= 16'b0;
spr_state <= SE_CLEAR_BUFFER;
end
SE_CLEAR_BUFFER:
begin
if(spritelbram_wr_addr[8:0] < spr_line_max[8:0])
begin
spritelbram_wr_addr <= spritelbram_wr_addr + 1'b1;
end
else
begin
// Disable line buffer write
spritelbram_wr <= 1'b0;
spr_state <= SE_SETUP_READ_Y;
end
end
SE_SETUP_READ_Y:
begin
// Setup address to read Y from sprite RAM
spriteram_addr <= spr_index * spr_ram_item_width;
spr_state <= SE_WAIT;
spr_state_next <= SE_READ_Y_UPPER;
end
SE_READ_Y_UPPER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_READ_Y_UPPER: spr: %d addr=%x dout=%x", spr_index, spriteram_addr, spriteram_data_out);
`endif
// Read enable bit from sprite RAM
spr_enable <= spriteram_data_out[7];
// Read collide bit from sprite RAM
spr_collide <= spriteram_data_out[6];
// Read palette index bits from sprite RAM
spr_palette_index <= spriteram_data_out[5:4];
// Read size bits from sprite RAM
spr_size <= (spriteram_data_out[3:2] == 2'd2 ? spr_size_8x8 :
spriteram_data_out[3:2] == 2'd1 ? spr_size_16x16 :
spriteram_data_out[3:2] == 2'd0 ? spr_size_32x32 : {SPRITE_POSITION_WIDTH{1'b0}});
// Read Y upper 1 bit from sprite RAM
spr_y[8] <= spriteram_data_out[0];
// Increment sprite RAM address
spriteram_addr <= spriteram_addr + 1'b1;
spr_state <= SE_WAIT;
spr_state_next <= SE_READ_Y_LOWER;
end
SE_READ_Y_LOWER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_READ_Y_LOWER: spr: %d addr=%x dout=%x", spr_index, spriteram_addr, spriteram_data_out);
`endif
// Read Y lower 8 bits from sprite RAM
spr_y[7:0] <= spriteram_data_out;
// Increment sprite RAM address
spriteram_addr <= spriteram_addr + 1'b1;
spr_state <= SE_CHECK_Y;
end
SE_CHECK_Y:
begin
`ifdef CASVAL_DEBUG
//$display("CASVAL->SE_CHECK_Y: spr_index=%d y: %d", spr_index, spr_y);
`endif
//// If this sprite is enabled and current line is within sprite Y area
if(spr_enable==1'b1 && spr_active_y >= spr_y && spr_active_y <= spr_y + spr_size)
begin
`ifdef CASVAL_DEBUG
$display("SE_CHECK_Y PASSED: spr_index=%d", spr_index);
`endif
spr_state <= SE_READ_X_UPPER;
end
else
begin
// If no then move to next sprite or finish
if(spr_index == spr_index_max)
begin
spr_state <= SE_LINE_COMPLETE;
end
else
begin
// Increment sprite index
spr_index <= spr_index + 1'd1;
spr_state <= SE_SETUP_READ_Y;
end
end
end
SE_READ_X_UPPER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_READ_X_UPPER: addr=%x dout=%x", spriteram_addr, spriteram_data_out);
`endif
// Read image index 6 bits from sprite RAM
spr_image_index <= spriteram_data_out[7:2];
// Read X upper 1 bit from sprite RAM
spr_x[8] <= spriteram_data_out[0];
// Increment sprite RAM address
spriteram_addr <= spriteram_addr + 1'b1;
spr_state <= SE_WAIT;
spr_state_next <= SE_READ_X_LOWER;
end
SE_READ_X_LOWER:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_READ_X_LOWER: addr=%x dout=%x", spriteram_addr, spriteram_data_out);
`endif
// Read X lower 8 bits from sprite RAM
spr_x[7:0] <= spriteram_data_out;
// Set up offset for sprite ROM read
spr_rom_y_offset <= spr_active_y - spr_y;
// Set up ROM offset for sprite size
case(spr_size)
spr_size_32x32: spr_rom_offset <= spr_rom_offset_32x32;
spr_size_16x16: spr_rom_offset <= spr_rom_offset_16x16;
default: spr_rom_offset <= spr_rom_offset_8x8;
endcase
spr_state <= SE_SETUP_WRITE;
end
SE_SETUP_WRITE:
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_SETUP_WRITE: AY: %d Y: %d X: %d I: %d O: %d", spr_active_y, spr_y, spr_x, spr_image_index, spr_rom_y_offset);
`endif
// Enable line buffer write
spritelbram_wr <= 1'b0;
// Setup line buffer write address
spritelbram_wr_addr <= {spritelb_slot_wr, spr_x};
// Set sprite rom read address
case(spr_size)
spr_size_32x32:
begin
sprom_addr <= spr_rom_offset + { spr_image_index[3:0], 10'b0} + { spr_rom_y_offset[7:0], 5'b0};
end
spr_size_16x16:
begin
sprom_addr <= spr_rom_offset + { spr_image_index[5:0], 8'b0} + { spr_rom_y_offset[8:0], 4'b0};
end
default:
begin
// Default to 8x8
sprom_addr <= spr_rom_offset + { 2'b0, spr_image_index[5:0], 6'b0} + { spr_rom_y_offset[9:0], 3'b0};
end
endcase
// Reset sprite pixel index and count
spr_pixel_index <= {SPRITE_SIZE_WIDTH+1{1'b0}};
spr_state <= SE_WAIT;
spr_state_next <= SE_GET_PIXEL;
end
SE_GET_PIXEL:
begin
if(spr_pixel_index > spr_size[SPRITE_SIZE_WIDTH:0])
begin
// Move to next sprite or finish
if(spr_index == spr_index_max)
begin
spr_state <= SE_LINE_COMPLETE;
end
else
begin
spr_index <= spr_index + 5'd1;
spr_state <= SE_SETUP_READ_Y;
end
end
else
begin
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_GET_PIXEL: y: %d, x: %d i: %d, sprom_addr < %x, palrom_addr < %x", spr_y, spr_pixel_index, spr_image_index, sprom_addr, {spriterom_data_out[4:0],1'b0});
`endif
// Setup palette address to read pixel colour
palrom_addr <= {spr_palette_index, spriterom_data_out[4:0],1'b0};
// Increment sprite ROM address
sprom_addr <= sprom_addr + 1'b1;
// Disable line buffer write
spritelbram_wr <= 1'b0;
spr_state <= SE_WAIT;
spr_state_next <= SE_STAGE_PIXEL;
end
end
SE_STAGE_PIXEL:
begin
`ifdef CASVAL_DEBUG_OUTLINE
/* verilator lint_off WIDTH */
if(spr_pixel_index == 0 || spr_pixel_index == spr_size || spr_active_y == spr_y || spr_active_y == (spr_y + spr_size)) begin
spritelbram_data_in <= 16'hFFFF;
spritelbram_wr <= 1'b1;
spr_state <= SE_WRITE_PIXEL;
end
/* verilator lint_on WIDTH */
else
begin
`endif
// Get pixel colour from palette rom
if(palrom_data_out[15])
begin
// If palette colour alpha is high, stage input to line buffer
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_STAGE_PIXEL: ay: %d y: %d, x: %d i: %d, spritelbram_data_in < %x", spr_active_y, spr_y, spr_pixel_index, spr_image_index, palrom_data_out);
`endif
// Enable line buffer write
spritelbram_wr <= 1'b1;
// Fill line buffer data in with palette ROM data out
spritelbram_data_in <= palrom_data_out;
// Trigger collision check (not in vblank)
if(!vblank && spr_collide)
begin
col_spriteindex <= spr_index[4:0];
col_x <= spr_x + {{(SPRITE_POSITION_WIDTH-SPRITE_SIZE_WIDTH)-1{1'b0}}, spr_pixel_index};
col_primary_state <= CP_STAGE_PIXEL;
end
// Move to write pixel state
spr_state <= SE_WRITE_PIXEL;
end
else
begin
// Pixel is transparent so move to next
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_STAGE_PIXEL: y: %d, x: %d i: %d, spritelbram_data_in < %x - FAIL ALPHA CHECK", spr_y,spr_pixel_index, spr_image_index, palrom_data_out);
`endif
// Increment line buffer write address
spritelbram_wr_addr <= spritelbram_wr_addr + 1'b1;
// Increment sprite pixel index
spr_pixel_index <= spr_pixel_index + 1'b1;
spr_state <= SE_GET_PIXEL;
end
end
`ifdef CASVAL_DEBUG_OUTLINE
end
`endif
SE_WRITE_PIXEL:
begin
// Get pixel colour from palette rom and stage input to line buffer
`ifdef CASVAL_DEBUG
$display("CASVAL->SE_WRITE_PIXEL: y: %d, x: %d i: %d, spritelbram_wr_addr < %d, spritelbram_data_in=%b", spr_y, spr_pixel_index, spr_image_index, spritelbram_wr_addr[SPRITE_POSITION_WIDTH-1:0], spritelbram_data_in);
`endif
// Disable line buffer write
spritelbram_wr <= 1'b0;
// Increment line buffer write address
spritelbram_wr_addr <= spritelbram_wr_addr + 1'b1;
// Increment sprite pixel index
spr_pixel_index <= spr_pixel_index + 1'b1;
spr_state <= SE_GET_PIXEL;
end
SE_LINE_COMPLETE:
begin
// Once all sprites have been processed for each pixel return to idle
`ifdef CASVAL_DEBUG_TIMES
$display("CASVAL->SE_LINE_COMPLETE: counter=%d", spr_timer_line);
// Update slowest line counter
if(spr_timer_line > spr_linetime_max)
begin
spr_linetime_max <= spr_timer_line;
end
// Reset idle timer
spr_timer_idle <= {SPR_TIMER_WIDTH{1'b0}};
`endif
spr_state <= SE_IDLE;
end
endcase
if(!pause)
begin
// Collision FSM
// When hsync goes high, rotate collision buffers and start detection pass for previous line
if(hsync && !hsync_last)
begin
col_secondary_state <= CS_DETECT_BEGIN;
col_buffer_primary_is_a <= ~col_buffer_primary_is_a;
end
case (col_secondary_state)
CS_WAIT:
begin
col_secondary_state <= col_secondary_state_next;
end
CS_DETECT_BEGIN:
begin
// Reset address and write states for secondary buffer
col_buffer_secondary_addr <= 9'b0;
col_buffer_secondary_data_in <= 32'b0;
col_buffer_secondary_wr <= 1'b1;
col_buffer_secondary_collisions <= 32'b0;
col_secondary_timer <= 16'b0;
col_secondary_state <= CS_DETECT;
`ifdef CASVAL_COLLISION_SECONDARY_DEBUG
$display("CS_DETECT_BEGIN t=%d hc=d%", col_secondary_timer, hcnt);
`endif
end
CS_DETECT:
begin
`ifdef CASVAL_COLLISION_SECONDARY_DEBUG
$display("CS_DETECT t=%d : x=%d c=%d cc1=%d", col_secondary_timer, col_buffer_secondary_addr, col_buffer_secondary_collisions, col_buffer_secondary_collisions_count1,);
`endif
// Check each pixel for a collision
if(col_buffer_secondary_collisions_count2 > 5'd1)
begin
//$display("CS_DETECT t=%d : x=%d c=%d cc1=%d", col_secondary_timer, col_buffer_secondary_addr, col_buffer_secondary_collisions, col_buffer_secondary_collisions_count1);
col_buffer_secondary_collisions <= col_buffer_secondary_collisions | col_buffer_secondary_data_out;
`ifdef DEBUG_SPRITE_COLLISION
//$display("CS_DETECT_DEBUG_OUT t=%d : a=%x", col_secondary_timer, ((spr_active_y) * 9'd320) + {8'b0, col_buffer_secondary_addr});
spritedebugram_data_in_b <= 8'hFF;
spritedebugram_wr_b <= 1'b1;
spritedebugram_addr_b <= ((spr_active_y) * 9'd320) + {8'b0, col_buffer_secondary_addr};
`endif
end
if(col_buffer_secondary_addr == spr_line_max - 1'b1)
begin
spritecollisionram_wr <= 1'b0;
spritecollisionram_addr <= {SPRITE_COLRAM_WIDTH{1'b0}};
`ifdef CASVAL_COLLISION_SECONDARY_DEBUG
$display(">CS_DETECT_COMPLETE t=%d : y=%d hc=%d vc=%d", col_secondary_timer, spr_active_y, hcnt, vcnt);
`endif
col_secondary_state <= CS_DETECT_COMPLETE;
end
else
begin
col_buffer_secondary_addr <= col_buffer_secondary_addr + 9'b1;
end
end
CS_DETECT_COMPLETE:
begin
// Copy individual bits from col_buffer_secondary_collisions into sprite collision ram
if(spritecollisionram_wr == 1'b0)
begin
`ifdef CASVAL_COLLISION_SECONDARY_DEBUG
$display("CS_DETECT_COMPLETE t=%d : RD b=%b c=%d x=%d col=%d y=%d do=%d di=%d", col_secondary_timer, col_buffer_secondary_collisions, col_buffer_secondary_collisions_count1, spritecollisionram_addr, col_buffer_secondary_collisions[spritecollisionram_addr], spr_active_y, spritecollisionram_data_out, col_buffer_secondary_collisions[spritecollisionram_addr] | spritecollisionram_data_out);
`endif
if(col_buffer_secondary_collisions_count1 > 5'b0)
begin
spritecollisionram_data_in <= col_buffer_secondary_collisions[spritecollisionram_addr] | spritecollisionram_data_out;
end
else
begin
spritecollisionram_data_in <= spritecollisionram_data_out;
end
spritecollisionram_wr <= 1'b1;
col_secondary_state <= CS_WAIT;
col_secondary_state_next <= CS_DETECT_COMPLETE;
end
else
begin
`ifdef CASVAL_COLLISION_SECONDARY_DEBUG
$display("CS_DETECT_COMPLETE WR t=%d : x=%d b=%b c=%d col=%d y=%d do=%d di=%d", col_secondary_timer, spritecollisionram_addr, col_buffer_secondary_collisions, col_buffer_secondary_collisions_count1, col_buffer_secondary_collisions[spritecollisionram_addr], spr_active_y, spritecollisionram_data_out, col_buffer_secondary_collisions[spritecollisionram_addr] | spritecollisionram_data_out);
`endif
if(spritecollisionram_addr == {SPRITE_COLRAM_WIDTH{1'b1}})
begin
`ifdef CASVAL_COLLISION_SECONDARY_DEBUG
$display("CS_DETECT_COMPLETE FINISHED t=%d hc=d%", col_secondary_timer, hcnt);
$display("CS_DETECT_COMPLETE FINISHED t=%d : b=%b bc=%d col=%d y=%d do=%d di=%d", col_secondary_timer, col_buffer_secondary_collisions, col_buffer_secondary_collisions_count1, col_buffer_secondary_collisions[spritecollisionram_addr], spr_active_y, spritecollisionram_data_out, col_buffer_secondary_collisions[spritecollisionram_addr] | spritecollisionram_data_out);
`endif
spritecollisionram_addr <= {SPRITE_COLRAM_WIDTH{1'b0}};
col_secondary_state <= CS_IDLE;
end
else
begin
spritecollisionram_addr <= spritecollisionram_addr + {{SPRITE_COLRAM_WIDTH-1{1'b0}},1'b1};
col_secondary_state <= CS_WAIT;
col_secondary_state_next <= CS_DETECT_COMPLETE;
end
spritecollisionram_wr <= 1'b0;
end
end
endcase
end
end
wire [31:0] col_buffer_data_out_a;
wire [31:0] col_buffer_data_out_b;
assign col_buffer_primary_data_out = col_buffer_primary_is_a ? col_buffer_data_out_a : col_buffer_data_out_b;
assign col_buffer_secondary_data_out = !col_buffer_primary_is_a ? col_buffer_data_out_a : col_buffer_data_out_b;
// Sprite Collision Buffer RAM A
spram #(9,32) spritecollisionbufferram_a
(
.clock(clk),
.address(col_buffer_primary_is_a ? col_buffer_primary_addr : col_buffer_secondary_addr),
.wren(col_buffer_primary_is_a ? col_buffer_primary_wr : col_buffer_secondary_wr),
.data(col_buffer_primary_is_a ? col_buffer_primary_data_in : col_buffer_secondary_data_in),
.q(col_buffer_data_out_a)
);
// Sprite Collision Buffer RAM B
spram #(9,32) spritecollisionbufferram_b
(
.clock(clk),
.address(!col_buffer_primary_is_a ? col_buffer_primary_addr : col_buffer_secondary_addr),
.wren(!col_buffer_primary_is_a ? col_buffer_primary_wr : col_buffer_secondary_wr),
.data(!col_buffer_primary_is_a ? col_buffer_primary_data_in : col_buffer_secondary_data_in),
.q(col_buffer_data_out_b)
);
endmodule
module count
(
input clk,
input [31:0] a,
output reg [4:0] sum
);
reg [5:0] n;
always @(negedge clk) begin
sum = 0;
for (n=0; n<=6'd31; n=n+6'd1) begin
sum = sum + {4'b0,a[n[4:0]]};
end
end
endmodule

142
rtl/starfield.v Normal file
View File

@@ -0,0 +1,142 @@
/*============================================================================
Aznable (custom 8-bit computer system) - Moroboshi (starfield)
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-11-06
Based on Project F: Ad Astra - Starfield
(C)2021 Will Green, open source hardware released under the MIT License
Learn more at https://projectf.io
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
`default_nettype none
`timescale 1ns / 1ps
module starfield #(
parameter [LEN-1:0] H=800,
parameter [LEN-1:0] V=525,
parameter LEN=25,
parameter TAPS=25'b1010000000000000000000000,
parameter SEED=25'b1111111111111110000000000,
parameter MASK=25'b1111111111111111111111111
) (
input wire clk,
input wire en,
input wire pause,
input wire rst,
input wire vblank,
input wire [2:0] addr, // Write address - 0 = enable, 1 = horizontal direction + speed msbs, 2 = horizontal speed lsbs, 3 = vertical direction + speed msbs, 4 = vertical speed lsbs
input wire [7:0] data_in,
input wire write,
output wire sf_on, // star on (alpha)
output wire [7:0] sf_star // star brightness
);
reg [LEN-1:0] RST_CNT; // counter starts at zero, so sub 1
reg [LEN-1:0] seed;
reg enabled;
reg vdirection;
reg [14:0] vspeed_set;
reg [7:0] vincrement;
reg [15:0] vtimer;
wire [14:0] vspeed_actual = pause ? 15'b0 : vspeed_set;
reg hdirection;
reg [14:0] hspeed_set;
reg [7:0] hincrement;
reg [15:0] htimer;
wire [14:0] hspeed_actual = pause ? 15'b0 : hspeed_set;
wire [LEN-1:0] sf_reg;
reg [LEN-1:0] sf_cnt;
always @(posedge clk)
begin
// Reset seed
if(rst)
begin
seed <= SEED;
RST_CNT <= (H * V) - 1'b1;
end
// CPU write
if(write)
begin
case(addr)
3'd0: enabled <= data_in[0];
3'd1: begin hdirection <= data_in[7]; hspeed_set[14:8] <= data_in[6:0]; end
3'd2: hspeed_set[7:0] <= data_in;
3'd3: begin vdirection <= data_in[7]; vspeed_set[14:8] <= data_in[6:0]; end
3'd4: vspeed_set[7:0] <= data_in;
default:
begin
end
endcase
end
if (en)
begin
sf_cnt <= sf_cnt + 1'b1;
if(sf_cnt == RST_CNT)
begin
htimer = htimer + hspeed_actual;
hincrement = 8'b0;
if(htimer >= 16'hFF)
begin
hincrement = htimer[15:8] > 8'b0 ? htimer[15:8] : 8'b1;
htimer = htimer - {hincrement[7:0], 8'b0};
end
vtimer = vtimer + vspeed_actual;
vincrement = 8'b0;
if(vtimer >= 16'hFF)
begin
vincrement = vtimer[15:8] > 8'b0 ? vtimer[15:8] : 8'b1;
vtimer = vtimer - {vincrement[7:0], 8'b0};
end
/* verilator lint_off WIDTH */
if(pause)
RST_CNT <= (H * V) - 1'b1;
else
RST_CNT <= (H * (vdirection ? V + vincrement : V - vincrement)) + (hdirection ? hincrement : -hincrement) - 1'b1;
/* verilator lint_on WIDTH */
sf_cnt <= 0;
end
end
if (rst) sf_cnt <= 0;
end
assign sf_on = &{sf_reg | MASK} & enabled;
assign sf_star = sf_reg[7:0];
lfsr #(
.LEN(LEN),
.TAPS(TAPS)
) lsfr_sf (
.clk(clk),
.rst(sf_cnt == {LEN{1'b0}} ),
.en(en),
.seed(seed),
.sreg(sf_reg)
);
endmodule

View File

@@ -21,10 +21,13 @@
===========================================================================*/
module system (
input clk_sys,
input ce_pix,
input clk_24,
input ce_6,
input ce_2,
input reset,
input [13:0] dn_addr,
input pause,
input menu, // Active-high trigger to open menu in system
input [16:0] dn_addr,
input dn_wr,
input [7:0] dn_data,
input [7:0] dn_index,
@@ -41,7 +44,7 @@ module system (
// 6 devices, 8 bits each - paddle 0..255
input [47:0] paddle,
// 6 devices, 16 bits eachspinner [7:0] -128..+127, [8] - toggle with every update, [9-15] padding
// 6 devices, 16 bits each spinner [7:0] -128..+127, [8] - toggle with every update, [9-15] padding
input [95:0] spinner,
// ps2 alternative interface.
@@ -61,7 +64,9 @@ module system (
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HB,
output VGA_VB
output VGA_VB,
output [15:0] AUDIO_L,
output [15:0] AUDIO_R
);
localparam [8:0] VGA_WIDTH = 9'd320;
@@ -78,11 +83,11 @@ wire [8:0] vcnt;
// Display timing module from JTFRAME
jtframe_vtimer #(
.HB_START(VGA_WIDTH - 1'b1),
.VB_START(VGA_HEIGHT- 1'b1)
.VB_START(VGA_HEIGHT - 1'b1)
) vtimer
(
.clk(clk_sys),
.pxl_cen(ce_pix),
.clk(clk_24),
.pxl_cen(ce_6),
.V(vcnt),
.H(hcnt),
.Hinit(),
@@ -94,91 +99,21 @@ jtframe_vtimer #(
);
// Millisecond timer
reg [15:0] timer;
reg [14:0] timer_divider = 15'd0;
always @(posedge clk_sys)
begin
if(timer_cs == 1'b1 && cpu_wr_n == 1'b0)
begin
timer <= 16'd0;
timer_divider <= 15'd0;
end
else
begin
if(timer_divider==15'd24000)
begin
timer <= timer + 16'd1;
timer_divider <= 15'd0;
end
else
begin
timer_divider <= timer_divider + 15'd1;
end
end
end
// Character map
wire [3:0] chpos_x = 4'd7 - hcnt[2:0];
wire [2:0] chpos_y = vcnt[2:0];
wire [5:0] chram_x = hcnt[8:3];
wire [5:0] chram_y = vcnt[8:3];
wire [11:0] chram_addr = {chram_y, chram_x};
wire [11:0] chrom_addr = {1'b0, chmap_data_out[7:0], chpos_y};
wire chpixel = chrom_data_out[chpos_x[2:0]];
// RGB mixer
wire [2:0] r_temp = chpixel ? fgcolram_data_out[2:0] : bgcolram_data_out[2:0];
wire [2:0] g_temp = chpixel ? fgcolram_data_out[5:3] : bgcolram_data_out[5:3];
wire [1:0] b_temp = chpixel ? fgcolram_data_out[7:6] : bgcolram_data_out[7:6];
// Convert RGb to 24bpp
assign VGA_R = {{2{r_temp}},2'b0};
assign VGA_G = {{2{g_temp}},2'b0};
assign VGA_B = {{3{b_temp}},2'b0};
// CPU control signals
wire [15:0] cpu_addr;
wire [7:0] cpu_din;
wire [7:0] cpu_dout;
wire cpu_rd_n;
wire cpu_wr_n;
wire cpu_mreq_n;
// include Z80 CPU
tv80s T80x (
.reset_n ( !reset ),
.clk ( clk_sys ),
.wait_n ( 1'b1 ),
.int_n ( 1'b1 ),
.nmi_n ( 1'b1 ),
.busrq_n ( 1'b1 ),
.mreq_n ( cpu_mreq_n ),
.rd_n ( cpu_rd_n ),
.wr_n ( cpu_wr_n ),
.A ( cpu_addr ),
.di ( cpu_din ),
.dout ( cpu_dout ),
.m1_n (),
.iorq_n (),
.rfsh_n (),
.halt_n (),
.busak_n ()
);
// RAM data to CPU
wire [7:0] pgrom_data_out;
wire [7:0] chrom_data_out;
wire [7:0] wkram_data_out;
wire [7:0] chram_data_out;
wire [7:0] fgcolram_data_out;
wire [7:0] bgcolram_data_out;
// RAM data to GFX
wire [7:0] chmap_data_out;
wire [15:0] timer;
generic_timer #(16,15,24) ms_timer
(
.clk(clk_24),
.reset(reset || (timer_cs && !cpu_wr_n)),
.counter(timer)
);
// Hardware inputs
wire [7:0] in0_data_out = {VGA_HS, VGA_VS,VGA_HB, VGA_VB, 4'b1000};
`ifdef DEBUG_SIMULATION
wire debug = 1'b1;
`else
wire debug = 1'b0;
`endif
wire [7:0] in0_data_out = {VGA_HS, VGA_VS,VGA_HB, VGA_VB, 2'b10, menu, debug};
wire [7:0] joystick_data_out = joystick[{cpu_addr[4:0],3'd0} +: 8];
wire [7:0] analog_l_data_out = analog_l[{cpu_addr[3:0],3'd0} +: 8];
wire [7:0] analog_r_data_out = analog_r[{cpu_addr[3:0],3'd0} +: 8];
@@ -188,44 +123,114 @@ wire [7:0] ps2_key_data_out = ps2_key[{cpu_addr[0],3'd0} +: 8];
wire [7:0] ps2_mouse_data_out = ps2_mouse[{cpu_addr[2:0],3'd0} +: 8];
wire [7:0] timestamp_data_out = timestamp[{cpu_addr[2:0],3'd0} +: 8];
wire [7:0] timer_data_out = timer[{cpu_addr[0],3'd0} +: 8];
wire [7:0] tilemapcontrol_data_out;
wire [7:0] music_data_out;
// CPU address decodes
wire pgrom_cs = cpu_addr[15:14] == 2'b00;
//wire chrom_cs = cpu_addr[15:12] == 4'b0100; // CPU never accesses the character ROM data directly
wire chram_cs = cpu_addr[15:11] == 5'b10000;
wire fgcolram_cs = cpu_addr[15:11] == 5'b10001;
wire bgcolram_cs = cpu_addr[15:11] == 5'b10010;
wire wkram_cs = cpu_addr[15:14] == 2'b11;
wire in0_cs = cpu_addr == 16'h6000;
wire joystick_cs = cpu_addr[15:8] == 8'b01110000;
wire analog_l_cs = cpu_addr[15:8] == 8'b01110001;
wire analog_r_cs = cpu_addr[15:8] == 8'b01110010;
wire paddle_cs = cpu_addr[15:8] == 8'b01110011;
wire spinner_cs = cpu_addr[15:8] == 8'b01110100;
wire ps2_key_cs = cpu_addr[15:8] == 8'b01110101;
wire ps2_mouse_cs = cpu_addr[15:8] == 8'b01110110;
wire timestamp_cs = cpu_addr[15:8] == 8'b01110111;
wire timer_cs = cpu_addr[15:8] == 8'b01111000;
// - Program ROM
wire pgrom_cs = cpu_addr[15] == 1'b0;
// - Memory mapped inputs
wire [7:0] memory_map_addr = cpu_addr[15:8];
wire in0_cs = memory_map_addr == 8'b10000000;
wire joystick_cs = memory_map_addr == 8'b10000001;
wire analog_l_cs = memory_map_addr == 8'b10000010;
wire analog_r_cs = memory_map_addr == 8'b10000011;
wire paddle_cs = memory_map_addr == 8'b1000100;
wire spinner_cs = memory_map_addr == 8'b10000101;
wire ps2_key_cs = memory_map_addr == 8'b10000110;
wire ps2_mouse_cs = memory_map_addr == 8'b10000111;
wire timestamp_cs = memory_map_addr == 8'b10001000;
wire timer_cs = memory_map_addr == 8'b10001001;
wire starfield1_cs = memory_map_addr == 8'b10001010 && cpu_addr[5:4] == 2'b00;
wire starfield2_cs = memory_map_addr == 8'b10001010 && cpu_addr[5:4] == 2'b01;
wire starfield3_cs = memory_map_addr == 8'b10001010 && cpu_addr[5:4] == 2'b10;
wire system_pause_cs = cpu_addr == 16'b1000101000110000;
wire system_menu_cs = cpu_addr == 16'b1000101000110001;
wire sound_cs = cpu_addr[15:4] == 12'b100010110000;
wire music_cs = cpu_addr[15:4] == 12'b100010110001;
//always @(posedge timestamp[32]) begin
// $display("%b", timestamp);
// end
//always @(posedge clk_sys) begin
// if(pgrom_cs) $display("%x pgrom o %x", cpu_addr, pgrom_data_out);
// if(wkram_cs) $display("%x wkram i %x o %x w %b", cpu_addr, cpu_dout, wkram_data_out, wkram_wr);
// if(chram_cs) $display("%x chram i %x o %x w %b", cpu_addr, cpu_dout, chram_data_out, chram_wr);
// if(fgcolram_cs) $display("%x fgcolram i %x o %x w %b", cpu_addr, cpu_dout, fgcolram_data_out, fgcolram_wr);
// if(in0_cs) $display("%x in0 i %x o %x", cpu_addr, cpu_dout, in0_data_out);
// if(joystick_cs) $display("joystick %b %b", joystick_bit, joystick_data_out);
// if(analog_l_cs) $display("analog_l %b %b", analog_l_bit, analog_l_data_out);
// if(analog_r_cs) $display("analog_r %b %b", analog_r_bit, analog_r_data_out);
// if(paddle_cs) $display("paddle %b", paddle_data_out);
// if(ps2_key_cs) $display("ps2_key %b %x", ps2_key_data_out, cpu_addr[3:0]);
// $display("%x", cpu_addr);
//end
// always @(posedge ps2_mouse[24]) begin
// $display("%b", ps2_mouse);
// end
// - Casval (character map)
wire chram_cs = cpu_addr[15:11] == 5'b10011;
wire fgcolram_cs = cpu_addr[15:11] == 5'b10100;
wire bgcolram_cs = cpu_addr[15:11] == 5'b10101;
// - Comet (sprite engine)
wire spriteram_cs = cpu_addr[15:11] == 5'b10110 && !spritecollisionram_cs;
wire spritecollisionram_cs = memory_map_addr == 8'b10110100;
// - Zechs (tile map)
wire tilemapcontrol_cs = cpu_addr[15:2] == 14'b10001100000000;
wire tilemapram_cs = cpu_addr >= 16'h8C10 && cpu_addr < 16'h8F10;
// - CPU working RAM
wire wkram_cs = cpu_addr[15:14] == 2'b11;
// System pause trigger
reg pause_trigger = 0;
wire pause_system = pause || pause_trigger;
always @(posedge clk_24) begin
if(system_pause_cs && !cpu_wr_n) pause_trigger <= 1'b1;
if(pause) pause_trigger<=1'b0;
end
// System menu trigger
reg menu_trigger;
always @(posedge clk_24) begin
if(menu) menu_trigger <= 1'b1;
if(system_menu_cs && !cpu_wr_n) menu_trigger <= 1'b0;
end
always @(posedge clk_24) begin
//if(pgrom_cs) $display("%x pgrom o %x", cpu_addr, pgrom_data_out);
//if(wkram_cs) $display("%x wkram i %x o %x w %b", cpu_addr, cpu_dout, wkram_data_out, wkram_wr);
//if(chram_cs) $display("%x chram i %x o %x w %b", cpu_addr, cpu_dout, chram_data_out, chram_wr);
//if(fgcolram_cs) $display("%x fgcolram i %x o %x w %b", cpu_addr, cpu_dout, fgcolram_data_out, fgcolram_wr);
//if(in0_cs) $display("%x in0 i %x o %x", cpu_addr, cpu_dout, in0_data_out);
//if(joystick_cs) $display("joystick %b %b", joystick_bit, joystick_data_out);
//if(analog_l_cs) $display("analog_l %b %b", analog_l_bit, analog_l_data_out);
//if(analog_r_cs) $display("analog_r %b %b", analog_r_bit, analog_r_data_out);
//if(paddle_cs) $display("paddle %b", paddle_data_out);
//if(ps2_key_cs) $display("ps2_key %b %x", ps2_key_data_out, cpu_addr[3:0]);
// if(starfield1_cs) $display("starfield1 %b %b", cpu_addr, cpu_dout);
// if(starfield2_cs) $display("starfield2 %b %b", cpu_addr, cpu_dout);
// if(starfield3_cs) $display("starfield3 %b %b", cpu_addr, cpu_dout);
//if(!cpu_wr_n) $display("cpu_write %x %b",cpu_addr, cpu_dout);
//if(spritecollisionram_cs && !cpu_wr_n) $display("spritecollisionram %b %b %b", cpu_wr_n, cpu_addr, cpu_dout);
//if(spriteram_cs && !cpu_wr_n) $display("spriteram_cs %x %b", cpu_addr[SPRITE_RAM_WIDTH-1:0], cpu_dout);
//if(sound_cs && !cpu_wr_n) $display("sound_cs %b %b", cpu_addr, cpu_dout);
//if(music_cs && !cpu_wr_n) $display("music_cs %b %b", cpu_addr, cpu_dout);
//if(tilemapcontrol_cs) $display("tilemapcontrol_cs addr=%x dout=%x din=%x wr=%b", cpu_addr, cpu_dout, tilemapcontrol_data_out, cpu_wr_n);
//if(tilemapram_cs && !cpu_wr_n) $display("tilemapram_cs addr=%x dout=%x", cpu_addr, cpu_dout);
end
// ROM data available to CPU
wire [7:0] pgrom_data_out;
wire [7:0] chrom_data_out;
// RAM data available to CPU
wire [7:0] wkram_data_out;
wire [7:0] chram_data_out;
wire [7:0] fgcolram_data_out;
wire [7:0] bgcolram_data_out;
// RAM data not available to CPU
wire [7:0] chmap_data_out;
// Rom upload write enables
wire pgrom_wr = dn_wr && dn_index == 8'd0;
wire chrom_wr = dn_wr && dn_index == 8'd1;
wire palrom_wr = dn_wr && dn_index == 8'd2;
wire spriterom_wr = dn_wr && dn_index == 8'd3;
wire musicrom_wr = dn_wr && dn_index == 8'd4;
wire soundrom_wr = dn_wr && dn_index == 8'd5;
wire tilemaprom_wr = dn_wr && dn_index == 8'd6;
// Ram write enables
wire wkram_wr = !cpu_wr_n && wkram_cs;
wire chram_wr = !cpu_wr_n && chram_cs;
wire fgcolram_wr = !cpu_wr_n && fgcolram_cs;
wire bgcolram_wr = !cpu_wr_n && bgcolram_cs;
wire spriteram_wr = !cpu_wr_n && spriteram_cs;
wire spritecollisionram_wr;
wire tilemapcontrol_wr = !cpu_wr_n && tilemapcontrol_cs;
wire tilemapram_wr = !cpu_wr_n && tilemapram_cs;
// CPU data mux
assign cpu_din = pgrom_cs ? pgrom_data_out :
@@ -233,6 +238,7 @@ assign cpu_din = pgrom_cs ? pgrom_data_out :
chram_cs ? chram_data_out :
fgcolram_cs ? fgcolram_data_out :
bgcolram_cs ? bgcolram_data_out :
spritecollisionram_cs ? {8{spritecollisionram_data_out_cpu}} :
in0_cs ? in0_data_out :
joystick_cs ? joystick_data_out :
analog_l_cs ? analog_l_data_out :
@@ -243,111 +249,655 @@ assign cpu_din = pgrom_cs ? pgrom_data_out :
ps2_mouse_cs ? ps2_mouse_data_out :
timestamp_cs ? timestamp_data_out :
timer_cs ? timer_data_out :
tilemapcontrol_cs ? tilemapcontrol_data_out :
music_cs ? music_data_out :
system_menu_cs ? {8{menu_trigger}} :
8'b00000000;
// Rom upload write enables
wire pgrom_wr = dn_wr && dn_index == 8'b0;
wire chrom_wr = dn_wr && dn_index == 8'b1;
// CPU control signals
wire [15:0] cpu_addr;
wire [7:0] cpu_din;
wire [7:0] cpu_dout;
wire cpu_wr_n;
// Ram write enables
wire wkram_wr = !cpu_wr_n && wkram_cs;
wire chram_wr = !cpu_wr_n && chram_cs;
wire fgcolram_wr = !cpu_wr_n && fgcolram_cs;
wire bgcolram_wr = !cpu_wr_n && bgcolram_cs;
// reg cpu_cen_count; // 24 Mhz
wire cpu_cen = 1'b1;
// always @(posedge clk_24)
// begin
// cpu_cen_count <= cpu_cen_count + 1'b1;
// end
`ifndef DISABLE_CPU
// include Z80 CPU
tv80e #(
.Mode(1),
.IOWait(0)
) T80x (
.reset_n (!reset),
.clk (clk_24),
.cen (cpu_cen),
.wait_n (!pause_system),
.int_n (1'b1),
.nmi_n (1'b1),
.busrq_n (1'b1),
.mreq_n (),
.rd_n (),
.wr_n (cpu_wr_n),
.A (cpu_addr),
.di (cpu_din),
.dout (cpu_dout),
.m1_n (),
.iorq_n (),
.rfsh_n (),
.halt_n (),
.busak_n ()
);
`endif
wire [7:0] charmap_r;
wire [7:0] charmap_g;
wire [7:0] charmap_b;
wire charmap_a;
`ifndef DISABLE_CHARMAP
// Casval - character map
wire [11:0] chram_addr;
wire [11:0] chrom_addr;
charmap casval
(
.clk(clk_24),
.reset(reset),
.hcnt(hcnt),
.vcnt(vcnt),
.chrom_data_out(chrom_data_out),
.fgcolram_data_out(fgcolram_data_out),
.bgcolram_data_out(bgcolram_data_out),
.chmap_data_out(chmap_data_out),
.chram_addr(chram_addr),
.chrom_addr(chrom_addr),
.r(charmap_r),
.g(charmap_g),
.b(charmap_b),
.a(charmap_a)
);
`endif
// Zechs - tile map
wire [7:0] tilemap_r;
wire [7:0] tilemap_g;
wire [7:0] tilemap_b;
wire tilemap_a;
`ifndef DISABLE_TILEMAP
localparam TILEMAP_ROM_WIDTH = 17;
localparam TILEMAP_RAM_WIDTH = 10;
wire [TILEMAP_ROM_WIDTH-1:0] tilemaprom_addr;
wire [15:0] tilemaprom_data_out;
wire [TILEMAP_RAM_WIDTH-1:0] tilemapram_addr;
wire [7:0] tilemapram_data_out;
wire tilemapram_ctl_wr;
wire [7:0] tilemapram_ctl_data_in;
tilemap #(
.TILEMAP_RAM_WIDTH(TILEMAP_RAM_WIDTH),
.TILEMAP_ROM_WIDTH(TILEMAP_ROM_WIDTH)
) zechs
(
.clk(clk_24),
.reset(reset),
.pause(pause_system),
.hcnt(hcnt),
.vcnt(vcnt),
.hblank(VGA_HB),
.addr(cpu_addr[1:0]),
.data_in(cpu_dout),
.write(tilemapcontrol_wr),
.tilemaprom_data_out(tilemaprom_data_out),
.tilemapram_data_out(tilemapram_data_out),
.tilemapcontrol_data_out(tilemapcontrol_data_out),
.tilemapram_ctl_wr(tilemapram_ctl_wr),
.tilemapram_ctl_data_in(tilemapram_ctl_data_in),
.tilemapram_addr(tilemapram_addr),
.tilemaprom_addr(tilemaprom_addr),
.tilemap_r(tilemap_r),
.tilemap_g(tilemap_g),
.tilemap_b(tilemap_b),
.tilemap_a(tilemap_a)
);
`endif
// Palettes
wire [7:0] palrom_addr;
wire [15:0] palrom_data_out;
// Comet - sprite engine
wire [7:0] spr_r;
wire [7:0] spr_g;
wire [7:0] spr_b;
wire spr_a;
wire spritecollisionram_data_out_cpu;
`ifndef DISABLE_SPRITES
localparam SPRITE_POSITION_WIDTH = 9;
localparam SPRITE_RAM_WIDTH = 7;
localparam SPRITE_ROM_WIDTH = 14;
localparam SPRITE_COLRAM_WIDTH = 5;
wire [SPRITE_ROM_WIDTH-1:0] sprom_addr;
wire [7:0] spriterom_data_out;
wire [SPRITE_RAM_WIDTH-1:0] spriteram_addr;
wire [7:0] spriteram_data_out;
wire [SPRITE_COLRAM_WIDTH-1:0] spritecollisionram_addr;
wire spritecollisionram_data_out;
wire spritecollisionram_data_in;
wire [SPRITE_POSITION_WIDTH:0] spritelbram_rd_addr;
wire [SPRITE_POSITION_WIDTH:0] spritelbram_wr_addr;
wire spritelbram_wr;
wire [15:0] spritelbram_data_in;
wire [15:0] spritelbram_data_out;
sprite_engine #(
.SPRITE_RAM_WIDTH(SPRITE_RAM_WIDTH),
.SPRITE_ROM_WIDTH(SPRITE_ROM_WIDTH),
.SPRITE_POSITION_WIDTH(SPRITE_POSITION_WIDTH),
.SPRITE_COLRAM_WIDTH(SPRITE_COLRAM_WIDTH)
) comet
(
.clk(clk_24),
.reset(reset),
.pause(pause_system),
.hsync(VGA_HS),
.vsync(VGA_VS),
.vblank(VGA_VB),
.hcnt(hcnt),
.vcnt(vcnt),
.spriterom_data_out(spriterom_data_out),
.spriteram_data_out(spriteram_data_out),
.palrom_data_out(palrom_data_out),
.spritelbram_data_out(spritelbram_data_out),
.spritecollisionram_data_in(spritecollisionram_data_in),
.spritecollisionram_data_out(spritecollisionram_data_out),
.spriteram_addr(spriteram_addr),
.spritecollisionram_addr(spritecollisionram_addr),
.sprom_addr(sprom_addr),
.palrom_addr(palrom_addr),
.spritelbram_rd_addr(spritelbram_rd_addr),
.spritelbram_wr_addr(spritelbram_wr_addr),
.spritelbram_wr(spritelbram_wr),
.spritecollisionram_wr(spritecollisionram_wr),
.spritelbram_data_in(spritelbram_data_in),
`ifdef DEBUG_SPRITE_COLLISION
.spritedebugram_addr_b(spritedebugram_addr_b),
.spritedebugram_wr_b(spritedebugram_wr_b),
.spritedebugram_data_in_b(spritedebugram_data_in_b),
.spritedebugram_data_out_b(spritedebugram_data_out_b),
`endif
.spr_r(spr_r),
.spr_g(spr_g),
.spr_b(spr_b),
.spr_a(spr_a)
);
// Sprite collision debug
`ifdef DEBUG_SPRITE_COLLISION
localparam SD_WAIT = 0;
localparam SD_CLEAR_BEGIN = 1;
localparam SD_CLEAR = 2;
reg [2:0] sd_state;
reg vblank_last;
reg [15:0] vblank_start;
always @(posedge clk_24)
begin
vblank_last <= VGA_VB;
case(sd_state)
SD_WAIT:
begin
spritedebugram_wr_a <= 1'b0;
spritedebugram_addr_a <= (({8'b0,vcnt} + 17'd16) * 17'd320) + {8'b0,hcnt} + 17'd19;
if(!pause_system)
begin
if(VGA_VB && !vblank_last)
begin
sd_state <= SD_CLEAR_BEGIN;
end
end
end
SD_CLEAR_BEGIN:
begin
//$display("SD_CLEAR_BEGIN: %d %d", hcnt, vcnt);
spritedebugram_addr_a <= 17'b0;
spritedebugram_data_in_a <= 8'd0;
spritedebugram_wr_a <= 1'b1;
sd_state <= SD_CLEAR;
end
SD_CLEAR:
begin
if(pause_system)
begin
sd_state <= SD_WAIT;
end
else
begin
if(spritedebugram_addr_a > 17'd79000)
begin
spritedebugram_addr_a <= 17'b0;
sd_state <= SD_WAIT;
//$display("SD_CLEAR_END: %d %d", hcnt, vcnt);
spritedebugram_wr_a <= 1'b0;
end
else
begin
spritedebugram_addr_a <= spritedebugram_addr_a + 17'b1;
end
end
end
endcase
end
`endif
`endif
// Moroboshi (starfield)
wire sf_on1;
wire [7:0] sf_star1;
starfield #(
.H(396),
.V(256),
.LEN(22),
.SEED(22'h1FFFFF),
.MASK(22'b0000111100001111000011),
.TAPS(22'b1100000000000000000000)
) stars1
(
.clk(clk_24),
.rst(reset),
.vblank(VGA_VB),
.en(ce_6),
.pause(pause_system),
.addr(cpu_addr[2:0]),
.data_in(cpu_dout),
.write(starfield1_cs && !cpu_wr_n),
.sf_on(sf_on1),
.sf_star(sf_star1)
);
wire sf_on2;
wire [7:0] sf_star2;
`ifndef DISABLE_STARS_2
starfield #(
.H(396),
.V(256),
.LEN(21),
.SEED(21'h1FFFF0),
.MASK(21'b000011110000111100001),
.TAPS(21'b101010000000000000000)
) stars2
(
.clk(clk_24),
.rst(reset),
.vblank(VGA_VB),
.en(ce_6),
.pause(pause_system),
.addr(cpu_addr[2:0]),
.data_in(cpu_dout),
.write(starfield2_cs && !cpu_wr_n),
.sf_on(sf_on2),
.sf_star(sf_star2)
);
`endif
wire sf_on3;
wire [7:0] sf_star3;
`ifndef DISABLE_STARS_3
starfield #(
.H(396),
.V(256),
.LEN(21),
.SEED(21'h1FFF00),
.MASK(21'b000011110000111100001),
.TAPS(21'b101000000000000000000)
) stars3
(
.clk(clk_24),
.rst(reset),
.vblank(VGA_VB),
.en(ce_6),
.pause(pause_system),
.addr(cpu_addr[2:0]),
.data_in(cpu_dout),
.write(starfield3_cs && !cpu_wr_n),
.sf_on(sf_on3),
.sf_star(sf_star3)
);
`endif
wire sf_on = sf_on1 || sf_on2 || sf_on3;
wire [7:0] sf_star_colour = sf_on1 ? sf_star1[7:0] : sf_on2 ? {1'b0,sf_star2[6:0]} : sf_on3 ? {2'b0,sf_star3[5:0]} : 8'b0;
// RGB mixer
`ifdef DEBUG_SPRITE_COLLISION
// highlight collisions
assign VGA_R = spritedebugram_data_out_a > 8'b0 ? spritedebugram_data_out_a : spr_a ? spr_r : charmap_a ? charmap_r : sf_on ? sf_star_colour : 8'b0;
assign VGA_G = spr_a ? spr_g : charmap_a ? charmap_g : sf_on ? sf_star_colour : 8'b0;
assign VGA_B = spritedebugram_data_out_a > 8'b0 ? spritedebugram_data_out_a : spr_a ? spr_b : charmap_a ? charmap_b : sf_on ? sf_star_colour : 8'b0;
`endif
`ifndef DEBUG_SPRITE_COLLISION
assign VGA_R = spr_a ? spr_r : charmap_a ? charmap_r : tilemap_a ? tilemap_r : sf_on ? sf_star_colour : 8'b0;
assign VGA_G = spr_a ? spr_g : charmap_a ? charmap_g : tilemap_a ? tilemap_g : sf_on ? sf_star_colour : 8'b0;
assign VGA_B = spr_a ? spr_b : charmap_a ? charmap_b : tilemap_a ? tilemap_b : sf_on ? sf_star_colour : 8'b0;
`endif
// Music player
wire [9:0] music_audio_out;
`ifndef DISABLE_MUSIC
localparam MUSIC_ROM_WIDTH = 16;
wire [MUSIC_ROM_WIDTH-1:0] musicrom_addr;
wire [7:0] musicrom_data_out;
music #(.ROM_WIDTH(MUSIC_ROM_WIDTH)) music (
.clk(clk_24),
.ce_2(ce_2),
.reset(reset),
.addr(cpu_addr[1:0]),
.data_in(cpu_dout),
.data_out(music_data_out),
.write(music_cs && ~cpu_wr_n),
.musicrom_addr(musicrom_addr),
.musicrom_data_out(musicrom_data_out),
.audio_out(music_audio_out)
);
`endif
// M5205 sound player
wire signed [11:0] snd_audio_out;
`ifndef DISABLE_SOUND
localparam SOUND_ROM_WIDTH = 14;
wire [SOUND_ROM_WIDTH-1:0] soundrom_addr;
wire [7:0] soundrom_data_out;
sound #(.ROM_WIDTH(SOUND_ROM_WIDTH)) sound (
.clk(clk_24),
.reset(reset),
.addr(cpu_addr[3:0]),
.data_in(cpu_dout),
.write(sound_cs && ~cpu_wr_n),
.soundrom_addr(soundrom_addr),
.soundrom_data_out(soundrom_data_out),
.audio_out(snd_audio_out)
);
`endif
// Mix audio (badly)
wire signed [15:0] music_signed = { 2'b0, music_audio_out, 4'b0 };
wire signed [15:0] audio_signed = { 1'b0, (snd_audio_out + 12'b100000000000), 3'b0 } + 16'b1100000000000000;
assign AUDIO_L = audio_signed + music_signed;
assign AUDIO_R = AUDIO_L;
// MEMORY
// ------
localparam PROGRAM_ROM_WIDTH = 15;
// Program ROM - 0x0000 - 0x3FFF (0x4000 / 16384 bytes)
dpram #(14,8, "rom.hex") pgrom
// Program ROM - 0x0000 - 0x7FFF (0x6000 / 32768 bytes)
dpram #(PROGRAM_ROM_WIDTH,8, "rom.hex") pgrom
(
.clock_a(clk_sys),
.address_a(cpu_addr[13:0]),
.clock_a(clk_24),
.address_a(cpu_addr[PROGRAM_ROM_WIDTH-1:0]),
.wren_a(1'b0),
.data_a(),
.q_a(pgrom_data_out),
.clock_b(clk_sys),
.address_b(dn_addr[13:0]),
.clock_b(clk_24),
.address_b(dn_addr[PROGRAM_ROM_WIDTH-1:0]),
.wren_b(pgrom_wr),
.data_b(dn_data),
.q_b()
);
// Char ROM - 0x4000 - 0x47FF (0x0400 / 2048 bytes)
`ifndef DISABLE_CHARMAP
// Char ROM - 0x9000 - 0x97FF (0x0800 / 2048 bytes)
dpram #(11,8, "font.hex") chrom
(
.clock_a(clk_sys),
.clock_a(clk_24),
.address_a(chrom_addr[10:0]),
.wren_a(1'b0),
.data_a(),
.q_a(chrom_data_out),
.clock_b(clk_sys),
.clock_b(clk_24),
.address_b(dn_addr[10:0]),
.wren_b(chrom_wr),
.data_b(dn_data),
.q_b()
);
// Char RAM - 0x8000 - 0x87FF (0x0800 / 2048 bytes)
// Char index RAM - 0x9800 - 0x9FFF (0x0800 / 2048 bytes)
dpram #(11,8) chram
(
.clock_a(clk_sys),
.clock_a(clk_24),
.address_a(cpu_addr[10:0]),
.wren_a(chram_wr),
.data_a(cpu_dout),
.q_a(chram_data_out),
.clock_b(clk_sys),
.clock_b(clk_24),
.address_b(chram_addr[10:0]),
.wren_b(1'b0),
.data_b(),
.q_b(chmap_data_out)
);
// Char foreground color RAM - 0x8800 - 0x8FFF (0x0800 / 2048 bytes)
// Char foreground color RAM - 0xA000 - 0xA7FF (0x0800 / 2048 bytes)
dpram #(11,8) fgcolram
(
.clock_a(clk_sys),
.clock_a(clk_24),
.address_a(cpu_addr[10:0]),
.wren_a(fgcolram_wr),
.data_a(cpu_dout),
.q_a(),
.clock_b(clk_sys),
.clock_b(clk_24),
.address_b(chram_addr[10:0]),
.wren_b(1'b0),
.data_b(),
.q_b(fgcolram_data_out)
);
// Char background color RAM - 0x9000 - 0x97FF (0x0800 / 2048 bytes)
// Char background color RAM - 0xA800 - 0xAFFF (0x0800 / 2048 bytes)
dpram #(11,8) bgcolram
(
.clock_a(clk_sys),
.clock_a(clk_24),
.address_a(cpu_addr[10:0]),
.wren_a(bgcolram_wr),
.data_a(cpu_dout),
.q_a(),
.clock_b(clk_sys),
.clock_b(clk_24),
.address_b(chram_addr[10:0]),
.wren_b(1'b0),
.data_b(),
.q_b(bgcolram_data_out)
);
`endif
`ifndef DISABLE_TILEMAP
// Tilemap index RAM
dpram #(TILEMAP_RAM_WIDTH,8) tilemapram
(
.clock_a(clk_24),
.address_a(cpu_addr[TILEMAP_RAM_WIDTH-1:0] - {{TILEMAP_RAM_WIDTH-5{1'b0}},5'h10}),
.wren_a(tilemapram_wr),
.data_a(cpu_dout),
.q_a(),
.clock_b(clk_24),
.address_b(tilemapram_addr),
.wren_b(tilemapram_ctl_wr),
.data_b(tilemapram_ctl_data_in),
.q_b(tilemapram_data_out)
);
// Tilemap ROM (0x1000 / 4096 bytes)
dpram_w1r2 #(TILEMAP_ROM_WIDTH,8, "tilemap.hex") tilemaprom
(
.clock_a(clk_24),
.address_a(dn_addr[TILEMAP_ROM_WIDTH-1:0]),
.wren_a(tilemaprom_wr),
.data_a(dn_data),
.clock_b(clk_24),
.address_b(tilemaprom_addr),
.q_b(tilemaprom_data_out)
);
`endif
`ifndef DISABLE_SPRITES
// Sprite RAM - 0xB000 - 0xB07F (0x0080 / 128 bytes)
dpram #(SPRITE_RAM_WIDTH,8) spriteram
(
.clock_a(clk_24),
.address_a(cpu_addr[SPRITE_RAM_WIDTH-1:0]),
.wren_a(spriteram_wr),
.data_a(cpu_dout),
.q_a(),
.clock_b(clk_24),
.address_b(spriteram_addr),
.wren_b(1'b0),
.data_b(),
.q_b(spriteram_data_out)
);
// Sprite Collision RAM - 0xB400 - 0xB47F (0x0080 / 128 bytes)
dpram #(SPRITE_COLRAM_WIDTH,1) spritecollisionram
(
.clock_a(clk_24),
.address_a(cpu_addr[SPRITE_COLRAM_WIDTH-1:0]),
.wren_a(spritecollisionram_cs && ~cpu_wr_n),
.data_a(cpu_dout[0]),
.q_a(spritecollisionram_data_out_cpu),
.clock_b(clk_24),
.address_b(spritecollisionram_addr),
.wren_b(spritecollisionram_wr),
.data_b(spritecollisionram_data_in),
.q_b(spritecollisionram_data_out)
);
`ifdef DEBUG_SPRITE_COLLISION
reg [16:0] spritedebugram_addr_a;
wire [16:0] spritedebugram_addr_b;
reg [7:0] spritedebugram_data_in_a;
wire [7:0] spritedebugram_data_in_b;
wire [7:0] spritedebugram_data_out_a;
wire [7:0] spritedebugram_data_out_b;
reg spritedebugram_wr_a;
wire spritedebugram_wr_b;
// Sprite Debug Frame Buffer
dpram #(17,8) spritedebugram
(
.clock_a(clk_24),
.address_a(spritedebugram_addr_a),
.wren_a(spritedebugram_wr_a),
.data_a(spritedebugram_data_in_a),
.q_a(spritedebugram_data_out_a),
.clock_b(clk_24),
.address_b(spritedebugram_addr_b),
.wren_b(spritedebugram_wr_b),
.data_b(spritedebugram_data_in_b),
.q_b(spritedebugram_data_out_b)
);
`endif
// Sprite linebuffer RAM - 0xB800 - 0xBFFF (0x0800 / 2048 bytes)
dpram #(SPRITE_POSITION_WIDTH+1,16) spritelbram
(
.clock_a(clk_24),
.address_a(spritelbram_wr_addr),
.wren_a(spritelbram_wr),
.data_a(spritelbram_data_in),
.q_a(),
.clock_b(clk_24),
.address_b(spritelbram_rd_addr),
.wren_b(1'b0),
.data_b(),
.q_b(spritelbram_data_out)
);
// Sprite ROM - 0x11000 - 0x11800 (0x1000 / 4096 bytes)
dpram #(SPRITE_ROM_WIDTH,8, "sprite.hex") spriterom
(
.clock_a(clk_24),
.address_a(sprom_addr),
.wren_a(1'b0),
.data_a(),
.q_a(spriterom_data_out),
.clock_b(clk_24),
.address_b(dn_addr[SPRITE_ROM_WIDTH-1:0]),
.wren_b(spriterom_wr),
.data_b(dn_data),
.q_b()
);
`endif
// Work RAM - 0xC000 - 0xFFFF (0x4000 / 16384 bytes)
spram #(14,8) wkram
(
.clock(clk_sys),
.clock(clk_24),
.address(cpu_addr[13:0]),
.wren(wkram_wr),
.data(cpu_dout),
.q(wkram_data_out)
);
// Palette ROM - 0x10000 - 0x10040 (0x0100 / 256 bytes)
dpram_w1r2 #(8,8, "palette.hex") palrom
(
.clock_a(clk_24),
.address_a(dn_addr[7:0]),
.wren_a(palrom_wr),
.data_a(dn_data),
.clock_b(clk_24),
.address_b(palrom_addr),
.q_b(palrom_data_out)
);
`ifndef DISABLE_MUSIC
// Music ROM - 128kB
dpram #(MUSIC_ROM_WIDTH,8, "music.hex") musicrom
(
.clock_a(clk_24),
.address_a(musicrom_addr),
.wren_a(1'b0),
.data_a(),
.q_a(musicrom_data_out),
.clock_b(clk_24),
.address_b(dn_addr[MUSIC_ROM_WIDTH-1:0]),
.wren_b(musicrom_wr),
.data_b(dn_data),
.q_b()
);
`endif
`ifndef DISABLE_SOUND
// Sound ROM - 64kB
dpram #(SOUND_ROM_WIDTH,8, "sound.hex") soundrom
(
.clock_a(clk_24),
.address_a(soundrom_addr),
.wren_a(1'b0),
.data_a(),
.q_a(soundrom_data_out),
.clock_b(clk_24),
.address_b(dn_addr[SOUND_ROM_WIDTH-1:0]),
.wren_b(soundrom_wr),
.data_b(dn_data),
.q_b()
);
`endif
endmodule

401
rtl/tilemap.v Normal file
View File

@@ -0,0 +1,401 @@
`timescale 1ns / 1ps
/*============================================================================
Aznable (custom 8-bit computer system) - Zechs (tilemap)
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 0.1
Date: 2022-01-04
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
module tilemap #(
parameter TILEMAP_ROM_WIDTH = 15,
parameter TILEMAP_RAM_WIDTH = 10,
parameter [9:0] TILEMAP_WIDTH = 10'd352,
parameter [9:0] TILEMAP_HEIGHT = 10'd272,
parameter [9:0] TILEMAP_BORDER = 10'd16,
parameter [4:0] TILEMAP_CELLS_X = 5'd22,
parameter [4:0] TILEMAP_CELLS_Y = 5'd17
)(
input clk,
input reset,
input pause,
input [8:0] hcnt,
input [8:0] vcnt,
input hblank,
input [1:0] addr,
input [7:0] data_in,
input write,
input [15:0] tilemaprom_data_out,
input [7:0] tilemapram_data_out,
output [7:0] tilemapcontrol_data_out,
output reg [TILEMAP_RAM_WIDTH-1:0] tilemapram_addr,
output reg [TILEMAP_ROM_WIDTH-1:0] tilemaprom_addr,
output reg tilemapram_ctl_wr,
output reg [7:0] tilemapram_ctl_data_in,
output reg [7:0] tilemap_r,
output reg [7:0] tilemap_g,
output reg [7:0] tilemap_b,
output reg tilemap_a
);
// Tilemap control registers
// 0 - Tilemap offset X (signed)
// 1 - Tilemap offset Y (signed)
// 2 - Tilemap control trigger
// -> 0 = IDLE
// -> 1 = SCROLL LEFT
// -> 2 = SCROLL RIGHT
// -> 3 = SCROLL UP
// -> 4 = SCROLL DOWN
// -> 5 = CLEAR
reg [7:0] tilemapreg [3:0];
assign tilemapcontrol_data_out = tilemapreg[addr];
// Current tilemap read positions
reg [9:0] tilemap_pos_x;
reg [9:0] tilemap_pos_y;
// Current tilemap scroll offsets
/* verilator lint_off WIDTH */
wire signed [9:0] tilemap_offset_x = $signed(tilemapreg[0]); // Convert scroll control x register to signed
wire signed [9:0] tilemap_offset_y = $signed(tilemapreg[1]); // Convert scroll control y register to signed
/* verilator lint_on WIDTH */
// Tilemap read machine state
reg [1:0] tilemap_read_state;
reg [15:0] tilemap_read_cycles;
// Tilemap control state constants
localparam TM_CTL_IDLE = 0;
localparam TM_CTL_SCROLL = 1;
localparam TM_CTL_CLEAR = 2;
// Tilemap control machine
reg [2:0] tilemap_ctl_state;
reg [4:0] tilemap_ctl_x;
reg [4:0] tilemap_ctl_y;
reg [15:0] tilemap_ctl_cycles;
reg [8:0] tilemap_ctl_hstart;
reg [8:0] tilemap_ctl_vstart;
// Tilemap scroll state constants
localparam TM_SCROLL_START = 0;
localparam TM_SCROLL_WAIT = 1;
localparam TM_SCROLL_GETINDEX = 2;
localparam TM_SCROLL_SETINDEX = 3;
// Tilemap scroll control
reg [4:0] tilemap_scroll_state;
reg [4:0] tilemap_scroll_state_next;
reg [4:0] tilemap_scroll_start_pos;
reg [4:0] tilemap_scroll_target_pos;
reg tilemap_scroll_axis;
reg tilemap_scroll_dir;
// Tilemap clear state constants
localparam TM_CLEAR_PREP = 0;
localparam TM_CLEAR_WRITE = 1;
localparam TM_CLEAR_DONE = 2;
// Tilemap clear control
reg [2:0] tilemap_clear_state;
reg [8:0] hcnt_last;
reg hblank_last;
//`define TM_DEBUG
always @(posedge clk) begin
hblank_last <= hblank;
if(reset)
begin
// Reset tilemap control registers
tilemapreg[0] <= 8'b0;
tilemapreg[1] <= 8'b0;
tilemapreg[2] <= 8'b0;
tilemapreg[3] <= 8'b0;
tilemap_read_state <= 2'b0;
// Start tilemap clear process
tilemap_clear_state <= TM_CLEAR_PREP;
tilemap_ctl_x = 5'd0;
tilemap_ctl_y = 5'd0;
tilemap_ctl_state <= TM_CTL_CLEAR;
end
else
begin
if(write)
begin
// Write tilemap control data from CPU
tilemapreg[addr[1:0]] <= data_in;
// If control trigger is set and control state machine is idle
if(addr[1:0] == 2'd2 && tilemap_ctl_state == TM_CTL_IDLE)
begin
`ifdef TM_DEBUG
$display("TM WRITE: a=%x d=%x", addr[1:0], data_in);
`endif
case(data_in)
8'd1: // SCROLL LEFT
begin
tilemap_scroll_dir <= 1'b0;
tilemap_scroll_axis <= 1'b0;
tilemap_scroll_start_pos = 5'd1;
tilemap_scroll_target_pos = TILEMAP_CELLS_X - 5'd1;
tilemap_scroll_state <= TM_SCROLL_START;
tilemap_ctl_x = tilemap_scroll_start_pos;
tilemap_ctl_y = 5'd0;
tilemap_ctl_state <= TM_CTL_SCROLL;
tilemap_ctl_hstart <= hcnt;
tilemap_ctl_vstart <= vcnt;
end
8'd2: // SCROLL RIGHT
begin
tilemap_scroll_dir <= 1'b1;
tilemap_scroll_axis <= 1'b0;
tilemap_scroll_start_pos = TILEMAP_CELLS_X - 5'd2;
tilemap_scroll_target_pos = 5'd0;
tilemap_scroll_state <= TM_SCROLL_START;
tilemap_ctl_x = tilemap_scroll_start_pos;
tilemap_ctl_y = 5'd0;
tilemap_ctl_state <= TM_CTL_SCROLL;
tilemap_ctl_hstart <= hcnt;
tilemap_ctl_vstart <= vcnt;
end
8'd3: // SCROLL UP
begin
tilemap_scroll_dir <= 1'b0;
tilemap_scroll_axis <= 1'b1;
tilemap_scroll_start_pos = 5'd1;
tilemap_scroll_target_pos = TILEMAP_CELLS_Y - 5'd1;
tilemap_scroll_state <= TM_SCROLL_START;
tilemap_ctl_x = 5'd0;
tilemap_ctl_y = tilemap_scroll_start_pos;
tilemap_ctl_state <= TM_CTL_SCROLL;
tilemap_ctl_hstart <= hcnt;
tilemap_ctl_vstart <= vcnt;
end
8'd4: // SCROLL DOWN
begin
tilemap_scroll_dir <= 1'b1;
tilemap_scroll_axis <= 1'b1;
tilemap_scroll_start_pos = TILEMAP_CELLS_Y - 5'd2;
tilemap_scroll_target_pos = 5'd0;
tilemap_scroll_state <= TM_SCROLL_START;
tilemap_ctl_x = 5'd0;
tilemap_ctl_y = tilemap_scroll_start_pos;
tilemap_ctl_state <= TM_CTL_SCROLL;
tilemap_ctl_hstart <= hcnt;
tilemap_ctl_vstart <= vcnt;
end
8'd5: // CLEAR
begin
tilemap_clear_state <= TM_CLEAR_PREP;
tilemap_ctl_x = 5'd0;
tilemap_ctl_y = 5'd0;
tilemap_ctl_state <= TM_CTL_CLEAR;
tilemap_ctl_hstart <= hcnt;
tilemap_ctl_vstart <= vcnt;
end
default:
begin
end
endcase
end
end
case(tilemap_ctl_state)
TM_CTL_IDLE:
begin
tilemap_ctl_cycles <= 16'b0;
hcnt_last <= hcnt;
if(hcnt == 9'd395 && hcnt_last == 9'd394)
begin
// When end of HBLANK is reached, reset tilemap read state
tilemap_read_state <= 2'b0;
tilemap_read_cycles <= 16'b0;
end
else
begin
tilemap_read_cycles <= tilemap_read_cycles + 1'b1;
tilemap_read_state <= tilemap_read_state + 2'b1;
case(tilemap_read_state)
2'b00:
begin
// - Calculate next pixel lookup address
tilemap_pos_x = $signed($signed((hcnt == 9'd395 ? 9'd0 : hcnt + 9'd1)) + TILEMAP_BORDER) + $signed(tilemap_offset_x);
tilemap_pos_y = $signed($signed((vcnt == 9'd255 ? 9'd0 : vcnt)) + TILEMAP_BORDER) + $signed(tilemap_offset_y);
// - Set tilemapram lookup address
tilemapram_addr <= { tilemap_pos_y[8:4], tilemap_pos_x[8:4] };
// Set colour output for previous ROM lookup
tilemap_r = {tilemaprom_data_out[4:0],tilemaprom_data_out[4:2]};
tilemap_g = {tilemaprom_data_out[9:5],tilemaprom_data_out[9:7]};
tilemap_b = {tilemaprom_data_out[14:10],tilemaprom_data_out[14:12]};
tilemap_a = tilemaprom_data_out[15];
end
2'b10:
begin
// Set ROM lookup address based on index RAM and cell offset
tilemaprom_addr <= { tilemapram_data_out[TILEMAP_ROM_WIDTH-10:0], tilemap_pos_y[3:0], tilemap_pos_x[3:0], 1'b0 };
end
default: begin end
endcase
end
end
TM_CTL_SCROLL:
begin
tilemap_ctl_cycles <= tilemap_ctl_cycles + 16'b1;
case(tilemap_scroll_state)
TM_SCROLL_WAIT:
begin
tilemap_scroll_state <= tilemap_scroll_state_next;
end
TM_SCROLL_START:
begin
`ifdef TM_DEBUG
$display("TM_SCROLL_START: axis=%b dir=%b", tilemap_scroll_axis, tilemap_scroll_dir);
`endif
tilemapram_addr <= { tilemap_ctl_y, tilemap_ctl_x };
tilemap_scroll_state <= TM_SCROLL_WAIT;
tilemap_scroll_state_next <= TM_SCROLL_GETINDEX;
end
TM_SCROLL_GETINDEX:
begin
`ifdef TM_DEBUG
$display("TM_SCROLL_GETINDEX: %d/%d - %x %d", tilemap_ctl_x, tilemap_ctl_y, tilemapram_addr, tilemapram_data_out);
`endif
tilemapram_ctl_data_in <= tilemapram_data_out;
if(tilemap_scroll_axis)
begin
tilemapram_addr <= { tilemap_scroll_dir ? tilemap_ctl_y + 5'd1 : tilemap_ctl_y - 5'd1, tilemap_ctl_x };
end
else
begin
tilemapram_addr <= { tilemap_ctl_y, tilemap_scroll_dir ? tilemap_ctl_x + 5'd1 : tilemap_ctl_x - 5'd1 };
end
tilemapram_ctl_wr <= 1'b1;
tilemap_scroll_state <= TM_SCROLL_WAIT;
tilemap_scroll_state_next <= TM_SCROLL_SETINDEX;
end
TM_SCROLL_SETINDEX:
begin
`ifdef TM_DEBUG
$display("TM_SCROLL_SETINDEX: %d/%d - %x %d", tilemap_ctl_x, tilemap_ctl_y, tilemapram_addr, tilemapram_ctl_data_in);
`endif
tilemapram_ctl_wr <= 1'b0;
if((tilemap_scroll_axis ? tilemap_ctl_y : tilemap_ctl_x) == tilemap_scroll_target_pos)
begin
if(!tilemap_scroll_axis ? (tilemap_ctl_y == TILEMAP_CELLS_Y - 5'd1) : (tilemap_ctl_x == TILEMAP_CELLS_X - 5'd1))
begin
// Scroll process completed
tilemap_ctl_state <= TM_CTL_IDLE;
`ifdef TM_DEBUG
$display("TM_SCROLL_COMPLETE - in %d | vstart: %d vend: %d | hstart: %d hend: %d", tilemap_ctl_cycles, tilemap_ctl_vstart, vcnt, tilemap_ctl_hstart, hcnt);
`endif
// Clear trigger control register
tilemapreg[2] <= 8'b0;
end
else
begin
if(tilemap_scroll_axis)
begin
tilemap_ctl_y = tilemap_scroll_start_pos;
tilemap_ctl_x = tilemap_ctl_x + 5'd1;
end
else
begin
tilemap_ctl_x = tilemap_scroll_start_pos;
tilemap_ctl_y = tilemap_ctl_y + 5'd1;
end
tilemapram_addr <= { tilemap_ctl_y, tilemap_ctl_x };
tilemap_scroll_state <= TM_SCROLL_WAIT;
tilemap_scroll_state_next <= TM_SCROLL_GETINDEX;
end
end
else
begin
if(tilemap_scroll_axis)
begin
tilemap_ctl_y = tilemap_scroll_dir ? tilemap_ctl_y - 5'd1 : tilemap_ctl_y + 5'd1;
end
else
begin
tilemap_ctl_x = tilemap_scroll_dir ? tilemap_ctl_x - 5'd1 : tilemap_ctl_x + 5'd1;
end
tilemapram_addr <= { tilemap_ctl_y, tilemap_ctl_x };
tilemap_scroll_state <= TM_SCROLL_WAIT;
tilemap_scroll_state_next <= TM_SCROLL_GETINDEX;
end
end
endcase
end
TM_CTL_CLEAR:
begin
case(tilemap_clear_state)
TM_CLEAR_PREP:
begin
`ifdef TM_DEBUG
$display("TM_CLEAR_PREP tilemap_ctl_x=%d tilemap_ctl_y=%d", tilemap_ctl_x, tilemap_ctl_y);
`endif
tilemapram_addr <= { tilemap_ctl_y, tilemap_ctl_x };
tilemapram_ctl_wr <= 1'b1;
tilemapram_ctl_data_in <= 8'b0;
tilemap_clear_state <= TM_CLEAR_WRITE;
end
TM_CLEAR_WRITE:
begin
`ifdef TM_DEBUG
$display("TM_CLEAR_WRITE tilemap_ctl_x=%d tilemap_ctl_y=%d", tilemap_ctl_x, tilemap_ctl_y);
`endif
tilemap_clear_state <= TM_CLEAR_PREP;
tilemap_ctl_x = tilemap_ctl_x + 5'd1;
if(tilemap_ctl_x == TILEMAP_CELLS_X)
begin
tilemap_ctl_x = 5'd0;
if(tilemap_ctl_y == TILEMAP_CELLS_Y)
begin
tilemap_clear_state <= TM_CLEAR_DONE;
end
else
begin
tilemap_ctl_y = tilemap_ctl_y + 5'd1;
end
end
end
TM_CLEAR_DONE:
begin
`ifdef TM_DEBUG
$display("TM_CLEAR_DONE tilemap_ctl_x=%d tilemap_ctl_y=%d", tilemap_ctl_x, tilemap_ctl_y);
`endif
tilemapram_ctl_wr <= 1'b0;
tilemap_ctl_state <= TM_CTL_IDLE;
// Clear trigger control register
tilemapreg[2] <= 8'b0;
end
endcase
end
endcase
end
end
endmodule

View File

@@ -3,4 +3,5 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80_a
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80_mcode.v"]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80_reg.v"]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80n.v"]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80s.v"]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80s.v"]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "tv80e.v"]

161
rtl/tv80/tv80e.v Normal file
View File

@@ -0,0 +1,161 @@
`timescale 1ns / 1ps
//
// TV80 8-Bit Microprocessor Core
// Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org)
//
// Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
module tv80e (/*AUTOARG*/
// Outputs
m1_n, mreq_n, iorq_n, rd_n, wr_n, rfsh_n, halt_n, busak_n, A, dout,
// Inputs
reset_n, clk, cen, wait_n, int_n, nmi_n, busrq_n, di
);
parameter Mode = 0; // 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
parameter T2Write = 1; // 0 => wr_n active in T3, /=0 => wr_n active in T2
parameter IOWait = 1; // 0 => Single cycle I/O, 1 => Std I/O cycle
input reset_n;
input clk;
input cen;
input wait_n;
input int_n;
input nmi_n;
input busrq_n;
output m1_n;
output mreq_n;
output iorq_n;
output rd_n;
output wr_n;
output rfsh_n;
output halt_n;
output busak_n;
output [15:0] A;
input [7:0] di;
output [7:0] dout;
reg mreq_n;
reg iorq_n;
reg rd_n;
reg wr_n;
wire intcycle_n;
wire no_read;
wire write;
wire iorq;
reg [7:0] di_reg;
wire [6:0] mcycle;
wire [6:0] tstate;
tv80_core #(Mode, IOWait) i_tv80_core
(
.cen (cen),
.m1_n (m1_n),
.iorq (iorq),
.no_read (no_read),
.write (write),
.rfsh_n (rfsh_n),
.halt_n (halt_n),
.wait_n (wait_n),
.int_n (int_n),
.nmi_n (nmi_n),
.reset_n (reset_n),
.busrq_n (busrq_n),
.busak_n (busak_n),
.clk (clk),
.IntE (),
.stop (),
.A (A),
.dinst (di),
.di (di_reg),
.dout (dout),
.mc (mcycle),
.ts (tstate),
.intcycle_n (intcycle_n)
);
always @(posedge clk or negedge reset_n)
begin
if (!reset_n)
begin
rd_n <= #1 1'b1;
wr_n <= #1 1'b1;
iorq_n <= #1 1'b1;
mreq_n <= #1 1'b1;
di_reg <= #1 0;
end
else if(cen)
begin
rd_n <= #1 1'b1;
wr_n <= #1 1'b1;
iorq_n <= #1 1'b1;
mreq_n <= #1 1'b1;
if (mcycle[0])
begin
if (tstate[1] || (tstate[2] && wait_n == 1'b0))
begin
rd_n <= #1 ~ intcycle_n;
mreq_n <= #1 ~ intcycle_n;
iorq_n <= #1 intcycle_n;
end
`ifdef TV80_REFRESH
if (tstate[3])
mreq_n <= #1 1'b0;
`endif
end // if (mcycle[0])
else
begin
if ((tstate[1] || (tstate[2] && wait_n == 1'b0)) && no_read == 1'b0 && write == 1'b0)
begin
rd_n <= #1 1'b0;
iorq_n <= #1 ~ iorq;
mreq_n <= #1 iorq;
end
if (T2Write == 0)
begin
if (tstate[2] && write == 1'b1)
begin
wr_n <= #1 1'b0;
iorq_n <= #1 ~ iorq;
mreq_n <= #1 iorq;
end
end
else
begin
if ((tstate[1] || (tstate[2] && wait_n == 1'b0)) && write == 1'b1)
begin
wr_n <= #1 1'b0;
iorq_n <= #1 ~ iorq;
mreq_n <= #1 iorq;
end
end // else: !if(T2write == 0)
end // else: !if(mcycle[0])
if (tstate[2] && wait_n == 1'b1)
di_reg <= #1 di;
end // else: !if(!reset_n)
end // always @ (posedge clk or negedge reset_n)
endmodule // t80s