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

3
.gitattributes vendored
View File

@@ -1,4 +1,5 @@
# Auto detect text files and perform LF normalization
* text=auto
# Convert linux scripts to LF permanently
*.sh crlf=input
*.sh text eol=lf
*.define text eol=lf

26
.gitignore vendored
View File

@@ -42,14 +42,24 @@ verilator/obj_dir/*
verilator/x64/*
verilator/roms/*
verilator/*.hex
src/os.asm
src/os.bin
src/os.lk
src/os.lst
src/os.map
src/os.noi
src/os.sym
rtl/*.hex
.vscode/settings.json
verilator/imgui.ini
verilator/imgui.ini
docs/*
**/.vs/*
**/bin/*
**/obj/*
docs/vids/*
verilator/audio.wav
*.log
**/build/*.sym
**/build/*.rel
**/build/*.lst
**/build/*.map
**/build/*.noi
**/build/*.lk
**/build/*.asm
**/sound/res/*
**/sprites/res/*
**/tilemap/res/*
**/music/res/*

1
CURRENT_PROJECT Normal file
View File

@@ -0,0 +1 @@
inputtest

View File

@@ -50,7 +50,7 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name ALM_REGISTER_PACKING_EFFORT MEDIUM
set_global_assignment -name SEED 1
#set_global_assignment -name VERILOG_MACRO "MISTER_FB=1"
set_global_assignment -name VERILOG_MACRO "MISTER_FB=1"
#enable it only if 8bit indexed mode is used in core
#set_global_assignment -name VERILOG_MACRO "MISTER_FB_PALETTE=1"
@@ -60,6 +60,18 @@ set_global_assignment -name SEED 1
#do not enable DEBUG_NOHDMI in release!
#set_global_assignment -name VERILOG_MACRO "MISTER_DEBUG_NOHDMI=1"
# Aznable specific defines
# ------------------------
#set_global_assignment -name VERILOG_MACRO "DISABLE_CPU=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_CHARMAP=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_SPRITES=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_TILEMAP=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_MUSIC=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_SOUND=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_STARS_2=1"
#set_global_assignment -name VERILOG_MACRO "DISABLE_STARS_3=1"
#set_global_assignment -name VERILOG_MACRO "DEBUG_SPRITE_COLLISION=1"
source sys/sys.tcl
source sys/sys_analog.tcl
source files.qip

View File

@@ -2,8 +2,8 @@
Input Test - emu module
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-12
Version: 1.1
Date: 2021-12-22
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
@@ -29,7 +29,7 @@ module emu
input RESET,
//Must be passed to hps_io module
inout [45:0] HPS_BUS,
inout [47:0] HPS_BUS,
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
@@ -180,14 +180,14 @@ assign USER_OUT = '1;
assign {UART_RTS, UART_TXD, UART_DTR} = 0;
assign {SD_SCK, SD_MOSI, SD_CS} = 'Z;
assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = 'Z;
assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = '0;
assign FB_FORCE_BLANK = 0;
assign VGA_F1 = 0;
assign VGA_SCALER = 0;
assign HDMI_FREEZE = 0;
assign AUDIO_S = 0;
assign AUDIO_L = 0;
assign AUDIO_R = 0;
assign AUDIO_S = 1;
assign AUDIO_MIX = 0;
assign LED_DISK = 0;
assign LED_POWER = 0;
assign BUTTONS = 0;
@@ -203,10 +203,25 @@ assign VIDEO_ARY = (!ar) ? 12'd3 : 12'd0;
localparam CONF_STR = {
"InputTest;;",
"-;",
"O35,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;",
"OGJ,Analog Video H-Pos,0,-1,-2,-3,-4,-5,-6,-7,8,7,6,5,4,3,2,1;",
"OKN,Analog Video V-Pos,0,-1,-2,-3,-4,-5,-6,-7,8,7,6,5,4,3,2,1;",
"O89,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
"-;",
"F0,BIN,Load BIOS;",
"O6,Rotate video,Off,On;",
"O7,Flip video,Off,On;",
"-;",
"RA,Open menu;",
"-;",
"P1,Pause options;",
"P1OP,Pause when OSD is open,On,Off;",
"P1OQ,Dim video after 10s,On,Off;",
"-;",
"F0,BIN,Load BIOS;",
"F3,BIN,Load Sprite ROM;",
"F4,YM,Load Music (YM5/6);",
"-;",
"R0,Reset;",
"J,A,B,X,Y,L,R,Select,Start;",
"V,v",`BUILD_DATE
};
@@ -287,6 +302,7 @@ hps_io #(.CONF_STR(CONF_STR)) hps_io
.joystick_l_analog_3(joystick_l_analog_3),
.joystick_l_analog_4(joystick_l_analog_4),
.joystick_l_analog_5(joystick_l_analog_5),
.joystick_r_analog_0(joystick_r_analog_0),
.joystick_r_analog_1(joystick_r_analog_1),
.joystick_r_analog_2(joystick_r_analog_2),
@@ -327,20 +343,27 @@ pll pll
/////////////////// CLOCK DIVIDER ////////////////////
wire ce_pix;
wire ce_2;
jtframe_cen24 divider
(
.clk(clk_sys),
.cen6(ce_pix)
.cen6(ce_pix),
.cen2(ce_2)
);
/////////////////// VIDEO ////////////////////
wire hblank, vblank, hs, vs;
wire hblank, vblank, hs, vs, hs_original, vs_original;
wire [7:0] r, g, b;
wire rotate_ccw = status[7];
wire no_rotate = ~status[6];
wire flip = status[7];
screen_rotate screen_rotate (.*);
arcade_video #(320,24) arcade_video
(
.*,
.clk_video(clk_sys),
.RGB_in({r,g,b}),
.RGB_in(rgb_out),
.HBlank(hblank),
.VBlank(vblank),
.HSync(hs),
@@ -348,34 +371,67 @@ arcade_video #(320,24) arcade_video
.fx(status[5:3])
);
// H/V offset
wire [3:0] voffset = status[23:20];
wire [3:0] hoffset = status[19:16];
jtframe_resync jtframe_resync
(
.clk(clk_sys),
.pxl_cen(ce_pix),
.hs_in(hs_original),
.vs_in(vs_original),
.LVBL(~vblank),
.LHBL(~hblank),
.hoffset(hoffset),
.voffset(voffset),
.hs_out(hs),
.vs_out(vs)
);
/////////////////// PAUSE SYSTEM ///////////////////
wire m_pause = joystick_0[8];
wire pause_cpu;
wire [23:0] rgb_out;
pause #(8,8,8,24) pause (
.*,
.user_button(m_pause),
.pause_request(),
.options(~status[26:25])
);
/////////////////// MAIN CORE ////////////////////
wire rom_download = ioctl_download && (ioctl_index < 8'd2);
wire reset = (RESET | status[0] | buttons[1] | rom_download);
assign LED_USER = rom_download;
system system(
.clk_sys(clk_sys),
.ce_pix(ce_pix),
.clk_24(clk_sys),
.ce_6(ce_pix),
.ce_2(ce_2),
.reset(reset),
.VGA_HS(hs),
.VGA_VS(vs),
.pause(pause_cpu),
.menu(status[10] || buttons[1]),
.VGA_HS(hs_original),
.VGA_VS(vs_original),
.VGA_R(r),
.VGA_G(g),
.VGA_B(b),
.VGA_HB(hblank),
.VGA_VB(vblank),
.dn_addr(ioctl_addr[13:0]),
.dn_addr(ioctl_addr[16:0]),
.dn_data(ioctl_dout),
.dn_wr(ioctl_wr),
.dn_index(ioctl_index),
.joystick({joystick_5,joystick_4,joystick_3,joystick_2,joystick_1,joystick_0}),
.analog_l({joystick_l_analog_5,joystick_l_analog_4,joystick_l_analog_3,joystick_l_analog_2,joystick_l_analog_1,joystick_l_analog_0}),
.analog_r({joystick_r_analog_5,joystick_r_analog_4,joystick_r_analog_3,joystick_r_analog_2,joystick_r_analog_1,joystick_r_analog_0}),
.paddle({paddle_5,paddle_4,paddle_3,paddle_2,paddle_1,paddle_0}),
.paddle({paddle_5,paddle_4,paddle_3,paddle_2,paddle_1,paddle_0}),
.spinner({7'b0,spinner_5,7'b0,spinner_4,7'b0,spinner_3,7'b0,spinner_2,7'b0,spinner_1,7'b0,spinner_0}),
.ps2_key(ps2_key),
.ps2_mouse({ps2_mouse_ext,7'b0,ps2_mouse}),
.timestamp(timestamp)
.timestamp(timestamp),
.AUDIO_L(AUDIO_L),
.AUDIO_R(AUDIO_R)
);
endmodule

BIN
MiSTer.pf

Binary file not shown.

View File

@@ -73,7 +73,7 @@ Start|End|Length|Name
/src contains a C program compiled to Z80 assembly using sdcc.
All required ROMs (compiled program and font) are built into this core.
All required ROMs (compiled program, font, images, sounds and music) are built into this core.
Selecting Load BIOS in the core allows hot loading of binary OS ROM files for easier development.

View File

@@ -1,17 +1,34 @@
# Make C code
cd src
make clean
# Define current project and other variables
PROJECT=$(cat CURRENT_PROJECT)
CURRENTDIR=$(pwd)
# Compile C code
cd src/$PROJECT
#make clean
make all
cd ..
cd $CURRENTDIR
# Verilate HDL
# Compile verilator code
cd verilator
./verilate.sh
cd ..
./verilate.sh $PROJECT
cd $CURRENTDIR
# Hexify roms
od -An -t x1 -v src/os.bin > verilator/rom.hex
od -An -t x1 -v src/os.bin > rtl/rom.hex
od -An -t x1 -v PETSCII.pf > verilator/font.hex
od -An -t x1 -v PETSCII.pf > rtl/font.hex
# Build target locations
TARGETS=( verilator rtl )
# Hexify rom and font and copy to build targets
for TARGET in "${TARGETS[@]}"; do
od -An -t x1 -v src/$PROJECT/bin/rom.bin > $TARGET/rom.hex
od -An -t x1 -v font.pf > $TARGET/font.hex
done
# Hexify resource binarys and copy to build targets
RESOURCES=( sprite palette music sound tilemap )
for RESOURCE in "${RESOURCES[@]}"; do
if [ -r "resources/$PROJECT/$RESOURCE.bin" ]; then
echo "Updating resources/$PROJECT/$RESOURCE.bin"
for TARGET in "${TARGETS[@]}"; do
od -An -t x1 -v resources/$PROJECT/$RESOURCE.bin > $TARGET/$RESOURCE.hex
done
fi
done

4
clean.sh Normal file
View File

@@ -0,0 +1,4 @@
# Make C code
cd src
make clean
cd ..

View File

@@ -3,7 +3,20 @@ set_global_assignment -name QIP_FILE rtl/tv80/TV80.qip
set_global_assignment -name CDF_FILE jtag.cdf
set_global_assignment -name QIP_FILE sys/sys.qip
set_global_assignment -name VERILOG_FILE rtl/JTFRAME/jtframe_vtimer.v
set_global_assignment -name VERILOG_FILE rtl/JTFRAME/jtframe_resync.v
set_global_assignment -name VERILOG_FILE rtl/JTFRAME/jtframe_cen24.v
set_global_assignment -name QIP_FILE rtl/jt49/jt49.qip
set_global_assignment -name QIP_FILE rtl/jt5205/jt5205.qip
set_global_assignment -name VERILOG_FILE rtl/charmap.v
set_global_assignment -name VERILOG_FILE rtl/sprite_engine.v
set_global_assignment -name VERILOG_FILE rtl/tilemap.v
set_global_assignment -name VERILOG_FILE rtl/lfsr.v
set_global_assignment -name VERILOG_FILE rtl/starfield.v
set_global_assignment -name VERILOG_FILE rtl/music.v
set_global_assignment -name VERILOG_FILE rtl/sound.v
set_global_assignment -name VERILOG_FILE rtl/generic_timer.v
set_global_assignment -name VERILOG_FILE rtl/system.v
set_global_assignment -name VERILOG_FILE rtl/dpram.v
set_global_assignment -name VERILOG_FILE rtl/spram.v
set_global_assignment -name VERILOG_FILE rtl/dpram_w1r2.v
set_global_assignment -name VERILOG_FILE rtl/spram.v
set_global_assignment -name VERILOG_FILE rtl/pause.v

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

BIN
gfx/palette.bin Normal file

Binary file not shown.

BIN
gfx/sprite.bin Normal file

Binary file not shown.

View File

@@ -1,2 +0,0 @@
sudo apt-get install sdcc srecord

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,2 @@
main_theme.ym#maintheme
game_over.ym#gameover

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,4 @@
explosion#player_explode
pickup#pickup_collect
alarm#alarm
newtype#newtype

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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

View File

@@ -1,25 +0,0 @@
SDCC=sdcc
CPU=z80
CODE=os
OBJ=os.rel
DATALOC=0xC000
all: $(CODE).bin
%.rel: %.c
$(SDCC) -m$(CPU) -c --data-loc $(DATALOC) $<
%.ihx: $(OBJ)
$(SDCC) -m$(CPU) --data-loc $(DATALOC) $(OBJ)
%.hex: %.ihx
mv $< $@
%.bin: %.hex
srec_cat $< -intel -o $@ -binary
disasm: $(CODE).bin
z80dasm -a -t -g 0 $<
clean:
rm -rf *~ *.asm *.ihx *.lk *.lst *.map *.noi *.rel *.sym *.hex *.bin

10
src/inputtest/.define Normal file
View File

@@ -0,0 +1,10 @@
//DISABLE_CPU
//DISABLE_SPRITES
//DISABLE_TILEMAP
//DISABLE_CHARMAP
//DEBUG_SPRITE_COLLISION
//DISABLE_STARS_1
//DISABLE_STARS_2
//DISABLE_STARS_3
//DISABLE_MUSIC
//DISABLE_SOUND

2
src/inputtest/Makefile Normal file
View File

@@ -0,0 +1,2 @@
DEFINES=-DPROJECT_NAME=inputtest
include ../shared/Makefile

132
src/inputtest/credits.c Normal file
View File

@@ -0,0 +1,132 @@
/*============================================================================
Aznable OS - Credits
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2022-01-05
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/>.
===========================================================================*/
#include "../shared/sys.h"
#include "../shared/ui.h"
#include "../shared/ps2.h"
#include "../shared/sprite.h"
#include "../shared/music.h"
#include "../shared/tilemap.h"
#include "../shared/starfield.h"
#include "credits.h"
#include "inputtester_sys.h"
const char *credits_text = "CODE AND GFX_-_JIMMYSTONES___MUSIC_-_DARRIN CARDANI___TESTING_-_PORKCHOP EXPRESS_SORGELIG_M WALRUS___EXTRA THANKS_-_ALANSWX_SORGELIG___";
unsigned char credits_pos = 0;
unsigned short credits_entry_pos = (16 * 32);
void app_credits()
{
clear_chars(0);
clear_sprites();
clear_tilemap();
stop_music();
enable_starfield();
set_starfield_speed_x(0);
set_starfield_speed_y(-0.1f);
tilemap_offset_x = 0;
tilemap_offset_y = 0;
char credits_line[22];
credits_pos = 0;
while (1)
{
vblank = CHECK_BIT(input0, INPUT_VBLANK);
if (VBLANK_RISING)
{
if (tilemap_offset_y >= 16)
{
tilemap_offset_y -= 16;
update_tilemap_offset();
scroll_tilemap_up();
unsigned char d;
unsigned char c;
unsigned char credits_line_len = 0;
for (d = 0; d < 22; d++)
{
c = credits_text[credits_pos];
credits_pos++;
if (c == '_' || c == 0)
{
break;
}
else
{
credits_line[d] = c;
credits_line_len++;
}
if (credits_pos >= strlen(credits_text) - 1)
{
credits_pos = 0;
break;
}
}
signed char credits_line_pre = (22 - credits_line_len) / 2;
for (d = 0; d < 22; d++)
{
c = 0;
signed char i = d - credits_line_pre;
if (i >= 0 && i < credits_line_len)
{
c = (credits_line[i] != '-') ? (credits_line[i] - 45) : 1;
}
tilemapram[credits_entry_pos + d] = c;
}
}
else
{
update_tilemap_offset();
}
}
if (VBLANK_FALLING)
{
handle_ps2();
basic_input();
if (input_a || input_b || input_select || input_start)
{
break;
}
signed dir = 1;
tilemap_offset_y += 2;
if (input_up)
{
tilemap_offset_y += 4;
}
}
vblank_last = vblank;
}
clear_chars(0);
clear_sprites();
clear_tilemap();
stop_music();
disable_starfield();
state = defaultstate;
}

22
src/inputtest/credits.h Normal file
View File

@@ -0,0 +1,22 @@
/*============================================================================
Aznable OS - Credits
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2022-01-05
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/>.
===========================================================================*/
extern void app_credits();

View File

@@ -19,12 +19,11 @@
with this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
#pragma once
#include "../shared/sys.h"
#include "../shared/ui.h"
#include "fader.h"
#include "inputtester_sys.h"
#include "sys.c"
// Fade in/out constants
#define fadefreq 4
// Fade in/out variables
unsigned char fade = 0;
unsigned char fadetimer = 0;

42
src/inputtest/fader.h Normal file
View File

@@ -0,0 +1,42 @@
/*============================================================================
Input Test - Fader
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-12
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/>.
===========================================================================*/
#ifndef FADER_H
#define FADER_H
// Fade in/out constants
#define fadefreq 4
// Fade in/out variables
extern unsigned char fade;
extern unsigned char fadetimer;
// Initialise fadeout state
extern void start_fadeout();
// Initialise fadein state
extern void start_fadein();
// Fade out state
extern void fadeout();
// Fade in state
extern void fadein();
#endif

View File

@@ -1,29 +1,35 @@
/*============================================================================
Input Test - Input test state handlers
Input Test - Input test state handlers
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-13
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-13
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 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.
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/>.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
#pragma once
#include "sys.c"
#include "fader.c"
#include "menu.c"
#include "../shared/sys.h"
#include "../shared/ui.h"
#include "../shared/ps2.h"
#include "../shared/sprite.h"
#include "fader.h"
#include "menu.h"
#include "sprite_images.h"
#include "inputtester_app.h"
#include "inputtester_sys.h"
#include "inputtester_ui.h"
#include "inputtester_pings.h"
// Input tester variables
unsigned char joystick_last[12];
@@ -42,9 +48,11 @@ unsigned char mse_button2_last = 255;
signed char mse_x_last = 1;
signed char mse_y_last = 1;
signed char mse_w_last = 1;
unsigned char mse_x_acc;
unsigned char mse_y_acc;
unsigned char mse_w_acc;
signed short mse_x_acc;
signed short mse_y_acc;
signed short mse_w_acc;
#define MOUSE_POINTER_SPRITE 9
// Mode switcher variables
char modeswitchtimer_select = 0;
@@ -261,6 +269,13 @@ void start_inputtester_advanced()
// Draw page
page_inputtester_advanced();
// Setup mouse pointer
enable_sprite(MOUSE_POINTER_SPRITE, sprite_palette_pointer, sprite_size_pointer, 0);
spr_index[MOUSE_POINTER_SPRITE] = sprite_index_pointer_first;
spr_on[MOUSE_POINTER_SPRITE] = 0;
mse_x_acc = 336;
mse_y_acc = 256;
// Reset last states for inputs
reset_inputstates();
}
@@ -316,12 +331,22 @@ void handle_codes()
{
pushhistory(5);
}
if (!input_b && input_b_last)
{
pushhistory(6);
}
// Check for SNEK code
if (history[0] == 1 && history[1] == 1 && history[2] == 2 && history[3] == 2 && history[4] == 3 && history[5] == 4 && history[6] == 5)
{
nextstate = STATE_START_ATTRACT;
pushhistory(0);
start_fadeout();
state = STATE_START_ATTRACT;
return;
}
// Check for Zorblax code
if (history[0] == 1 && history[1] == 1 && history[2] == 2 && history[3] == 2 && history[4] == 3 && history[5] == 4 && history[6] == 6)
{
pushhistory(0);
state = STATE_START_ZORBLAXX;
return;
}
}
@@ -329,6 +354,15 @@ void handle_codes()
// Menu opening handler
bool modeswitcher()
{
// Check system menu trigger
if (system_menu)
{
system_menu = 0;
modeswitchtimer_select = 0;
start_menu();
return 1;
}
// Open menu if select is held
if (input_select)
{
@@ -351,7 +385,7 @@ bool modeswitcher()
void inputtester_digital()
{
// // Handle PS/2 inputs whenever possible to improve latency
// Handle PS/2 inputs whenever possible to improve latency
handle_ps2();
// Handle secret code detection (joypad 1 directions)
@@ -493,14 +527,16 @@ void inputtester_advanced()
// Handle test mode switch
if (modeswitcher())
{
clear_sprites();
update_sprites();
return;
}
// Draw joystick inputs (only update each byte if value has changed)
for (char inputindex = 0; inputindex < 6; inputindex++)
{
char m = 0b00000001;
char x = 6;
char mask = 0b00000001;
char cx = 6;
char y = 6 + inputindex;
char inputoffset = (inputindex * 4);
char lastoffset = (inputindex * 2);
@@ -511,18 +547,18 @@ void inputtester_advanced()
char joy = joystick[index];
if (joy != joystick_last[lastindex])
{
m = 0b00000001;
mask = 0b00000001;
char bytes = (b == 0 ? 8 : 4);
for (char i = 0; i < bytes; i++)
{
x++;
write_char((joy & m) ? asc_1 : asc_0, 0xFF, x, y);
m <<= 1;
cx++;
write_char((joy & mask) ? asc_1 : asc_0, 0xFF, cx, y);
mask <<= 1;
}
}
else
{
x += 8;
cx += 8;
}
joystick_last[lastindex] = joy;
}
@@ -595,12 +631,37 @@ void inputtester_advanced()
if (mse_changed)
{
// Mouse position accumulator
mse_x_acc += mse_x;
mse_y_acc += mse_y;
mse_y_acc -= mse_y;
mse_w_acc += mse_w;
write_stringf("%3d", 0xFF, 8, 23, mse_x_acc);
write_stringf("%3d", 0xFF, 12, 23, mse_y_acc);
// Enforce mouse pointer limit
if (mse_x_acc < 32)
{
mse_x_acc = 32;
}
else if (mse_x_acc >= 671)
{
mse_x_acc = 671;
}
if (mse_y_acc < 32)
{
mse_y_acc = 32;
}
else if (mse_y_acc >= 511)
{
mse_y_acc = 511;
}
unsigned short mx = (mse_x_acc / 2);
unsigned short my = (mse_y_acc / 2);
if (mse_x != 0 || mse_y != 0)
{
spr_on[MOUSE_POINTER_SPRITE] = 1;
set_sprite_position(MOUSE_POINTER_SPRITE, mx, my);
}
write_stringf_ushort("%3d", 0xFF, 8, 23, mx - 16);
write_stringf_ushort("%3d", 0xFF, 12, 23, my - 16);
write_stringf("%3d", 0xFF, 20, 23, mse_w_acc);
if (mse_button1_last != mse_button1)
@@ -613,8 +674,10 @@ void inputtester_advanced()
write_char((mse_button1 & m) ? asc_1 : asc_0, 0xFF, x, 23);
m <<= 1;
}
mse_button1_last = mse_button1;
input_mouse_left = CHECK_BIT(mse_button1, 0);
input_mouse_right = CHECK_BIT(mse_button1, 1);
}
mse_button1_last = mse_button1;
if (mse_button2_last != mse_button2)
{
char x = 31;
@@ -625,10 +688,23 @@ void inputtester_advanced()
write_char((mse_button2 & m) ? asc_1 : asc_0, 0xFF, x, 23);
m <<= 1;
}
mse_button2_last = mse_button2;
}
mse_button2_last = mse_button2;
if (input_mouse_left && !input_mouse_left_last)
{
add_ping(0, mx - 8, my - 8);
}
if (input_mouse_right && !input_mouse_right_last)
{
add_ping(1, mx - 8, my - 8);
}
mse_changed = 0;
}
handle_pings();
update_sprites();
}
}
@@ -780,14 +856,6 @@ void btntest_test()
}
}
unsigned short abs(signed short value)
{
if (value < 0)
{
value = value * -1;
}
return value;
}
// Button test - results view
void btntest_results()
{

View File

@@ -0,0 +1,78 @@
/*============================================================================
Input Test - Input test state handlers
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-13
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/>.
===========================================================================*/
#ifndef INPUTTESTER_H
#define INPUTTESTER_H
// Mode switcher variables
extern char modeswitchtimer_select;
extern char modeswitchtimer_start;
#define PAD_COUNT 2
#define BUTTON_COUNT 12
#define color_button_active 0xFF
#define color_button_inactive 0b01010010
#define analog_size 18
#define analog_ratio 15 // 256 / 17;
#define timestamp_clock_index 32
#define timestamp_index_1 8
#define timestamp_index_2 16
#define timestamp_index_3 24
// Button test constants
#define btntest_mode_select 0
#define btntest_mode_ready 1
#define btntest_mode_test 2
#define btntest_mode_results 3
#define btntest_timer_start 60 // vblanks to wait before first prompt
#define btntest_timer_interval 90 // vblanks to wait between prompts
#define btntest_timer_visible 30 // vblanks to wait between prompts
#define btntest_counter_max 5 // Number of button presses required
#define btntest_max 255
#define btntest_highlight_start 2
#define btntest_highlight_end 35
// Initialise digital inputtester state and draw static elements
extern void start_inputtester_digital();
// Initialise analog inputtester state and draw static elements
extern void start_inputtester_analog();
// Initialise advanced inputtester state and draw static elements
extern void start_inputtester_advanced();
// Initialise button test state and draw static elements
extern void start_btntest();
// Digital input tester state
extern void inputtester_digital();
// Analog input tester state
extern void inputtester_analog();
// Advanced input tester state
extern void inputtester_advanced();
// Button test - mode handler
extern void btntest();
#endif

View File

@@ -0,0 +1,88 @@
/*============================================================================
Input Test - Mouse ping animations
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-12-22
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/>.
===========================================================================*/
#include "../shared/sys.h"
#include "../shared/sprite.h"
#include "sprite_images.h"
#include "inputtester_pings.h"
#define const_ping_max 8
unsigned char ping_max = const_ping_max;
unsigned char ping_sprite_first = 0;
unsigned char ping_timer[const_ping_max];
unsigned char ping_frame[const_ping_max];
unsigned char ping_type[const_ping_max];
const unsigned char ping_lifespan = 2;
#define ping_frame_count 7
#define ping_type_count 2
void setup_pings()
{
for (int e = ping_sprite_first; e < ping_sprite_first + ping_max; e++)
{
enable_sprite(e, sprite_palette_pings, sprite_size_pings, false);
spr_on[e] = false;
}
}
void add_ping(unsigned type, unsigned short x, unsigned short y)
{
for (unsigned char e = 0; e < ping_max; e++)
{
if (ping_timer[e] == 0)
{
ping_timer[e] = ping_lifespan;
ping_frame[e] = 0;
type = 0;
// ping_type[e] = type;
unsigned char sprite = ping_sprite_first + e;
enable_sprite(sprite, sprite_palette_pings, sprite_size_pings, 0);
spr_index[sprite] = sprite_index_pings_first + (type * ping_frame_count);
set_sprite_position(sprite, x, y);
return;
}
}
}
void handle_pings()
{
for (unsigned char t = 0; t < ping_max; t++)
{
if (ping_timer[t] > 0)
{
ping_timer[t]--;
if (ping_timer[t] == 0)
{
unsigned char sprite = ping_sprite_first + t;
spr_index[sprite]++;
ping_frame[t]++;
if (ping_frame[t] == ping_frame_count)
{
spr_on[sprite] = false;
}
else
{
ping_timer[t] = ping_lifespan;
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
/*============================================================================
Input Test - Mouse ping animations
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-12-22
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/>.
===========================================================================*/
#ifndef INPUTTESTER_PINGS_H
#define INPUTTESTER_PINGS_H
extern unsigned char ping_max;
extern unsigned char ping_sprite_first;
extern unsigned char ping_timer[];
extern unsigned char ping_frame[];
extern unsigned char ping_type[];
extern const unsigned char ping_lifespan;
extern void setup_pings();
extern void add_ping(unsigned type, unsigned short x, unsigned short y);
extern void handle_pings();
#endif

View File

@@ -19,37 +19,9 @@
with this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
#pragma once
#include "sys.c"
#include "ps2.c"
// Application states
#define STATE_START_INPUTTESTER 1
#define STATE_INPUTTESTER 2
#define STATE_START_INPUTTESTERADVANCED 3
#define STATE_INPUTTESTERADVANCED 4
#define STATE_START_INPUTTESTERANALOG 5
#define STATE_INPUTTESTERANALOG 6
#define STATE_START_BTNTEST 7
#define STATE_BTNTEST 8
#define STATE_START_MENU 9
#define STATE_MENU 10
#define STATE_FADEOUT 20
#define STATE_START_FADEIN 21
#define STATE_FADEIN 22
#define STATE_START_ATTRACT 30
#define STATE_ATTRACT 31
#define STATE_START_GAME_SNEK 40
#define STATE_GAME_SNEK 41
#define GET_TIMER ((unsigned short)timer[1] << 8) | (unsigned char)timer[0]
#include "../shared/sys.h"
#include "../shared/ps2.h"
#include "inputtester_sys.h"
// DPAD tracker
bool input_left = 0;
@@ -69,6 +41,17 @@ bool input_a_last = 0;
bool input_b;
bool input_b_last = 0;
// Mouse tracker
bool input_mouse_left;
bool input_mouse_left_last;
bool input_mouse_right;
bool input_mouse_right_last;
// Input tester application state
char state = 0;
char defaultstate = STATE_START_INPUTTESTER;
char nextstate = 0;
// Track joypad 1 directions and start for menu control
void basic_input()
{
@@ -80,12 +63,15 @@ void basic_input()
input_select_last = input_select;
input_a_last = input_a;
input_b_last = input_b;
input_up = CHECK_BIT(joystick[0], 3) || kbd_down[KEY_UP];
input_down = CHECK_BIT(joystick[0], 2) || kbd_down[KEY_DOWN];
input_left = CHECK_BIT(joystick[0], 1) || kbd_down[KEY_LEFT];
input_mouse_left_last = input_mouse_left;
input_mouse_right_last = input_mouse_right;
input_right = CHECK_BIT(joystick[0], 0) || kbd_down[KEY_RIGHT];
input_start = CHECK_BIT(joystick[1], 3) || kbd_down[KEY_1];
input_select = CHECK_BIT(joystick[1], 2) || kbd_down[KEY_ESC];
input_left = CHECK_BIT(joystick[0], 1) || kbd_down[KEY_LEFT];
input_down = CHECK_BIT(joystick[0], 2) || kbd_down[KEY_DOWN];
input_up = CHECK_BIT(joystick[0], 3) || kbd_down[KEY_UP];
input_a = CHECK_BIT(joystick[0], 4) || kbd_down[KEY_ENTER];
input_b = CHECK_BIT(joystick[0], 5) || kbd_down[KEY_SPACE];
input_start = CHECK_BIT(joystick[1], 3) || kbd_down[KEY_1]|| mse_button1;
input_select = CHECK_BIT(joystick[1], 2) || kbd_down[KEY_ESC] || mse_button2;
}

View File

@@ -0,0 +1,89 @@
/*============================================================================
Input Test - Custom system functions
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-12
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/>.
===========================================================================*/
#ifndef INPUTTESTER_SYS_H
#define INPUTTESTER_SYS_H
// Application states
#define STATE_START_INPUTTESTER 1
#define STATE_INPUTTESTER 2
#define STATE_START_INPUTTESTERADVANCED 3
#define STATE_INPUTTESTERADVANCED 4
#define STATE_START_INPUTTESTERANALOG 5
#define STATE_INPUTTESTERANALOG 6
#define STATE_START_BTNTEST 7
#define STATE_BTNTEST 8
#define STATE_START_MENU 9
#define STATE_MENU 10
#define STATE_FADEOUT 20
#define STATE_START_FADEIN 21
#define STATE_FADEIN 22
#define STATE_START_ATTRACT 30
#define STATE_ATTRACT 31
#define STATE_START_GAME_SNEK 40
#define STATE_GAME_SNEK 41
#define STATE_START_CREDITS 42
#define STATE_START_ZORBLAXX 43
#define GET_TIMER ((unsigned short)timer[1] << 8) | (unsigned char)timer[0]
// DPAD tracker
extern bool input_left;
extern bool input_left_last;
extern bool input_right;
extern bool input_right_last;
extern bool input_up;
extern bool input_up_last;
extern bool input_down;
extern bool input_down_last;
extern bool input_start;
extern bool input_start_last;
extern bool input_select;
extern bool input_select_last;
extern bool input_a;
extern bool input_a_last;
extern bool input_b;
extern bool input_b_last;
// Mouse tracker
extern bool input_mouse_left;
extern bool input_mouse_left_last;
extern bool input_mouse_right;
extern bool input_mouse_right_last;
// Input tester application state
extern char state;
extern char defaultstate;
extern char nextstate;
// Track joypad 1 directions and start for menu control
extern void basic_input();
#endif

View File

@@ -18,10 +18,10 @@
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
#pragma once
#include <stdbool.h>
#define color_pad_outline 0xFE
#include "../shared/sys.h"
#include "../shared/ui.h"
#include "inputtester_ui.h"
void page_frame(bool showMenuButton, bool showContinueButton)
{
@@ -93,8 +93,6 @@ void draw_pad(char xo, char yo)
write_char(char_corner_round_tr, color_pad_outline, xo + 25, yo);
}
#define color_analog_grid 0x23
// Draw game pad outline
void draw_analog(char xo, char yo, char xs, char ys)
{

View File

@@ -0,0 +1,35 @@
/*============================================================================
Input Test - Custom UI functions
Author: Jim Gregory - https://github.com/JimmyStones/
Version: 1.0
Date: 2021-07-12
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/>.
===========================================================================*/
#ifndef INPUTTESTER_UI_H
#define INPUTTESTER_UI_H
#define color_pad_outline 0xFE
#define color_analog_grid 0x23
extern void page_frame(bool showMenuButton, bool showContinueButton);
// Draw game pad outline
extern void draw_pad(char xo, char yo);
// Draw game pad outline
extern void draw_analog(char xo, char yo, char xs, char ys);
#endif

Some files were not shown because too many files have changed in this diff Show More