From 02dfe45644e5143d8bfe1a7e28f4318bc0f90335 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 18 Jan 2025 10:53:46 -0600 Subject: [PATCH 001/155] Added list of games developed with CVBasic --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e6ec37..9849f65 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,22 @@ The NABU PC can only use binaries up to 32 kb, joysticks can be used for both co Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) +### People using CVBasic + +There are some very good examples of games developed with CVBasic. + +* Beachhead by Eric Damain. Demo screenshots [https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/](https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/) + +* Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) + +* Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) + +* Rogue-like Wip by Skywaffle. Available from [https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/](https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/) + +* Unnamed game by OriginalJohn. Demo screenshot [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429) + +* Whack'em Smack'em Byron. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) + ### Supporting the developer If you find CVBasic useful, please show your appreciation making a donation via Paypal ($9 USD suggested) to b-i+y-u+b-i (at) gmail.com @@ -206,7 +222,7 @@ You can also get my book **Programming Games for Colecovision** including an int The foreword is written by the legendary David R. Megarry, programmer of Zaxxon™ for Colecovision, and creator of the Dungeon!™ Board game. -All the games in the book will compile for **all** the platforms. +All the games in the book will compile for **all** the platforms (exception of Dungeon Warrior for Casio PV2000 because the small 16KB ROM size) * [Programming Games for Colecovision, paperback, 250 pages](https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-colecovision/paperback/product-95qvzj8.html?page=1&pageSize=4) * [Programming Games for Colecovision, hardcover, 250 pages](https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-colecovision/hardcover/product-84nm767.html?page=1&pageSize=4) From e54bc3e69f4004ebd165e3d185860fc9343344c7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 18 Jan 2025 10:55:05 -0600 Subject: [PATCH 002/155] Added another game to the list --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9849f65..a964b37 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,8 @@ There are some very good examples of games developed with CVBasic. * Beachhead by Eric Damain. Demo screenshots [https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/](https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/) +* Camelot Knights by myself. Available from [https://forums.atariage.com/topic/363252-camelot-knights-game/](https://forums.atariage.com/topic/363252-camelot-knights-game/) + * Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) From 3f5c1f5937dcbe9397b468b6b4513a2a647063e7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 18 Jan 2025 11:03:06 -0600 Subject: [PATCH 003/155] Added Colecovania to the list of games --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a964b37..d0dcffc 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,9 @@ There are some very good examples of games developed with CVBasic. * Beachhead by Eric Damain. Demo screenshots [https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/](https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/) -* Camelot Knights by myself. Available from [https://forums.atariage.com/topic/363252-camelot-knights-game/](https://forums.atariage.com/topic/363252-camelot-knights-game/) +* Camelot Knights by nanochess. Available from [https://forums.atariage.com/topic/363252-camelot-knights-game/](https://forums.atariage.com/topic/363252-camelot-knights-game/) + +* Colecovania demo by Skywaffle. Video at [https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl]((https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl) * Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) @@ -212,7 +214,7 @@ There are some very good examples of games developed with CVBasic. * Unnamed game by OriginalJohn. Demo screenshot [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429) -* Whack'em Smack'em Byron. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) +* Whack'em Smack'em Byron by Jess Ragan. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) ### Supporting the developer From 462faee3ba8d905851558ebf5deeae58aae469e4 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 18 Jan 2025 11:04:27 -0600 Subject: [PATCH 004/155] Added Monkey Moon to the list of games --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d0dcffc..c1da055 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,8 @@ There are some very good examples of games developed with CVBasic. * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) +* Monkey Moon by nanochess, example from the book **Programming Games for Colecovision**. Available from [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249) + * Rogue-like Wip by Skywaffle. Available from [https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/](https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/) * Unnamed game by OriginalJohn. Demo screenshot [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429) From 405b2d646c4b6975ace8b02a4c9bd9ad6afe4516 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 18 Jan 2025 11:05:17 -0600 Subject: [PATCH 005/155] Corrected Colecovania link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1da055..8ce007d 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ There are some very good examples of games developed with CVBasic. * Camelot Knights by nanochess. Available from [https://forums.atariage.com/topic/363252-camelot-knights-game/](https://forums.atariage.com/topic/363252-camelot-knights-game/) -* Colecovania demo by Skywaffle. Video at [https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl]((https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl) +* Colecovania demo by Skywaffle. Video at [https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl](https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl) * Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) From 42227be23924eca88c3b4a3c10e70c7989a128ce Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 18 Jan 2025 11:06:50 -0600 Subject: [PATCH 006/155] Added Gorilla.BAS to the list of games --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8ce007d..b650a30 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,8 @@ There are some very good examples of games developed with CVBasic. * Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) +* Gorilla.BAS by nanochess. Available from [https://forums.atariage.com/topic/370716-gorillabas-for-colecovision/](https://forums.atariage.com/topic/370716-gorillabas-for-colecovision/) + * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) * Monkey Moon by nanochess, example from the book **Programming Games for Colecovision**. Available from [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249) From 6fddec3206447f7e7d51f4727c37d9082d2f1fd2 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 23 Jan 2025 16:52:18 -0600 Subject: [PATCH 007/155] Added plot.bas example for pixels and line-drawing --- examples/plot.bas | 133 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 examples/plot.bas diff --git a/examples/plot.bas b/examples/plot.bas new file mode 100644 index 0000000..e8f37ef --- /dev/null +++ b/examples/plot.bas @@ -0,0 +1,133 @@ + ' + ' Drawing pixels and lines with CVBasic + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Jan/23/2025. + ' + + DEF FN PSET(x,y)=#c=((x) AND $f8.)+((y) / 8. * 256)+((y) AND 7.):VPOKE #c,VPEEK(#c) OR bit_table((x) AND 7) + + DEF FN PSETCOLOR(x,y,color)=PSET(x,y):VPOKE #c+$2000,color*16 + + DEF FN PRESET(x,y)=#c=((x) AND $f8.)+((y) / 8. * 256)+((y) AND 7.):VPOKE #c,VPEEK(#c) AND NOT bit_table((x) AND 7) + + DEF FN LINE(w,x,y,z)=x1=w:y1=x:x2=y:y2=z:GOSUB draw_line + + DEF FN LINECOLOR(w,x,y,z,a)=x1=w:y1=x:x2=y:y2=z:c=a:GOSUB draw_line_color + + MODE 1 + + y = 20 + FOR x = 20 TO 220 + PSET(x, y) + NEXT x + + FOR y = 20 TO 170 + PSET(x, y) + NEXT y + + FOR x = 220 TO 20 STEP -1 + PSET(x, y) + NEXT x + + FOR y = 170 TO 20 STEP -1 + PSET(x, y) + NEXT y + + FOR y = 40 TO 150 + FOR x = 40 TO 63 + PSETCOLOR(x, y, y AND $0F) + NEXT x + NEXT y + + FOR x = 72 TO 202 STEP 10 + LINE(x, 40, 202, 150) + NEXT x + + FOR y = 40 TO 150 STEP 10 + LINE(72, y, 202, 150) + NEXT y + + FOR x = 8 TO 240 STEP 8 + LINECOLOR(128, 0, x, 16, (x / 8) AND $0F) + NEXT x + + WHILE 1: WEND + + ' + ' Draw a line using the Bresenham algorithm + ' + SIGNED #err + +draw_line: PROCEDURE + sx = SGN(x2 + 0 - x1) + sy = SGN(y2 + 0 - y1) + #dx = ABS(x2 + 0 - x1) + #dy = ABS(y2 + 0 - y1) + IF #dx > #dy THEN + #err = 2 * #dy - #dx + WHILE 1 + PSET(x1, y1) + IF x1 = x2 THEN RETURN + IF #err < 0 THEN + #err = #err + 2 * #dy + ELSE + #err = #err + 2 * (#dy - #dx) + y1 = y1 + sy + END IF + x1 = x1 + sx + WEND + ELSE + #err = 2 * #dx - #dy + WHILE 1 + PSET(x1, y1) + IF y1 = y2 THEN RETURN + IF #err < 0 THEN + #err = #err + 2 * #dx + ELSE + #err = #err + 2 * (#dx - #dy) + x1 = x1 + sx + END IF + y1 = y1 + sy + WEND + END IF + END + +draw_line_color: PROCEDURE + sx = SGN(x2 + 0 - x1) + sy = SGN(y2 + 0 - y1) + #dx = ABS(x2 + 0 - x1) + #dy = ABS(y2 + 0 - y1) + IF #dx > #dy THEN + #err = 2 * #dy - #dx + WHILE 1 + PSETCOLOR(x1, y1, c) + IF x1 = x2 THEN RETURN + IF #err < 0 THEN + #err = #err + 2 * #dy + ELSE + #err = #err + 2 * (#dy - #dx) + y1 = y1 + sy + END IF + x1 = x1 + sx + WEND + ELSE + #err = 2 * #dx - #dy + WHILE 1 + PSETCOLOR(x1, y1, c) + IF y1 = y2 THEN RETURN + IF #err < 0 THEN + #err = #err + 2 * #dx + ELSE + #err = #err + 2 * (#dx - #dy) + x1 = x1 + sx + END IF + y1 = y1 + sy + WEND + END IF + END + +bit_table: + DATA BYTE $80,$40,$20,$10,$08,$04,$02,$01 From 3722a42918d24c9d474e54f3039217c9b692ce28 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 24 Jan 2025 14:44:02 -0600 Subject: [PATCH 008/155] Added circle subroutine to plot.bas --- examples/plot.bas | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/examples/plot.bas b/examples/plot.bas index e8f37ef..aef44e1 100644 --- a/examples/plot.bas +++ b/examples/plot.bas @@ -17,6 +17,8 @@ DEF FN LINECOLOR(w,x,y,z,a)=x1=w:y1=x:x2=y:y2=z:c=a:GOSUB draw_line_color + DEF FN CIRCLE(w,x,y)=x1=w:y1=x:c=y:GOSUB draw_circle + MODE 1 y = 20 @@ -37,23 +39,27 @@ NEXT y FOR y = 40 TO 150 - FOR x = 40 TO 63 + FOR x = 32 TO 55 PSETCOLOR(x, y, y AND $0F) NEXT x NEXT y - FOR x = 72 TO 202 STEP 10 + FOR x = 102 TO 202 STEP 10 LINE(x, 40, 202, 150) NEXT x FOR y = 40 TO 150 STEP 10 - LINE(72, y, 202, 150) + LINE(102, y, 202, 150) NEXT y FOR x = 8 TO 240 STEP 8 LINECOLOR(128, 0, x, 16, (x / 8) AND $0F) NEXT x + CIRCLE(80, 60, 15) + CIRCLE(80, 100, 20) + CIRCLE(80, 140, 25) + WHILE 1: WEND ' @@ -129,5 +135,34 @@ draw_line_color: PROCEDURE END IF END +draw_points: PROCEDURE + PSET(x1 + x, y1 + y) + PSET(x1 + x, y1 - y) + PSET(x1 - x, y1 + y) + PSET(x1 - x, y1 - y) + PSET(x1 + y, y1 + x) + PSET(x1 + y, y1 - x) + PSET(x1 - y, y1 + x) + PSET(x1 - y, y1 - x) + END + +draw_circle: PROCEDURE + x = 0 + y = c + #err = 3 - 2 * c + GOSUB draw_points + WHILE x <= y + IF #err > 0 THEN + y = y - 1 + #err = #err + 4 * x - 4 * y + 10 + ELSE + #err = #err + 4 * x + 6 + END IF + x = x + 1 + GOSUB draw_points + WEND + + END + bit_table: DATA BYTE $80,$40,$20,$10,$08,$04,$02,$01 From fd9d5cbac3b71deac74731ed4d47acbec01ba504 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 3 Feb 2025 10:44:54 -0600 Subject: [PATCH 009/155] Solved typo in %C (reported by sinsinpub) --- cvbasic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic.c b/cvbasic.c index 0adafcb..7dc73c4 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5902,7 +5902,7 @@ int main(int argc, char *argv[]) if ((machine == MEMOTECH || machine == EINSTEIN) && cpm_option != 0) fprintf(output, "STACK:\tequ %c%04x\t; Base stack pointer\n", hex, 0xe000); else - fprintf(output, "STACK:\tequ %C%04x\t; Base stack pointer\n", hex, consoles[machine].stack); + fprintf(output, "STACK:\tequ %c%04x\t; Base stack pointer\n", hex, consoles[machine].stack); fprintf(output, "VDP:\tequ %c%02x\t; VDP port (write)\n", hex, consoles[machine].vdp_port_write); fprintf(output, "VDPR:\tequ %c%02x\t; VDP port (read)\n", hex, consoles[machine].vdp_port_read); if (machine != TI994A) { From 3d23b1390bd226c6ecd842af9bd9b607a44c5430 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 3 Feb 2025 10:55:29 -0600 Subject: [PATCH 010/155] Final ROM rounding to multiples of 8K (suggested by sinsinpub) --- cvbasic_epilogue.asm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 775864e..686b6a3 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -19,10 +19,15 @@ ; Revision date: Aug/02/2024. Added rom_end label for Memotech. ; Revision date: Aug/15/2024. Added support for Tatung Einstein. ; Revision date: Nov/12/2024. Added vdp_status. + ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. ; rom_end: + ; ROM final size rounding + if MSX+COLECO+SG1000+SVI+SORD+PENCIL + TIMES (($+$1FFF)&$e000)-$ DB $ff + endif if MEMOTECH+EINSTEIN+NABU ; Align following data to a 256-byte page. TIMES $100-($&$ff) DB $4f @@ -30,6 +35,7 @@ rom_end: if PV2000 TIMES $10000-$ DB $ff endif + if COLECO+SG1000+MSX+SVI+SORD+PV2000 org BASE_RAM endif From f8b252d99522ee47e15084f64b8a417245c26bba Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 3 Feb 2025 11:25:24 -0600 Subject: [PATCH 011/155] Small patch --- cvbasic_epilogue.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 686b6a3..71ade79 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -25,7 +25,7 @@ rom_end: ; ROM final size rounding - if MSX+COLECO+SG1000+SVI+SORD+PENCIL + if MSX+COLECO+SG1000+SVI+SORD TIMES (($+$1FFF)&$e000)-$ DB $ff endif if MEMOTECH+EINSTEIN+NABU From a03d5284189bbaa462e5be68ed8c50e4c8361ff9 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 20 Mar 2025 18:38:08 -0600 Subject: [PATCH 012/155] Solved bug where 16-bit arrays marked SIGNED were taken as 8-bit --- cvbasic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic.c b/cvbasic.c index 7dc73c4..bab3995 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -1723,7 +1723,7 @@ struct node *evaluate_level_7(int *type) tree = node_create(N_MUL16, 0, tree, node_create(N_NUM16, 2, NULL, NULL)); } - tree = node_create(*type == TYPE_16 ? N_PEEK16 : N_PEEK8, 0, + tree = node_create((*type & MAIN_TYPE) == TYPE_16 ? N_PEEK16 : N_PEEK8, 0, node_create(N_PLUS16, 0, addr, tree), NULL); return tree; } From a0d1c3515993b81b44bbc5759d8a93656a469207 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 26 Mar 2025 13:00:11 -0600 Subject: [PATCH 013/155] Solved bug when doing TO 0 STEP -1, also when rounding Colecovision ROM to 32KB --- cvbasic.c | 69 ++++++++++++++++++++++++++++---------------- cvbasic_epilogue.asm | 2 +- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index bab3995..8f2bd83 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -2313,7 +2313,6 @@ void compile_statement(int check_for_else) struct node *var; int positive; int type; - int step_value; int type_var; enum node_type comparison; struct signedness *sign; @@ -2351,32 +2350,30 @@ void compile_statement(int check_for_else) final = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, final, NULL); else if ((type_var & MAIN_TYPE) == TYPE_8 && (type & MAIN_TYPE) == TYPE_16) final = node_create(N_REDUCE16, 0, final, NULL); - positive = 1; + positive = 2; var = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_LOAD16 : N_LOAD8, 0, NULL, NULL); var->label = label_search(new_loop->var); if (lex == C_NAME && strcmp(name, "STEP") == 0) { get_lex(); if (lex == C_MINUS) { get_lex(); - step = evaluate_level_0(&type); - if ((type_var & MAIN_TYPE) == TYPE_16 && (type & MAIN_TYPE) == TYPE_8) - step = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, step, NULL); - else if ((type_var & MAIN_TYPE) == TYPE_8 && (type & MAIN_TYPE) == TYPE_16) - step = node_create(N_REDUCE16, 0, step, NULL); - step = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_MINUS16 : N_MINUS8, 0, - var, step); positive = 0; - } else { - step = evaluate_level_0(&type); - if ((type_var & MAIN_TYPE) == TYPE_16 && (type & MAIN_TYPE) == TYPE_8) - step = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, step, NULL); - else if ((type_var & MAIN_TYPE) == TYPE_8 && (type & MAIN_TYPE) == TYPE_16) - step = node_create(N_REDUCE16, 0, step, NULL); - step = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_PLUS16 : N_PLUS8, 0, var, step); } + step = evaluate_level_0(&type); + if ((type_var & MAIN_TYPE) == TYPE_16 && (type & MAIN_TYPE) == TYPE_8) + step = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, step, NULL); + else if ((type_var & MAIN_TYPE) == TYPE_8 && (type & MAIN_TYPE) == TYPE_16) + step = node_create(N_REDUCE16, 0, step, NULL); + if ((step->type == N_NUM8 && step->value == 1) + || (step->type == N_NUM16 && step->value == 1)) + positive |= 1; } else { - step_value = 1; step = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_NUM16 : N_NUM8, 1, NULL, NULL); + positive |= 1; + } + if ((positive & 2) == 0) { /* Negative step */ + step = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_MINUS16 : N_MINUS8, 0, var, step); + } else { /* Positive step */ step = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_PLUS16 : N_PLUS8, 0, var, step); } var = node_create(N_ADDR, 0, NULL, NULL); @@ -2385,15 +2382,37 @@ void compile_statement(int check_for_else) var = node_create((type_var & MAIN_TYPE) == TYPE_16 ? N_LOAD16 : N_LOAD8, 0, NULL, NULL); var->label = label_search(new_loop->var); if ((type_var & MAIN_TYPE) == TYPE_16) { - if (type_var & TYPE_SIGNED) - comparison = positive ? N_GREATER16S : N_LESS16S; - else - comparison = positive ? N_GREATER16 : N_LESS16; + if (type_var & TYPE_SIGNED) { + if (final->type == N_NUM16 && final->value == 0x8000 && (positive & 1) != 0) { + final->value = 0x7fff; + comparison = N_EQUAL16; + } else { + comparison = (positive & 2) ? N_GREATER16S : N_LESS16S; + } + } else { + if (final->type == N_NUM16 && final->value == 0x0000 && (positive & 1) != 0) { + final->value = 0xffff; + comparison = N_EQUAL16; + } else { + comparison = (positive & 2) ? N_GREATER16 : N_LESS16; + } + } } else { - if (type_var & TYPE_SIGNED) - comparison = positive ? N_GREATER8S : N_LESS8S; - else - comparison = positive ? N_GREATER8 : N_LESS8; + if (type_var & TYPE_SIGNED) { + if (final->type == N_NUM8 && final->value == 0x80 && (positive & 1) != 0) { + final->value = 0x7f; + comparison = N_EQUAL8; + } else { + comparison = (positive & 2) ? N_GREATER8S : N_LESS8S; + } + } else { + if (final->type == N_NUM8 && final->value == 0x00 && (positive & 1) != 0) { + final->value = 0xff; + comparison = N_EQUAL8; + } else { + comparison = (positive & 2) ? N_GREATER8 : N_LESS8; + } + } } final = node_create(comparison, 0, var, final); } diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 71ade79..e35c884 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -26,7 +26,7 @@ rom_end: ; ROM final size rounding if MSX+COLECO+SG1000+SVI+SORD - TIMES (($+$1FFF)&$e000)-$ DB $ff + TIMES (($+$1FFF)&$1e000)-$ DB $ff endif if MEMOTECH+EINSTEIN+NABU ; Align following data to a 256-byte page. From ed2bb5f841f61a41f6f8d1c368fb94156c45f533 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 14 Apr 2025 12:05:57 -0600 Subject: [PATCH 014/155] Solved bug in Creativision when using SCREEN with source offset constant --- node.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/node.c b/node.c index a8bf147..2117663 100644 --- a/node.c +++ b/node.c @@ -786,16 +786,18 @@ struct node *node_create(enum node_type type, int value, struct node *left, stru ** parenthesis: 1 - open and close () 2 - # - 3 - open only ( + 3 - #( 4 - @ */ void node_get_label(struct node *node, int parenthesis) { temp[0] = '\0'; - if (parenthesis == 1 || parenthesis == 3) + if (parenthesis == 1) strcat(temp, "("); else if (parenthesis == 2) strcat(temp, "#"); + else if (parenthesis == 3) + strcat(temp, "#("); else if (parenthesis == 4) strcat(temp, "@"); if (node->label->length) { From de54a2c87bbddd86bd37f8e97a206a0bf106b832 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 14 Apr 2025 12:25:12 -0600 Subject: [PATCH 015/155] SG1000 games now include a Sega Master System ROM header --- brinquitos.asm | 4856 ++++++++++++++++++++++++++++++++++++++++++ brinquitos.rom | Bin 0 -> 32768 bytes cvbasic_epilogue.asm | 11 +- 3 files changed, 4866 insertions(+), 1 deletion(-) create mode 100644 brinquitos.asm create mode 100644 brinquitos.rom diff --git a/brinquitos.asm b/brinquitos.asm new file mode 100644 index 0000000..c998a2d --- /dev/null +++ b/brinquitos.asm @@ -0,0 +1,4856 @@ + ; CVBasic compiler v0.8.0 Nov/12/2024 + ; Command: ./cvbasic --sg1000 examples/brinquitos.bas brinquitos.asm + ; Created: Mon Apr 14 12:13:08 2025 + +COLECO: equ 0 +SG1000: equ 1 +MSX: equ 0 +SGM: equ 0 +SVI: equ 0 +SORD: equ 0 +MEMOTECH: equ 0 +EINSTEIN: equ 0 +CPM: equ 0 +PENCIL: equ 0 +PV2000: equ 0 +TI99: equ 0 +NABU: equ 0 + +CVBASIC_MUSIC_PLAYER: equ 1 +CVBASIC_COMPRESSION: equ 0 +CVBASIC_BANK_SWITCHING: equ 0 + +BASE_RAM: equ $c000 ; Base of RAM +STACK: equ $c400 ; Base stack pointer +VDP: equ $be ; VDP port (write) +VDPR: equ $be ; VDP port (read) +PSG: equ $7f ; PSG port (write) + + ; + ; CVBasic prologue (BASIC compiler for Colecovision) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. + ; Added 16-bit multiply, division, modulo, and abs. + ; Added random generator. Added sound routines. + ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. + ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/14/2024. Added _sgn16. + ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. + ; Revision date: Apr/11/2024. Added support for formatting numbers. Added + ; support for Super Game Module. + ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. + ; Shorter mode setting subroutines. + ; Revision date: Apr/26/2024. Interruption handler saves current bank. + ; Revision date: Apr/27/2024. Music player now supports bank switching. + ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller + ; support with keyboard (code by SiRioKD) + ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. + ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. + ; Revision date: Jun/17/2024. Added SVI-328 support. + ; Revision date: Aug/01/2024. Added Sord M5 support. + ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech + ; support. + ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support + ; for Casio PV-2000. + ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, + ; and Casio PV-2000. + ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision + ; with flicker flag). + ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number + ; keys values were inverted. + ; Revision date: Nov/12/2024. Saves the VDP status. + ; + +JOYSEL: equ $c0 +KEYSEL: equ $80 + +JOY1: equ $fc-$20*SG1000 +JOY2: equ $ff-$22*SG1000 + + if COLECO + org $8000 + if PENCIL + db "COPYRIGHT SOUNDIC" + jp START + jp nmi_handler + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + db "CVBASIC!POWERED BY!2024!" + else + db $55,$aa + dw 0 + dw 0 + dw 0 + dw 0 + dw START + + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + + jp nmi_handler + endif + endif + if SG1000+SVI + org $0000 + di + ld sp,STACK + jp START + db $ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp nmi_handler ; It should be called int_handler. + endif + if MSX + ORG $4000 + db "AB" + dw START + dw $0000 + dw $0000 + dw $0000 + dw $0000 + +WRTPSG: equ $0093 +RDPSG: equ $0096 + + endif + if SORD + ORG $2000 + db $02 ; Avoid checking $4000 + dw START ; Start address. + dw $002e ; Prestart address (just point to RET in BIOS). + endif + if PV2000 + ORG $C000 + jp START + endif + + if MEMOTECH + if CPM + org $0100 + else + org $40fc + dw rom_start + dw rom_end-rom_start + endif +rom_start: + jp START + db 0,0,0,0,0 + dw nmi_handler + dw null_vector + dw null_vector + dw rom_start + +null_vector: + ei + reti + endif + if EINSTEIN + org $0100 +rom_start: + jp START + db 0,0,0,0,0 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + endif + if NABU + if CPM + org $0100 + else + org $140d + endif + nop + nop + nop + jp START + times $100-($&255) db $ff +nabu_int: + dw null_vector + dw null_vector + dw keyboard_handler + dw nmi_handler + dw null_vector + dw null_vector + dw null_vector + dw null_vector + +null_vector: + ei + reti + endif + + if SVI +WRTPSG: + out ($88),a + push af + ld a,e + out ($8c),a + pop af + ret + +RDPSG: + out ($88),a + push af + pop af + in a,($90) + ret + endif + + if EINSTEIN +WRTPSG: + out ($02),a + push af + ld a,e + out ($03),a + pop af + ret + +RDPSG: + out ($02),a + push af + pop af + in a,($02) + ret + endif + + if NABU +WRTPSG: + out ($41),a + push af + ld a,e + out ($40),a + pop af + ret + +RDPSG: + out ($41),a + push af + pop af + in a,($40) + ret + endif + + if PV2000 +WRTVDP: + ld a,b + ld (VDP+1),a + ld a,c + or $80 + ld (VDP+1),a + ret + +SETWRT: + ld a,l + ld (VDP+1),a + ld a,h + or $40 + ld (VDP+1),a + ret + +SETRD: + ld a,l + ld (VDP+1),a + ld a,h + and $3f + ld (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + ld (VDP),a + ret + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + ld a,(VDP) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: ld (VDP),a ; 13 14 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 37 42 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + ld a,(VDP) + ld (de),a + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + EX DE,HL + CALL SETWRT + EX DE,HL + DEC BC + INC C + LD A,B + LD B,C + INC A + LD C,A +.1: + LD A,(HL) ; 7 8 + LD (VDP),A ; 13 14 + INC HL ; 6 7 + DJNZ .1 ; 13 14 + DEC C ; 4 5 + JP NZ,.1 ; 10 11 + RET + else +WRTVDP: + ld a,b + out (VDP+1),a + ld a,c + or $80 + out (VDP+1),a + ret + +SETWRT: + ld a,l + out (VDP+1),a + ld a,h + or $40 + out (VDP+1),a + ret + +SETRD: + ld a,l + out (VDP+1),a + ld a,h + and $3f + out (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + out (VDP),a + ret + + if SG1000 + db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Located at $0066 + ei ; NMI handler (pause button) + retn + endif + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + in a,(VDPR) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: out (VDP),a ; 11 12 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 35 40 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + in a,(VDP) + ld (de),a + if SORD + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + ex de,hl + call SETWRT + ex de,hl + dec bc + inc c + ld a,b + ld b,c + inc a + ld c,VDP +.1: + if SORD + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + outi + jp nz,.1 + dec a + jp nz,.1 + ret + endif + +LDIRVM3: + call .1 + call .1 +.1: push hl + push de + push bc + call LDIRVM + pop bc + pop de + ld a,d + add a,8 + ld d,a + pop hl + ret + +DISSCR: + call nmi_off + ld bc,$a201 + call WRTVDP + jp nmi_on + +ENASCR: + call nmi_off + ld bc,$e201 + call WRTVDP + jp nmi_on + +CPYBLK: + pop hl + ex af,af' + pop af + ld b,a + pop af + ld c,a + pop de + ex (sp),hl + call nmi_off +.1: push bc + push hl + push de + ld b,0 + call LDIRVM + pop hl + ld bc,$0020 + add hl,bc + ex de,hl + pop hl + ex af,af' + ld c,a + ld b,0 + add hl,bc + ex af,af' + pop bc + djnz .1 + jp nmi_on + +nmi_off: + if COLECO+PV2000 + push hl + ld hl,mode + set 0,(hl) + pop hl + endif + if SG1000+MSX+SVI+SORD+MEMOTECH+NABU + di + endif + ret + +nmi_on: + if COLECO+PV2000 + push af + push hl + ld hl,mode + res 0,(hl) + nop + bit 1,(hl) + jp nz,nmi_handler.0 + pop hl + pop af + endif + if SG1000+MSX+SVI+SORD+MEMOTECH+NABU + ei + endif + ret + + if COLECO +keypad_table: + db $0f,$08,$04,$05,$0c,$07,$0b,$02 + db $0d,$0a,$00,$09,$03,$01,$06,$0f + endif + +cls: + ld hl,$1800 + ld (cursor),hl + ld bc,$0300 + ld a,$20 + call nmi_off + call FILVRM + jp nmi_on + +print_string: + ld c,a + ld b,0 + ld de,(cursor) + ld a,d + and $07 + or $18 + ld d,a + push de + push bc + call nmi_off + call LDIRVM + call nmi_on + pop bc + pop hl + add hl,bc + ld (cursor),hl + ret + +print_number: + ld b,0 + call nmi_off +print_number5: + ld de,10000 + call print_digit +print_number4: + ld de,1000 + call print_digit +print_number3: + ld de,100 + call print_digit +print_number2: + ld de,10 + call print_digit +print_number1: + ld de,1 + ld b,e + call print_digit + jp nmi_on + +print_digit: + ld a,$2f + or a +.2: inc a + sbc hl,de + jp nc,.2 + add hl,de + cp $30 + jr nz,.3 + ld a,b + or a + ret z + dec a + jr z,.4 + ld a,c + jr .5 +.4: + ld a,$30 +.3: ld b,1 +.5: push hl + ld hl,(cursor) + ex af,af' + ld a,h + and $07 + or $18 + ld h,a + ex af,af' + call WRTVRM + inc hl + ld (cursor),hl + pop hl + ret + +define_sprite: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + ld h,$07 + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + ex de,hl + call nmi_off + call LDIRVM + jp nmi_on + +define_char: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + call nmi_off + ld a,(mode) + and 8 + jr nz,.1 + call LDIRVM3 + jp nmi_on + +.1: call LDIRVM + jp nmi_on + +define_color: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d + call nmi_off + call LDIRVM3 + jp nmi_on + +update_sprite: + pop bc + ld (sprite_data+3),a + pop af + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + push bc + ld de,sprites + add a,a + add a,a + if SORD + or $80 + endif + ld e,a + ld hl,sprite_data + ld bc,4 + ldir + ret + + ; Fast 16-bit multiplication. +_mul16: + ld b,h + ld c,l + ld a,16 + ld hl,0 +.1: + srl d + rr e + jr nc,.2 + add hl,bc +.2: sla c + rl b + dec a + jp nz,.1 + ret + + ; 16-bit signed modulo. + ; hl = hl % de +_mod16s: + ld a,h + or a + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _mod16 + pop af + ret p + jp _neg16 + + ; 16-bit signed division. + ; hl = hl / de +_div16s: + ld a,h + xor d + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _div16 + pop af + ret p + jp _neg16 + +_abs16: + bit 7,h + ret z +_neg16: + ld a,h + cpl + ld h,a + ld a,l + cpl + ld l,a + inc hl + ret + + ; Fast 16-bit division. + ; hl = hl / de +_div16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + rl c + rl b + ld h,b + ld l,c + ret + + ; Fast 16-bit modulo. +_mod16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + ret + +_sgn16: + ld a,h + or l + ret z + bit 7,h + ld hl,$ffff + ret nz + inc hl + inc hl + ret + + ; Random number generator. + ; From my game Mecha Eight. +random: + ld hl,(lfsr) + ld a,h + or l + jr nz,.0 + ld hl,$7811 +.0: ld a,h + and $80 + ld b,a + ld a,h + and $02 + rrca + rrca + xor b + ld b,a + ld a,h + and $01 + rrca + xor b + ld b,a + ld a,l + and $20 + rlca + rlca + xor b + rlca + rr h + rr l + ld (lfsr),hl + ret + +sn76489_freq: + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + ld b,a + ld a,l + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + and $3f + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_vol: + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + cpl + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_control: + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + and $0f + or $e0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +ay3_reg: + if COLECO + push af + ld a,b + out ($50),a + pop af + out ($51),a + ret + endif + if SG1000+SORD+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,a + ld a,b + jp WRTPSG + endif + +ay3_freq: + if COLECO + out ($50),a + push af + ld a,l + out ($51),a + pop af + inc a + out ($50),a + push af + ld a,h + and $0f + out ($51),a + pop af + ret + endif + if SG1000+SORD+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,l + call WRTPSG + ld e,h + inc a + jp WRTPSG + endif + + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ; Required for SG1000 as it doesn't have a BIOS + ; Required for SVI because we don't have access to BIOS in cartridge. + ; Required for Sord M5 because it doesn't provide an ASCII charset. + ; Required for Memotech/Einstein because CP/M uses the memory. + ; My personal font for TMS9928. + ; + ; Patterned after the TMS9928 programming manual 6x8 letters + ; with better lowercase letters, also I made a proper + ; AT sign. + ; +font_bitmaps: + db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space + db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! + db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " + db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # + db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ + db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % + db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & + db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' + db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( + db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) + db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * + db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + + db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , + db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - + db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . + db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / + db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 + db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 + db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 + db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 + db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 + db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 + db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 + db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 + db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 + db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 + db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : + db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; + db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < + db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = + db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > + db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? + db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ + db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A + db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B + db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C + db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D + db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E + db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F + db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G + db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H + db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I + db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J + db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K + db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L + db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M + db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N + db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O + db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P + db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q + db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R + db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S + db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T + db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U + db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V + db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W + db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X + db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y + db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z + db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ + db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ + db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] + db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E + db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ + db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 + db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a + db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b + db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c + db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d + db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e + db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f + db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g + db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h + db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i + db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j + db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k + db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l + db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m + db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n + db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o + db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p + db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q + db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r + db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s + db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t + db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u + db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v + db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w + db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x + db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y + db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z + db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { + db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | + db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } + db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e + db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f + endif + +vdp_generic_mode: + call nmi_off + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0602 ; $1800 for pattern table. + call WRTVDP + ld b,d + ld c,$03 ; for color table. + call WRTVDP + ld b,e + ld c,$04 ; for bitmap table. + call WRTVDP + ld bc,$3605 ; $1b00 for sprite attribute table. + call WRTVDP + ld bc,$0706 ; $3800 for sprites bitmaps. + call WRTVDP + ld bc,$0107 + jp WRTVDP + +mode_0: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls +vdp_generic_sprites: + call nmi_off + ld hl,$1b00 + ld bc,$0080 + ld a,$d1 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,127 + ld (hl),$d1 + ldir + call nmi_on + call nmi_off + ld bc,$e201 ; Enable screen and interrupts. + call WRTVDP + jp nmi_on + +mode_1: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld hl,$0000 + ld bc,$1800 + xor a + call FILVRM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + ld hl,$1800 +.1: call nmi_off + ld b,32 +.2: ld a,l + call WRTVRM + inc hl + djnz .2 + call nmi_on + ld a,h + cp $1b + jp nz,.1 + jp vdp_generic_sprites + +mode_2: + ld hl,mode + set 3,(hl) + ld bc,$0000 + ld de,$8000 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$0020 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites + + if MSX +ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) +RSLREG: EQU $0138 ; Read slot status in A + + ; + ; Get slot mapping + ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) + ; A = Current slot selection status (CALL RSLREG) + ; +get_slot_mapping: + call rotate_slot + ld c,a + add a,$C1 ; EXPTBL + ld l,a + ld h,$FC + ld a,(hl) + and $80 ; Get expanded flag + or c + ld c,a + inc hl + inc hl + inc hl + inc hl + ld a,(hl) ; SLTTBL + call rotate_slot + rlca + rlca + or c ; A contains bit 7 = Marks expanded + ; bit 6 - 4 = Doesn't care + ; bit 3 - 2 = Secondary mapper + ; bit 1 - 0 = Primary mapper + ret + +rotate_slot: + push bc + dec b + inc b + jr z,.1 +.0: rrca + rrca + djnz .0 +.1: and 3 + pop bc + ret + + endif + +nmi_handler: + push af + push hl + ld hl,mode + bit 0,(hl) + jr z,.1 + set 1,(hl) + pop hl + pop af + retn + +.0: res 1,(hl) + +.1: push bc + push de + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000 + ld a,($7fff) + endif + if MSX + ld a,($bfff) + endif + push af + endif + if SORD+MEMOTECH + call ctc_reti + endif + if SG1000+MSX+SVI+SORD+MEMOTECH+NABU + in a,(VDPR+1) + ld (vdp_status),a + endif + ld bc,$8000+VDP + bit 2,(hl) + jr z,.4 + + ld hl,$1b00 + call SETWRT + ld hl,sprites +.7: + if PV2000 + ld a,(hl) + ld (VDP),a + inc hl + djnz .7 + else + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp nz,.7 + endif + jr .5 + +.4: + ld hl,$1b00 + call SETWRT + ld a,(flicker) + add a,$04 + ld (flicker),a + ld de,24 + ld b,128 + ld l,a + if SORD + else + ld h,sprites>>8 + endif +.6: + if SORD + set 7,l + ld h,sprites>>8 + else + res 7,l + endif + if PV2000 + ld a,(hl) ; 7 8 + ld (VDP),a ; 13 14 + inc hl ; 6 7 + dec b ; 4 5 + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + else + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + endif + add hl,de + jp nz,.6 +.5: + + if COLECO + out (JOYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + or $b0 + ld b,a + in a,(JOY2) + or $b0 + ld c,a + + out (KEYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + ld d,a + in a,(JOY2) + ld e,a + + ld a,d + rlca + or $7f + and b + cpl + ld (joy1_data),a + + ld a,e + rlca + or $7f + and c + cpl + ld (joy2_data),a + + ld a,d + and $0f + ld c,a + ld b,0 + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key1_data),a + + ld a,e + and $0f + ld c,a + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key2_data),a + endif + if SG1000 + ld a,$07 + out ($de),a + ld b,$ff + in a,(JOY1) + ld h,a + in a,(JOY2) + ld l,a + in a,($de) + cp 7 + jp nz,.sg1000 + + ld a,$00 + out ($de),a + in a,($dc) + rra + ld c,1 + jr nc,.sg1 + in a,($dd) + rra + ld c,8 + jr nc,.sg1 + ld a,$01 + out ($de),a + in a,($dc) + rra + ld c,2 + jr nc,.sg1 + in a,($dd) + rra + ld c,9 + jr nc,.sg1 + ld a,$02 + out ($de),a + in a,($dc) + rra + ld c,3 + jr nc,.sg1 + in a,($dd) + rra + ld c,0 + jr nc,.sg1 + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a + ld c,10 + jr z,.sg1 + rra + ld c,4 + jr nc,.sg1 + ld a,$04 + out ($de),a + in a,($dc) + rra + ld c,5 + jr nc,.sg1 + ld a,$05 + out ($de),a + in a,($dc) + bit 6,a + ld c,11 + jr z,.sg1 + rra + ld c,6 + jr nc,.sg1 + ld a,$06 + out ($de),a + in a,($dc) + rra + ld c,7 + jr nc,.sg1 + ld c,15 +.sg1: ld a,c + ld (key1_data),a + + ld a,$04 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard down. + jr nz,$+4 + res 1,h + ld a,$05 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard left. + jr nz,$+4 + res 2,h + ld a,$06 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard right. + jr nz,$+4 + res 3,h + bit 6,a ; Keyboard up. + jr nz,$+4 + res 0,h + ld a,$02 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Ins + jr nz,$+4 + res 4,h + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Del + jr nz,$+4 + res 5,h +.sg1000: + bit 0,h + jr nz,$+4 + res 0,b + bit 1,h + jr nz,$+4 + res 2,b + bit 2,h + jr nz,$+4 + res 3,b + bit 3,h + jr nz,$+4 + res 1,b + bit 4,h + jr nz,$+4 + res 6,b + bit 5,h + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + + ld a,$ff + bit 6,h + jr nz,$+4 + res 0,a + bit 7,h + jr nz,$+4 + res 2,a + + bit 0,l + jr nz,$+4 + res 3,a + bit 1,l + jr nz,$+4 + res 1,a + bit 2,l + jr nz,$+4 + res 4,a + bit 3,l + jr nz,$+4 + res 5,a + cpl + ld (joy2_data),a + + endif + if MSX + ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php + ld a,15 + call RDPSG + and $b0 + or $4f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + ld b,$ff + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy2_data),a + + in a,($aa) + and $f0 + or $00 + out ($aa),a + in a,($a9) + cp $ff + ld c,$ff + jr nz,.key1 + in a,($aa) + and $f0 + or $01 + out ($aa),a + in a,($a9) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + in a,($aa) + and $f0 + or $07 + out ($aa),a + in a,($a9) + bit 5,a ; BS + ld c,$0a + jr z,.key2 + bit 7,a ; RET + ld c,$0b + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + in a,($aa) + and $f0 + or $08 + out ($aa),a + in a,($a9) + bit 5,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 6,a + jr nz,$+4 + res 2,b + bit 4,a + jr nz,$+4 + res 3,b + bit 0,a + jr nz,$+4 + res 6,b + in a,($aa) + and $f0 + or $04 + out ($aa),a + in a,($a9) + bit 2,a + jr nz,$+4 + res 7,b + + ld a,15 + call RDPSG + and $b0 + or $0f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + + ld a,b + cpl + ld (joy1_data),a + endif + if SVI + ld a,14 + call RDPSG + ld b,$ff + bit 4,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 5,a + jr nz,$+4 + res 2,b + bit 6,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 5,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy2_data),a + + ld a,$10 + out ($96),a + in a,($99) + cp $ff + ld c,$ff + jr nz,.key1 + ld a,$11 + out ($96),a + in a,($99) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + ld a,$16 + out ($96),a + in a,($99) + bit 6,a + ld c,$0b + jr z,.key2 + ld a,$15 + out ($96),a + in a,($99) + bit 6,a + ld c,$0a + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + ld a,$15 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 0,b + ld a,$18 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 1,b + ld a,$17 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 2,b + ld a,$16 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 3,b + ld a,$18 + out ($96),a + in a,($99) + bit 0,a + jr nz,$+4 + res 6,b + ld a,$13 + out ($96),a + in a,($99) + bit 5,a + jr nz,$+4 + res 7,b + + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 4,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy1_data),a + endif + if SORD + ld bc,$ffff + in a,($37) ; Read joystick + rra + jr nc,$+4 + res 1,b + rra + jr nc,$+4 + res 0,b + rra + jr nc,$+4 + res 3,b + rra + jr nc,$+4 + res 2,b + rra + jr nc,$+4 + res 1,c + rra + jr nc,$+4 + res 0,c + rra + jr nc,$+4 + res 3,c + rra + jr nc,$+4 + res 2,c + in a,($31) + rra + jr nc,$+4 + res 6,b + rra + jr nc,$+4 + res 7,b + rra + rra + rra + jr nc,$+4 + res 6,c + rra + jr nc,$+4 + res 7,c + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + in a,($31) ; Keyboard 1-8 + or a + ld c,$00 + jr nz,.key3 + in a,($35) + bit 0,a ; 9 + ld c,$09 + jr nz,.key5 + bit 1,a ; 0 + ld c,$00 + jr nz,.key5 + bit 7,a ; Backspace + ld c,$0a + jr nz,.key5 + in a,($30) + bit 7,a ; Enter + ld c,$0b + jr nz,.key5 + ld c,$0f + jr .key5 + +.key3: rra + inc c + jr nc,.key3 +.key5: + ld a,c + ld (key1_data),a + + endif + if MEMOTECH + ld bc,$ffff + + ld a,$fb + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 0,b ; Up direction. + bit 3,a ; Y + jr nz,$+4 + res 0,c ; Up direction. + + ld a,$ef + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 1,b ; Right key. + ld a,$bf + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 2,b ; Down key. + ld a,$f7 + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 3,b ; Left key. + ld a,$df + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a ; Home key. + jr nz,$+4 + res 6,b ; Button 1 + + ld a,$7F + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 2,a ; B + jr nz,$+4 + res 0,c ; Up key. + bit 1,a ; C + jr nz,$+4 + res 1,c ; Right key. + bit 3,a ; M + jr nz,$+4 + res 2,c ; Down key. + bit 0,a ; Z + jr nz,$+4 + res 3,c ; Left key. + bit 5,a ; - + jr nz,$+4 + res 7,c ; Button 2 for player 2. + bit 7,a ; - + jr nz,$+4 + res 7,b ; Button 2 for player 1. + in a,($06) ; Read keyboard data. + bit 0,a ; Space + jr nz,$+4 + res 6,c ; Button 1. + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$fe + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + ld b,1 + jr nc,.mt1 + rra + ld b,3 + jr nc,.mt1 + rra + ld b,5 + jr nc,.mt1 + rra + ld b,7 + jr nc,.mt1 + rra + ld b,9 + jr nc,.mt1 + ld a,$df + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + bit 6,a + ld b,11 + jr z,.mt1 + ld a,$fd + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + rra + ld b,2 + jr nc,.mt1 + rra + ld b,4 + jr nc,.mt1 + rra + ld b,6 + jr nc,.mt1 + rra + ld b,8 + jr nc,.mt1 + rra + ld b,0 + jr nc,.mt1 + in a,($06) + rra + ld b,10 + jr nc,.mt1 + ld b,15 +.mt1: + ld a,b + ld (key1_data),a + endif + if EINSTEIN + ld bc,$ffff + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 0,b ; Up + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 4,a + jr nz,$+4 + res 1,b ; Right + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + jr nz,$+4 + res 2,b ; Down + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + jr nz,$+4 + res 3,b ; Left + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 6,b ; Fire + ld a,$0e + out ($02),a + ld a,$7f + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 0,a + jr nz,$+4 + res 7,b ; 2nd fire + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$0e + out ($02),a + ld a,$ef + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + rra + ld b,7 + jr nc,.te1 + rra + ld b,6 + jr nc,.te1 + rra + ld b,5 + jr nc,.te1 + rra + ld b,4 + jr nc,.te1 + rra + ld b,3 + jr nc,.te1 + rra + ld b,2 + jr nc,.te1 + rra + ld b,1 + jr nc,.te1 + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + ld b,8 + jr z,.te1 + bit 4,a + ld b,10 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + ld b,9 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + ld b,11 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 7,a + ld b,0 + jr z,.te1 + ld b,15 +.te1: + ld a,b + ld (key1_data),a + endif + if PV2000 + ld bc,$ffff + ld a,7 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 0,b + bit 0,a + jr z,$+4 + res 3,b + ld a,6 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 1,b + bit 0,a + jr z,$+4 + res 2,b + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 0,a + jr z,$+4 + res 6,b + bit 1,a + jr z,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + ld a,0 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + and $0f + ld b,$04 + jr nz,.pv1 + in a,($10) + and $0f + ld b,$08 + jr nz,.pv1 + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($10) + ld b,11 + bit 0,a + jr nz,.pv2 + ld a,4 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + ld b,10 + bit 3,a + jr nz,.pv2 + in a,($10) + ld b,9 + bit 0,a + jr nz,.pv2 + ld b,0 + bit 3,a + jr nz,.pv2 + ld b,15 + jr .pv2 + +.pv1: rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b +.pv2: ld a,b + ld (key1_data),a + endif + if NABU + ld a,(nabu_data0) + and $cf + ld (joy1_data),a + ld a,(nabu_data1) + and $cf + ld (joy2_data),a + ld a,(nabu_data2) + ld (key1_data),a + ld a,$0f + ld (nabu_data2),a + endif + + if CVBASIC_MUSIC_PLAYER + ld a,(music_mode) + or a + call nz,music_hardware + endif + + ld hl,(frame) + inc hl + ld (frame),hl + + ld hl,lfsr ; Make LFSR more random + inc (hl) + inc (hl) + inc (hl) + + if CVBASIC_MUSIC_PLAYER + ; + ; Music is played with a 50hz clock. + ; + ld a,(ntsc) + or a + jr z,.2 + ld a,(music_tick) + inc a + cp 6 + jr nz,$+3 + xor a + ld (music_tick),a + jr z,.3 +.2: + ld a,(music_mode) + or a + call nz,music_generate +.3: + endif + + if CVBASIC_BANK_SWITCHING + pop af + if COLECO + ld l,a + ld h,$ff + ld a,(hl) + endif + if SG1000 + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + pop de + pop bc + pop hl + if COLECO + in a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + if SG1000+SVI+NABU + pop af + ei + reti + endif + if MSX + pop af + ret + endif + if SORD+MEMOTECH + pop af + ei + ret + +ctc_reti: + reti + endif + if EINSTEIN + pop af + ret + endif + if PV2000 + ld a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + + if NABU +keyboard_handler: + push af + push bc + push hl + in a,($90) + ld c,a + cp $0d ; Enter + ld a,11 + jr z,.8 + ld a,c + cp $7f ; Del + ld a,10 + jr z,.8 + ld a,c + cp $30 + jr c,.7 + cp $3a + jr nc,.7 + sub $30 +.8: ld (nabu_data2),a + jr .1 +.7: + cp $a0 + jr c,.2 + cp $c0 + jr c,.joystick +.2: + ld hl,nabu_data0 + cp $80 + jr nz,.3 + res 4,(hl) + jr .1 +.3: + cp $81 + jr nz,.4 + set 4,(hl) + jr .1 +.4: + cp $e0 + jr c,.1 + and $0f + ld b,2 + jr z,.5 + dec a + ld b,8 + jr z,.5 + dec a + ld b,1 + jr z,.5 + dec a + ld b,4 + jr z,.5 + dec a + ld b,$80 + jr z,.5 + dec a + ld b,$40 + jr nz,.1 +.5: bit 4,c + jr nz,.6 + ld a,(hl) + or b + ld (hl),a + jr .1 + +.6: + ld a,b + cpl + and (hl) + ld (hl),a + jr .1 + +.joystick: + ld hl,nabu_data0 + bit 4,(hl) + jr z,$+5 + ld hl,nabu_data1 + ld b,$00 + bit 3,c + jr z,$+4 + set 0,b + bit 2,c + jr z,$+4 + set 1,b + bit 1,c + jr z,$+4 + set 2,b + bit 0,c + jr z,$+4 + set 3,b + bit 4,c + jr z,$+4 + set 6,b + ld (hl),b +.1: + pop hl + pop bc + pop af + ei + reti + endif + if SORD +wait: + ld de,(frame) +.1: + ld hl,(frame) + or a + sbc hl,de + jr z,.1 + ret + endif + if EINSTEIN +wait: + in a,(VDP+1) + nop + in a,(VDP+1) + bit 7,a + jr z,$-4 + ld (vdp_status),a + jp nmi_handler + endif + + ; + ; The music player code comes from my + ; game Princess Quest for Colecovision (2012) + ; + + ; + ; Init music player. + ; +music_init: + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + ld a,$9f + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$bf + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$df + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ff + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ec + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + if COLECO+SG1000+MSX+SVI+SORD+MEMOTECH+PV2000 +MIX_BASE: equ $b8 + endif + if EINSTEIN+NABU +MIX_BASE: equ $78 + endif + if MSX+SVI+EINSTEIN+NABU + ld a,$08 + ld e,$00 + call WRTPSG + ld a,$09 + ld e,$00 + call WRTPSG + ld a,$0a + ld e,$00 + call WRTPSG + ld a,$07 + ld e,MIX_BASE + call WRTPSG + endif + if SGM + ld b,$08 + xor a + call ay3_reg + ld b,$09 + call ay3_reg + ld b,$0a + call ay3_reg + ld b,$07 + ld a,$b8 + call ay3_reg + endif + if CVBASIC_MUSIC_PLAYER + else + ret + endif + + if CVBASIC_MUSIC_PLAYER + ld a,$ff + ld (audio_vol4hw),a + ld a,$ec + ld (audio_control),a + ld a,MIX_BASE + ld (audio_mix),a + ld hl,music_silence + ; + ; Play a music. + ; HL = Pointer to music. + ; +music_play: + call nmi_off + ld a,(hl) + ld (music_timing),a + inc hl + ld (music_start),hl + ld (music_pointer),hl + xor a + ld (music_note_counter),a + inc a + ld (music_playing),a + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000 + ld a,($7fff) + endif + if MSX + ld a,($bfff) + endif + ld (music_bank),a + endif + jp nmi_on + + ; + ; Generates music. + ; +music_generate: + ld a,(audio_mix) + and $c0 + or $38 + ld (audio_mix),a + xor a ; Turn off all the sound channels. + ld l,a + ld h,a + ld (audio_vol1),hl ; audio_vol1/audio_vol2 + ld (audio_vol3),a + ld a,$ff + ld (audio_vol4hw),a + + ld a,(music_note_counter) + or a + jp nz,.6 + ld hl,(music_pointer) +.15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if COLECO + ld e,a + ld d,$ff + ld a,(de) + endif + if SG1000 + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.16 + ld e,d + ld d,0 + jr .17 + +.16: rlca + jr nc,.17 + ld e,0 +.17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.19: cp -3 ; Repeat music? + jp nz,.0 + ld hl,(music_start) + jr .15 + +.0: ld a,(music_timing) + and $3f ; Restart note time. + ld (music_note_counter),a + ld a,b + cp $3f ; Sustain? + jr z,.1 + rlca + rlca + and 3 + ld (music_instrument_1),a + ld a,b + and $3f + ld (music_note_1),a + xor a + ld (music_counter_1),a +.1: ld a,c + cp $3f + jr z,.2 + rlca + rlca + and 3 + ld (music_instrument_2),a + ld a,c + and $3f + ld (music_note_2),a + xor a + ld (music_counter_2),a +.2: ld a,d + cp $3f + jr z,.3 + rlca + rlca + and 3 + ld (music_instrument_3),a + ld a,d + and $3f + ld (music_note_3),a + xor a + ld (music_counter_3),a +.3: ld a,e + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + +.6: ld a,(music_note_1) + or a + jr z,.7 + ld bc,(music_instrument_1) + call music_note2freq + ld (audio_freq1),hl + ld (audio_vol1),a + +.7: ld a,(music_note_2) + or a + jr z,.8 + ld bc,(music_instrument_2) + call music_note2freq + ld (audio_freq2),hl + ld (audio_vol2),a + +.8: ld a,(music_note_3) + or a + jr z,.9 + ld bc,(music_instrument_3) + call music_note2freq + ld (audio_freq3),hl + ld (audio_vol3),a + +.9: ld a,(music_drum) + or a + jr z,.4 + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + cp 3 + jp nc,.4 +.10: ld a,5 + ld (audio_noise),a + call enable_drum + jr .4 + +.5: dec a ; 2 - Short durm. + jr nz,.11 + ld a,(music_counter_4) + or a + jp nz,.4 + ld a,8 + ld (audio_noise),a + call enable_drum + jr .4 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + cp 2 + jp c,.10 + cp b + jp c,.4 + dec a + dec a + cp b + jp c,.10 +.4: + ld a,(music_counter_1) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_1),a + + ld a,(music_counter_2) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_2),a + + ld a,(music_counter_3) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_3),a + + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + + ; + ; Converts note to frequency. + ; Input: + ; A = Note (1-62). + ; B = Instrument counter. + ; C = Instrument. + ; Output: + ; HL = Frequency. + ; A = Volume. + ; +music_note2freq: + add a,a + ld e,a + ld d,0 + ld hl,music_notes_table + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ld a,c + or a + jp z,music_piano + dec a + jp z,music_clarinet + dec a + jp z,music_flute + ; + ; Bass instrument. + ; +music_bass: + add hl,hl + + ; + ; Piano instrument. + ; +music_piano: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ret + +.1: + db 12,11,11,10,10,9,9,8 + db 8,7,7,6,6,5,5,4 + db 4,4,5,5,4,4,3,3 + + ; + ; Clarinet instrument. + ; +music_clarinet: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + srl h + rr l + jp nc,.2 + inc hl +.2: ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + + db 13,14,14,13,13,12,12,12 + db 11,11,11,11,12,12,12,12 + db 11,11,11,11,12,12,12,12 + + ; + ; Flute instrument. + ; +music_flute: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + + db 10,12,13,13,12,12,12,12 + db 11,11,11,11,10,10,10,10 + db 11,11,11,11,10,10,10,10 + + ; + ; Emit sound. + ; +music_hardware: + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.7 ; Yes, jump. + ld a,(audio_vol2) + or a + jp nz,.7 + ld a,(audio_vol3) + or a + jp z,.7 + ld (audio_vol2),a + xor a + ld (audio_vol3),a + ld hl,(audio_freq3) + ld (audio_freq2),hl +.7: + ld hl,(audio_freq1) + ld a,h + cp 4 + ld a,$9f + jp nc,.1 + ld a,l + and $0f + or $80 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol1) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $90 +.1: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld hl,(audio_freq2) + ld a,h + cp 4 + ld a,$bf + jp nc,.2 + ld a,l + and $0f + or $a0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol2) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $b0 +.2: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.6 ; Yes, jump. + + ld hl,(audio_freq3) + ld a,h + cp 4 + ld a,$df + jp nc,.3 + ld a,l + and $0f + or $c0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol3) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $d0 +.3: out (PSG),a + if MEMOTECH + in a,($03) + endif + +.6: + ld a,(music_mode) + and 1 ; NO DRUMS? + ret z ; Yes, return. + + ld a,(audio_vol4hw) + inc a + jr z,.4 + ld a,(audio_noise) + cp 16 + ld b,$ec + jp c,.5 + ld b,$ed +; ld b,$ee +.5: ld a,(audio_control) + cp b + jr z,.4 + ld a,b + ld (audio_control),a + out (PSG),a + if MEMOTECH + in a,($03) + endif +.4: ld a,(audio_vol4hw) + out (PSG),a + if MEMOTECH + in a,($03) + endif + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.8 ; Yes, jump. + ld hl,audio_freq1 + ld bc,$0b00 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret +.8: + ld hl,audio_freq1 + ld bc,$0400 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + inc hl + inc hl + inc c + inc c + ld a,(music_mode) + and 1 + jr z,.9 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + jr .10 +.9: inc hl + inc c + inc hl + inc c +.10: ld b,$02 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret + endif + + ; + ; Enable drum. + ; +enable_drum: + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + ld a,$f5 + ld (audio_vol4hw),a + else + ld hl,audio_mix + ld a,(audio_vol2) + or a + jr nz,.1 + ld a,10 + ld (audio_vol2),a + set 1,(hl) +.1: res 4,(hl) + endif + ret + + ; + ; Musical notes table. + ; +music_notes_table: + ; Silence - 0 + dw 0 + if MEMOTECH+EINSTEIN + ; Values for 4.00 mhz. + ; 2nd octave - Index 1 + dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 + ; 3rd octave - Index 13 + dw 956,902,851,804,758,716,676,638,602,568,536,506 + ; 4th octave - Index 25 + dw 478,451,426,402,379,358,338,319,301,284,268,253 + ; 5th octave - Index 37 + dw 239,225,213,201,190,179,169,159,150,142,134,127 + ; 6th octave - Index 49 + dw 119,113,106,100,95,89,84,80,75,71,67,63 + ; 7th octave - Index 61 + dw 60,56,53 + else + ; Values for 3.58 mhz. + ; 2nd octave - Index 1 + dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 + ; 3rd octave - Index 13 + dw 855,807,762,719,679,641,605,571,539,508,480,453 + ; 4th octave - Index 25 + dw 428,404,381,360,339,320,302,285,269,254,240,226 + ; 5th octave - Index 37 + dw 214,202,190,180,170,160,151,143,135,127,120,113 + ; 6th octave - Index 49 + dw 107,101,95,90,85,80,76,71,67,64,60,57 + ; 7th octave - Index 61 + dw 53,50,48 + endif + + if COLECO+SG1000+SORD+MEMOTECH+PV2000 + ; + ; Converts AY-3-8910 volume to SN76489 + ; +ay2sn: + db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 + endif + +music_silence: + db 8 + db 0,0,0,0 + db -2 + endif + + if CVBASIC_COMPRESSION +define_char_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + ld a,(mode) + and 8 + jp z,unpack3 + jp unpack + +define_color_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d +unpack3: + call .1 + call .1 +.1: + push de + push hl + call unpack + pop hl + pop de + ld a,d + add a,8 + ld d,a + ret + + ; + ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) + ; +unpack: +; Initialization + ld a,(hl) + inc hl + exx + ld de,0 + add a,a + inc a + rl e + add a,a + rl e + add a,a + rl e + rl e + ld hl,.modes + add hl,de + ld c,(hl) + inc hl + ld b,(hl) + push bc + pop ix + ld e,1 + exx + ld iy,.loop + +; Main depack loop +.literal: + ex af,af' + call nmi_off + ld a,(hl) + ex de,hl + call WRTVRM + ex de,hl + inc hl + inc de + call nmi_on + ex af,af' +.loop: add a,a + call z,.getbit + jr nc,.literal + +; Compressed data + exx + ld h,d + ld l,e +.getlen: add a,a + call z,.getbitexx + jr nc,.lenok +.lus: add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr nc,.lenok + add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr c,.lus +.lenok: inc hl + exx + ld c,(hl) + inc hl + ld b,0 + bit 7,c + jr z,.offsok + jp (ix) + +.mode6: add a,a + call z,.getbit + rl b +.mode5: add a,a + call z,.getbit + rl b +.mode4: add a,a + call z,.getbit + rl b +.mode3: add a,a + call z,.getbit + rl b +.mode2: add a,a + call z,.getbit + rl b + add a,a + call z,.getbit + jr nc,.offsok + or a + inc b + res 7,c +.offsok: inc bc + push hl + exx + push hl + exx + ld l,e + ld h,d + sbc hl,bc + pop bc + ex af,af' +.loop2: + call nmi_off + call RDVRM ; unpack + ex de,hl + call WRTVRM + ex de,hl ; 4 + call nmi_on + inc hl ; 6 + inc de ; 6 + dec bc ; 6 + ld a,b ; 4 + or c ; 4 + jr nz,.loop2 ; 10 + ex af,af' + pop hl + jp (iy) + +.getbit: ld a,(hl) + inc hl + rla + ret + +.getbitexx: + exx + ld a,(hl) + inc hl + exx + rla + ret + +.modes: + dw .offsok + dw .mode2 + dw .mode3 + dw .mode4 + dw .mode5 + dw .mode6 + + endif + +START: + if SVI+SG1000 + im 1 + endif + if MEMOTECH +Z80_CTC: equ $08 + endif + if EINSTEIN +Z80_CTC: equ $28 + endif + + if EINSTEIN+MEMOTECH + di + im 2 + ld a,rom_start>>8 + ld i,a + ld a,$03 ; Reset Z80 CTC + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + ld a,$08 ; Interrupt vector offset + out (Z80_CTC+0),a + endif + if MEMOTECH + ld a,$25 ; Disable channel 2 interrupt. + out (Z80_CTC+2),a + ld a,$9c + out (Z80_CTC+2),a + ld a,$25 ; Disable channel 1 interrupt. + out (Z80_CTC+1),a + ld a,$9c + out (Z80_CTC+1),a + ld a,$c5 ; Enable channel 0 interrupt (VDP). + out (Z80_CTC+0),a + ld a,$01 + out (Z80_CTC+0),a + endif + if SORD + ld hl,$186c ; Disable handling of CTC Channel 1 interruption. + ld ($7002),hl + ld hl,$7040 + set 0,(hl) ; Avoid BIOS VDP handling. + endif + if SVI + ld e,$00 + ld a,$08 + call WRTPSG + ld a,$09 + call WRTPSG + ld a,$0A + call WRTPSG + ld a,$07 + ld e,$b8 + call WRTPSG + ld a,$92 ; Setup 8255 for keyboard/joystick reading. + out ($97),a + endif + if SG1000 + ; Contributed by SiRioKD + ld a,$9F ; Turn off PSG + out (PSG),a + ld a,$BF + out (PSG),a + ld a,$DF + out (PSG),a + ld a,$FF + out (PSG),a + ld a,$92 ; Setup 8255 for SC3000. + out ($df),a + endif + if SG1000+SVI + ; Wait for VDP ready (around 1000 ms) + ld b,11 + ld de,$FFFF +.delay1: + ld hl,$39DE +.delay2: + add hl,de + jr c,.delay2 + djnz .delay1 + else + di + ld sp,STACK + endif + if NABU + im 2 + ld a,nabu_int>>8 + ld i,a + ld a,$03 ; Disable ROM + out ($00),a + ld a,$07 + out ($41),a + ld a,$78 ; Setup output ports and mixer. + out ($40),a + ld a,$0e + out ($41),a + ld a,$30 ; Enable video and keyboard. + out ($40),a + endif + if PV2000 + ld hl,nmi_handler + ld ($7499),hl + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + else + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + endif + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffc0) ; Megacart + endif + if SG1000 + ld a,1 ; Sega mapper + ld ($fffe),a + endif + if MSX + ld a,1 ; ASCII 16K + ld ($7000),a + endif + endif + if MEMOTECH+EINSTEIN+NABU + ld ix,(lfsr) + ld hl,ram_start + ld de,ram_start+1 + ld bc,ram_end-ram_start-1 + ld (hl),0 + ldir + ld (lfsr),ix + else + ld hl,(lfsr) ; Save RAM trash for random generator. + ld de,BASE_RAM + xor a + ld (de),a + inc de + if PV2000 + bit 7,d + else + bit 2,d + endif + jp z,$-4 + ld (lfsr),hl + endif + + if SGM +WRITE_REGISTER: equ $1fd9 +FILL_VRAM: equ $1f82 +WRITE_VRAM: equ $1fdf + + ld b,$00 ; First step. +.0: ld hl,$2000 ; RAM at $2000. +.1: ld (hl),h ; Try to write a byte. + inc h + jp p,.1 ; Repeat until reaching $8000. + ld h,$20 ; Go back at $2000. +.2: ld a,(hl) ; Read back byte. + cp h ; Is it correct? + jr nz,.3 ; No, jump. + inc h + jp p,.2 ; Repeat until reaching $8000. + jp .4 ; Memory valid! + +.3: ld a,$01 ; Enable SGM + out ($53),a + inc b + bit 1,b ; Already enabled? + jr z,.0 ; No, test RAM again. + + ld bc,$0000 + call WRITE_REGISTER + ld bc,$0180 + call WRITE_REGISTER + ld bc,$0206 + call WRITE_REGISTER + ld bc,$0380 + call WRITE_REGISTER + ld bc,$0400 + call WRITE_REGISTER + ld bc,$0536 + call WRITE_REGISTER + ld bc,$0607 + call WRITE_REGISTER + ld bc,$070D + call WRITE_REGISTER + ld bc,$03F0 + ld de,$00E8 + ld hl,$158B ; Note! direct access to Colecovision ROM + call WRITE_VRAM + ld hl,$2000 + ld de,32 + ld a,$FD + call FILL_VRAM + ld hl,$1B00 + ld de,128 + ld a,$D1 + call FILL_VRAM + ld hl,$1800 + ld de,769 + ld a,$20 + call FILL_VRAM + ld bc,$0020 + ld de,$1980 + ld hl,.5 + call WRITE_VRAM + ld bc,$01C0 + call WRITE_REGISTER + jr $ + +.5: db " SUPER GAME MODULE NOT DETECTED " + +.4: + ld ix,(lfsr) + ld hl,$2000 + ld de,$2001 + ld bc,$5FFF + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO + ld a,($0069) + cp 50 + ld a,1 + jr nz,$+3 + dec a + endif + if SG1000+SVI+SORD+PV2000+NABU + ld a,1 ; Always NTSC. + endif + if MEMOTECH+EINSTEIN + ld a,0 ; Always PAL. + endif + if MSX + call RSLREG + ld b,1 ; $4000-$7fff + call get_slot_mapping + ld h,$80 + call ENASLT ; Map into $8000-$BFFF + + ld a,($002b) + cpl + rlca + and $01 + endif + ld (ntsc),a + + call music_init + + xor a + ld (mode),a + + call mode_0 + + xor a + ld (joy1_data),a + ld (joy2_data),a + if NABU + ld (nabu_data0),a + ld (nabu_data1),a + endif + ld a,$0f + ld (key1_data),a + ld (key2_data),a + if NABU + ld (nabu_data2),a + endif + + if MSX + ld hl,nmi_handler + ld ($fd9b),hl + ld a,$c3 + ld ($fd9a),a + endif + if SORD + ld hl,nmi_handler + ld ($7006),hl + endif + + ; CVBasic program start. + ; ' + ; ' Brinquitos: Demo game + ; ' + ; ' by Oscar Toledo Gutiérrez + ; ' https://nanochess.org/ + ; ' + ; ' Creation date: Oct/06/2024. + ; ' + ; + ; CONST MAX_CLOUDS = 4 +const_MAX_CLOUDS: equ $0004 + ; + ; ' + ; ' Cloud information + ; ' + ; DIM cloud_x(MAX_CLOUDS) ' X-coordinate + ; DIM cloud_y(MAX_CLOUDS) ' Y-coordinate + ; DIM cloud_e(MAX_CLOUDS) ' State + ; + ; ' + ; ' Restart game + ; ' + ; restart_game: +cvb_RESTART_GAME: + ; ' Clear the screen + ; CLS + CALL cls + ; MODE 2 + CALL mode_2 + ; ' Blue background, green foreground + ; FOR c = 0 TO 31 + SUB A + LD (cvb_C),A +cv1: + ; VPOKE $2000 + c, $34 + LD HL,(cvb_C) + LD H,0 + LD DE,8192 + ADD HL,DE + LD A,52 + CALL NMI_OFF + CALL WRTVRM + CALL NMI_ON + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 32 + JP C,cv1 + ; ' Turquoise numbers. + ; VPOKE $2006, $74 + LD HL,8198 + LD A,116 + CALL NMI_OFF + CALL WRTVRM + CALL NMI_ON + ; VPOKE $2007, $74 + LD HL,8199 + LD A,116 + CALL NMI_OFF + CALL WRTVRM + CALL NMI_ON + ; + ; ' Define sprites + ; DEFINE SPRITE 0,4,sprites_bitmaps + LD HL,0 + PUSH HL + LD A,4 + LD HL,cvb_SPRITES_BITMAPS + CALL define_sprite + ; + ; #puntos = 0 + LD HL,0 + LD (cvb_#PUNTOS),HL + ; + ; ' Setup initial clouds + ; cloud_y(3) = 176 + LD A,176 + LD (array_CLOUD_Y+3),A + ; cloud_y(2) = 126 + LD A,126 + LD (array_CLOUD_Y+2),A + ; cloud_y(1) = 76 + LD A,76 + LD (array_CLOUD_Y+1),A + ; cloud_y(0) = 26 + LD A,26 + LD (array_CLOUD_Y),A + ; + ; cloud_x(3) = 128 + LD A,128 + LD (array_CLOUD_X+3),A + ; cloud_e(3) = 0 + SUB A + LD (array_CLOUD_E+3),A + ; + ; c = 2 + LD A,2 + LD (cvb_C),A + ; GOSUB setup_cloud + CALL cvb_SETUP_CLOUD + ; c = 1 + LD A,1 + LD (cvb_C),A + ; GOSUB setup_cloud + CALL cvb_SETUP_CLOUD + ; c = 0 + SUB A + LD (cvb_C),A + ; GOSUB setup_cloud + CALL cvb_SETUP_CLOUD + ; + ; ' Setup player + ; x = 128 ' X-coordinate + LD A,128 + LD (cvb_X),A + ; y = 160 ' Y-coordinate + LD A,160 + LD (cvb_Y),A + ; jump_state = 0 ' Jump state + SUB A + LD (cvb_JUMP_STATE),A + ; standing_on = 3 ' Standing on cloud 3 + LD A,3 + LD (cvb_STANDING_ON),A + ; + ; PLAY SIMPLE + LD A,3 + LD (music_mode),A + ; PLAY music_gladiators + LD HL,cvb_MUSIC_GLADIATORS + CALL music_play + ; + ; ' + ; ' Main loop + ; ' + ; main_loop: +cvb_MAIN_LOOP: + ; + ; ' + ; ' Jump sound effect. + ; ' + ; IF jump_state >= 33 THEN ' Jumping + LD A,(cvb_JUMP_STATE) + CP 33 + JP C,cv2 + ; f = 4 + LD A,4 + LD (cvb_F),A + ; SOUND 2, y, 12 + LD HL,(cvb_Y) + LD H,0 + LD A,$c0 + CALL sn76489_freq + LD A,12 + LD B,$d0 + CALL sn76489_vol + ; SOUND 7, y, 12 + LD HL,(cvb_Y) + LD H,0 + LD A,$04 + CALL ay3_freq + LD A,12 + LD B,$0a + CALL ay3_reg + ; ELSEIF jump_state THEN ' Falling + JP cv3 +cv2: + LD A,(cvb_JUMP_STATE) + OR A + JP Z,cv4 + ; f = 8 + LD A,8 + LD (cvb_F),A + ; SOUND 2, y, 12 + LD HL,(cvb_Y) + LD H,0 + LD A,$c0 + CALL sn76489_freq + LD A,12 + LD B,$d0 + CALL sn76489_vol + ; SOUND 7, y, 12 + LD HL,(cvb_Y) + LD H,0 + LD A,$04 + CALL ay3_freq + LD A,12 + LD B,$0a + CALL ay3_reg + ; ELSE ' Standing + JP cv3 +cv4: + ; f = 0 + SUB A + LD (cvb_F),A + ; SOUND 2, , 0 + SUB A + LD B,$d0 + CALL sn76489_vol + ; SOUND 7, , 0 + SUB A + LD B,$0a + CALL ay3_reg + ; END IF +cv3: + ; + ; ' Show the player sprite + ; SPRITE 0, y - 1, x - 8, f, 10 + SUB A + PUSH AF + LD A,(cvb_Y) + DEC A + PUSH AF + LD A,(cvb_X) + SUB 8 + PUSH AF + LD A,(cvb_F) + PUSH AF + LD A,10 + CALL update_sprite + ; + ; ' Show sprites for clouds + ; FOR c = 0 TO 3 + SUB A + LD (cvb_C),A +cv5: + ; SPRITE c + 1, cloud_y(c) - 1, cloud_x(c) - 8, 12, 15 + LD A,(cvb_C) + INC A + PUSH AF + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_Y + ADD HL,DE + LD A,(HL) + DEC A + PUSH AF + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + LD A,(HL) + SUB 8 + PUSH AF + LD A,12 + PUSH AF + LD A,15 + CALL update_sprite + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 4 + JP C,cv5 + ; + ; ' Video synchronization + ; WAIT + HALT + ; + ; ' Update score + ; PRINT AT 1,<>#puntos + LD HL,1 + LD (cursor),HL + LD HL,(cvb_#PUNTOS) + CALL print_number + ; + ; ' Detect if it should do vertical displacement... + ; ' ...of the screen. + ; IF y < 110 AND jump_state = 0 THEN + LD A,(cvb_JUMP_STATE) + AND A + LD A,0 + JR NZ,$+3 + DEC A + LD B,A + LD A,(cvb_Y) + CP 110 + LD A,0 + SBC A,A + AND B + JP Z,cv6 + ; y = y + 1 + LD HL,cvb_Y + INC (HL) + ; FOR c = 0 TO MAX_CLOUDS - 1 + SUB A + LD (cvb_C),A +cv7: + ; cloud_y(c) = cloud_y(c) + 1 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_Y + ADD HL,DE + INC (HL) + ; IF cloud_y(c) = 192 THEN + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_Y + ADD HL,DE + LD A,(HL) + CP 192 + JP NZ,cv8 + ; cloud_y(c) = -8 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_Y + ADD HL,DE + LD (HL),248 + ; GOSUB setup_cloud + CALL cvb_SETUP_CLOUD + ; END IF +cv8: + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 4 + JP C,cv7 + ; END IF +cv6: + ; + ; ' Detect if the player stands on a cloud + ; IF jump_state <> 0 AND jump_state < 33 AND standing_on = 255 THEN + LD A,(cvb_JUMP_STATE) + CP 33 + LD A,0 + SBC A,A + LD B,A + LD A,(cvb_JUMP_STATE) + AND A + LD A,0 + JR Z,$+3 + DEC A + AND B + LD B,A + LD A,(cvb_STANDING_ON) + CP 255 + LD A,0 + JR NZ,$+3 + DEC A + AND B + JP Z,cv9 + ; FOR c = 0 TO MAX_CLOUDS - 1 + SUB A + LD (cvb_C),A +cv10: + ; IF ABS(cloud_x(c) + 1 - x) < 8 AND ABS(cloud_y(c) - 16 - y) < 3 THEN + LD HL,(cvb_Y) + LD H,0 + PUSH HL + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_Y + ADD HL,DE + LD L,(HL) + LD H,0 + LD DE,65520 + ADD HL,DE + POP DE + OR A + SBC HL,DE + CALL _abs16 + LD DE,3 + OR A + SBC HL,DE + LD A,0 + SBC A,A + LD B,A + LD HL,(cvb_X) + LD H,0 + PUSH HL + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + LD L,(HL) + LD H,0 + INC HL + POP DE + OR A + SBC HL,DE + CALL _abs16 + LD DE,8 + OR A + SBC HL,DE + LD A,0 + SBC A,A + AND B + JP Z,cv11 + ; jump_state = 0 + SUB A + LD (cvb_JUMP_STATE),A + ; y = cloud_y(c) - 16 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_Y + ADD HL,DE + LD A,(HL) + SUB 16 + LD (cvb_Y),A + ; standing_on = c + LD A,(cvb_C) + LD (cvb_STANDING_ON),A + ; IF was_on <> standing_on THEN + LD B,A + LD A,(cvb_WAS_ON) + CP B + JP Z,cv12 + ; #puntos = #puntos + 1 + LD HL,(cvb_#PUNTOS) + INC HL + LD (cvb_#PUNTOS),HL + ; END IF +cv12: + ; END IF +cv11: + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 4 + JP C,cv10 + ; END IF +cv9: + ; + ; ' Move the clouds + ; FOR c = 0 TO MAX_CLOUDS - 1 + SUB A + LD (cvb_C),A +cv13: + ; IF cloud_e(c) = 1 THEN ' 1- Left + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_E + ADD HL,DE + LD A,(HL) + CP 1 + JP NZ,cv14 + ; IF standing_on = c THEN x = x - 2 + LD A,(cvb_C) + LD B,A + LD A,(cvb_STANDING_ON) + CP B + JP NZ,cv15 + LD HL,cvb_X + DEC (HL) + DEC (HL) +cv15: + ; cloud_x(c) = cloud_x(c) - 2 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + DEC (HL) + DEC (HL) + ; IF cloud_x(c) < 18 THEN cloud_e(c) = 2 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + LD A,(HL) + CP 18 + JP NC,cv16 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_E + ADD HL,DE + LD (HL),2 +cv16: + ; ELSEIF cloud_e(c) = 2 THEN ' 2- Right + JP cv17 +cv14: + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_E + ADD HL,DE + LD A,(HL) + CP 2 + JP NZ,cv18 + ; IF standing_on = c THEN x = x + 2 + LD A,(cvb_C) + LD B,A + LD A,(cvb_STANDING_ON) + CP B + JP NZ,cv19 + LD HL,cvb_X + INC (HL) + INC (HL) +cv19: + ; cloud_x(c) = cloud_x(c) + 2 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + INC (HL) + INC (HL) + ; IF cloud_x(c) > 238 THEN cloud_e(c) = 1 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + LD A,(HL) + CP 239 + JP C,cv20 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_E + ADD HL,DE + LD (HL),1 +cv20: + ; END IF +cv17: +cv18: + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 4 + JP C,cv13 + ; + ; ' Handle jumping. + ; IF jump_state THEN + LD A,(cvb_JUMP_STATE) + OR A + JP Z,cv21 + ; IF jump_state >= 33 THEN + LD A,(cvb_JUMP_STATE) + CP 33 + JP C,cv22 + ; jump_state = jump_state - 1 + LD HL,cvb_JUMP_STATE + DEC (HL) + ; y = y - 2 + LD HL,cvb_Y + DEC (HL) + DEC (HL) + ; ELSE + JP cv23 +cv22: + ; y = y + 2 + LD HL,cvb_Y + INC (HL) + INC (HL) + ; IF y = 200 OR y = 201 THEN GOTO end_of_game + LD A,(HL) + CP 201 + LD A,0 + JR NZ,$+3 + DEC A + LD B,A + LD A,(HL) + CP 200 + LD A,0 + JR NZ,$+3 + DEC A + OR B + JP Z,cv24 + JP cvb_END_OF_GAME +cv24: + ; END IF +cv23: + ; END IF +cv21: + ; + ; ' Jump if button pressed + ; IF cont.button THEN + LD HL,(joy1_data) + LD A,H + OR L + AND 64 + JP Z,cv25 + ; IF jump_state = 0 THEN + LD A,(cvb_JUMP_STATE) + AND A + JP NZ,cv26 + ; jump_state = 64 + LD A,64 + LD (cvb_JUMP_STATE),A + ; was_on = standing_on + LD A,(cvb_STANDING_ON) + LD (cvb_WAS_ON),A + ; standing_on = 255 + LD A,255 + LD (cvb_STANDING_ON),A + ; END IF +cv26: + ; END IF +cv25: + ; + ; GOTO main_loop + JP cvb_MAIN_LOOP + ; + ; ' + ; ' End of game + ; ' + ; end_of_game: +cvb_END_OF_GAME: + ; ' Turn off jumping sound effect + ; SOUND 2, , 0 + SUB A + LD B,$d0 + CALL sn76489_vol + ; SOUND 7, , 0 + SUB A + LD B,$0a + CALL ay3_reg + ; + ; ' Final music + ; PLAY music_end + LD HL,cvb_MUSIC_END + CALL music_play + ; + ; PRINT AT 135,"G A M E O V E R" + LD HL,135 + LD (cursor),HL + LD HL,cv27 + LD A,17 + CALL print_string + JP cv28 +cv27: + DB $47,$20,$41,$20,$4d,$20,$45,$20 + DB $20,$20,$4f,$20,$56,$20,$45,$20 + DB $52 +cv28: + ; + ; FOR c = 1 TO 240 + LD A,1 + LD (cvb_C),A +cv29: + ; WAIT + HALT + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 241 + JP C,cv29 + ; + ; GOTO restart_game + JP cvb_RESTART_GAME + ; + ; ' + ; ' Setup a cloud + ; ' + ; setup_cloud: PROCEDURE +cvb_SETUP_CLOUD: + ; + ; ' + ; ' Choose a position with margin of 32 pixels at each side. + ; ' Make sure the minimum distance of 64 pixels... + ; ' ...against the next cloud so the jump is possible. + ; ' + ; DO +cv30: + ; cloud_x(c) = RANDOM(96) * 2 + 32 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + PUSH HL + CALL random + LD DE,96 + CALL _mod16 + LD A,L + ADD A,A + ADD A,32 + POP HL + LD (HL),A + ; LOOP WHILE ABS(cloud_x(c) + 1 - cloud_x((c + 1) % MAX_CLOUDS)) < 64 + LD HL,(cvb_C) + LD H,0 + INC HL + LD A,L + AND 3 + LD L,A + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + LD L,(HL) + LD H,0 + PUSH HL + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_X + ADD HL,DE + LD L,(HL) + LD H,0 + INC HL + POP DE + OR A + SBC HL,DE + CALL _abs16 + LD DE,64 + OR A + SBC HL,DE + JP NC,cv32 + JP cv30 +cv32: + ; + ; ' Assign a movement direction. + ; cloud_e(c) = RANDOM(2) + 1 + LD HL,(cvb_C) + LD H,0 + LD DE,array_CLOUD_E + ADD HL,DE + PUSH HL + CALL random + LD A,L + AND 1 + INC A + POP HL + LD (HL),A + ; END + RET + ; + ; ' + ; ' Game sprites + ; ' + ; sprites_bitmaps: +cvb_SPRITES_BITMAPS: + ; BITMAP "................" ' Standing + ; BITMAP "................" + ; BITMAP "................" + ; BITMAP "......XXXX......" + ; BITMAP ".....XXXXXX....." + ; BITMAP "....XXXXXXXXX..." + ; BITMAP "...XX..XX..XX..." + ; BITMAP "...XX..XX..XX..." + ; BITMAP "..XXXXXXXXXXXX.." + ; BITMAP ".XXXXX.XX.XXXXX." + ; BITMAP "XX.X..XXXX..X.XX" + ; BITMAP "XX.XX......XX.XX" + ; BITMAP "XX.XXXXXXXXXX.XX" + ; BITMAP "XXX..XX..XX..XXX" + ; BITMAP "....XXX..XXX...." + ; BITMAP "...XXXX..XXXX..." + DB $00,$00,$00,$03,$07,$0f,$19,$19 + DB $3f,$7d,$d3,$d8,$df,$e6,$0e,$1e + DB $00,$00,$00,$c0,$e0,$f8,$98,$98 + DB $fc,$be,$cb,$1b,$fb,$67,$70,$78 + ; + ; BITMAP ".XX..........XX." ' Jumping + ; BITMAP "XXX..........XXX" + ; BITMAP "XXX...XXXX...XXX" + ; BITMAP ".XX..XXXXXX..XX." + ; BITMAP ".XX.X..XX..X.XX." + ; BITMAP ".X.XX..XX..XX.X." + ; BITMAP ".X.XXXXXXXXXX.X." + ; BITMAP "..XXXX.XX.XXXX.." + ; BITMAP "...X..XXXX..X..." + ; BITMAP "...XX..XX..XX..." + ; BITMAP "...XXX....XXX..." + ; BITMAP "...XXXXXXXXXX..." + ; BITMAP ".....XX..XX....." + ; BITMAP ".....XX..XX....." + ; BITMAP ".....XX..XX....." + ; BITMAP "....XXX..XXX...." + DB $60,$e0,$e3,$67,$69,$59,$5f,$3d + DB $13,$19,$1c,$1f,$06,$06,$06,$0e + DB $06,$07,$c7,$e6,$96,$9a,$fa,$bc + DB $c8,$98,$38,$f8,$60,$60,$60,$70 + ; + ; BITMAP ".XX..........XX." ' Falling + ; BITMAP "XXX...XXXX...XXX" + ; BITMAP ".XX..XXXXXX..XX." + ; BITMAP ".XX.X..XX..X.XX." + ; BITMAP ".X.XX..XX..XX.X." + ; BITMAP ".X.XXXXXXXXXX.X." + ; BITMAP "..XXXX.XX.XXXX.." + ; BITMAP "...XXXX..XXXX..." + ; BITMAP "...XX......XX..." + ; BITMAP "...XXX....XXX..." + ; BITMAP "...XXXXXXXXXX..." + ; BITMAP ".....XX..XX....." + ; BITMAP ".....XX..XX....." + ; BITMAP ".....XX..XX....." + ; BITMAP ".....XX..XX....." + ; BITMAP "....XXX..XXX...." + DB $60,$e3,$67,$69,$59,$5f,$3d,$1e + DB $18,$1c,$1f,$06,$06,$06,$06,$0e + DB $06,$c7,$e6,$96,$9a,$fa,$bc,$78 + DB $18,$38,$f8,$60,$60,$60,$60,$70 + ; + ; BITMAP "..XXX.XXX.X....." ' Cloud + ; BITMAP ".XXXXX.XXX.XX..." + ; BITMAP ".XXXXXX.XXX.XX.." + ; BITMAP "XXX..XX.XXX.XX.." + ; BITMAP "XX.XXX..XXX..X.." + ; BITMAP "..XXX.XX...XX..." + ; BITMAP ".XXXX.XXX.XXXX.." + ; BITMAP ".XXXX.XXX.XXXXX." + ; BITMAP "..XXXX..XX..XX.." + ; BITMAP "................" + ; BITMAP "................" + ; BITMAP "................" + ; BITMAP "................" + ; BITMAP "................" + ; BITMAP "................" + ; BITMAP "................" + DB $3b,$7d,$7e,$e6,$dc,$3b,$7b,$7b + DB $3c,$00,$00,$00,$00,$00,$00,$00 + DB $a0,$d8,$ec,$ec,$e4,$18,$bc,$be + DB $cc,$00,$00,$00,$00,$00,$00,$00 + ; + ; ' + ; ' Gladiators music (circus entry) + ; ' + ; music_gladiators: +cvb_MUSIC_GLADIATORS: + ; DATA BYTE 7 + DB $07 + ; MUSIC C5,C3,-,- + db $25,$0d,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC B4,G3,-,- + db $24,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC A4#,G2,-,- + db $23,$08,$00,$00 + ; MUSIC B4,S,-,- + db $24,$3f,$00,$00 + ; MUSIC A4#,G3,-,- + db $23,$14,$00,$00 + ; MUSIC A4,S,-,- + db $22,$3f,$00,$00 + ; + ; MUSIC G4#,C3,-,- + db $21,$0d,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC G4,G3,-,- + db $20,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC F4#,G2,-,- + db $1f,$08,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC G4,G3,-,- + db $20,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; + ; MUSIC A4,C3,-,- + db $22,$0d,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC G4#,G3,-,- + db $21,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC G4,G2,-,- + db $20,$08,$00,$00 + ; MUSIC G4#,S,-,- + db $21,$3f,$00,$00 + ; MUSIC G4,G3,-,- + db $20,$14,$00,$00 + ; MUSIC F4#,S,-,- + db $1f,$3f,$00,$00 + ; + ; MUSIC F4,C3,-,- + db $1e,$0d,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC E4,G3,-,- + db $1d,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC D4#,G2,-,- + db $1c,$08,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC E4,G3,-,- + db $1d,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; + ; MUSIC G4,B2,-,- + db $20,$0c,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC F4,G3,-,- + db $1e,$14,$00,$00 + ; MUSIC F4,S,-,- + db $1e,$3f,$00,$00 + ; MUSIC C4#,G2,-,- + db $1a,$08,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC D4,G3,-,- + db $1b,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; + ; MUSIC G4,B2,-,- + db $20,$0c,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC F4,G3,-,- + db $1e,$14,$00,$00 + ; MUSIC F4,S,-,- + db $1e,$3f,$00,$00 + ; MUSIC C4#,G2,-,- + db $1a,$08,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC D4,G3,-,- + db $1b,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; + ; MUSIC B3,B2,-,- + db $18,$0c,$00,$00 + ; MUSIC C4,S,-,- + db $19,$3f,$00,$00 + ; MUSIC C4S,G3,-,- + db $19,$14,$00,$00 + ; MUSIC D4,S,-,- + db $1b,$3f,$00,$00 + ; MUSIC D4S,G2,-,- + db $1b,$08,$00,$00 + ; MUSIC E4,S,-,- + db $1d,$3f,$00,$00 + ; MUSIC F4,G3,-,- + db $1e,$14,$00,$00 + ; MUSIC F4S,S,-,- + db $1e,$3f,$00,$00 + ; + ; MUSIC G4,B2,-,- + db $20,$0c,$00,$00 + ; MUSIC G4S,S,-,- + db $20,$3f,$00,$00 + ; MUSIC A4,G3,-,- + db $22,$14,$00,$00 + ; MUSIC B4,S,-,- + db $24,$3f,$00,$00 + ; MUSIC A4,G2,-,- + db $22,$08,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; MUSIC G4,G3,-,- + db $20,$14,$00,$00 + ; MUSIC S,S,-,- + db $3f,$3f,$00,$00 + ; + ; MUSIC REPEAT + db $fd,$00,$00,$00 + ; + ; ' + ; ' Music for end of game. + ; ' + ; music_end: +cvb_MUSIC_END: + ; DATA BYTE 20 + DB $14 + ; MUSIC C4,-,-,- + db $19,$00,$00,$00 + ; MUSIC G3,-,-,- + db $14,$00,$00,$00 + ; MUSIC C3,-,-,- + db $0d,$00,$00,$00 + ; MUSIC S,-,-,- + db $3f,$00,$00,$00 + ; MUSIC S,-,-,- + db $3f,$00,$00,$00 + ; MUSIC S,-,-,- + db $3f,$00,$00,$00 + ; MUSIC STOP + db $fe,$00,$00,$00 + ; + ; + ; CVBasic epilogue (BASIC compiler for Colecovision) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and + ; read_pointer variables. + ; Revision date: Mar/04/2024. Added music player. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/13/2024. Added Pletter decompressor. + ; Revision date: Mar/19/2024. Added support for sprite flicker. + ; Revision date: Apr/11/2024. Added support for Super Game Module. + ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. + ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it + ; can remain accessible in bank 0 (bank switching). + ; Revision date: Aug/02/2024. Added rom_end label for Memotech. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. + ; Revision date: Nov/12/2024. Added vdp_status. + ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. + ; + +rom_end: + + ; ROM final size rounding + if MSX+COLECO+SG1000+SVI+SORD + TIMES (($+$1FFF)&$1e000)-$ DB $ff + endif + if MEMOTECH+EINSTEIN+NABU + ; Align following data to a 256-byte page. + TIMES $100-($&$ff) DB $4f + endif + if PV2000 + TIMES $10000-$ DB $ff + endif + if SG1000 + forg $7FF0 + org $7FF0 + db "TMR SEGA" + db 0,0 + db 0,0 ; Checksum + db $11,$78 ; Product code + db $00 ; Version + db $4c ; SMS Export + 32KB for checksum + endif + if COLECO+SG1000+MSX+SVI+SORD+PV2000 + org BASE_RAM + endif +ram_start: + +sprites: + rb 128 +sprite_data: + rb 4 +frame: + rb 2 +read_pointer: + rb 2 +cursor: + rb 2 +lfsr: + rb 2 +mode: + rb 1 +flicker: + rb 1 +joy1_data: + rb 1 +joy2_data: + rb 1 +key1_data: + rb 1 +key2_data: + rb 1 +ntsc: + rb 1 +vdp_status: + rb 1 + if NABU +nabu_data0: rb 1 +nabu_data1: rb 1 +nabu_data2: rb 1 + endif + + if CVBASIC_MUSIC_PLAYER +music_tick: rb 1 +music_mode: rb 1 + + if CVBASIC_BANK_SWITCHING +music_bank: rb 1 + endif +music_start: rb 2 +music_pointer: rb 2 +music_playing: rb 1 +music_timing: rb 1 +music_note_counter: rb 1 +music_instrument_1: rb 1 +music_counter_1: rb 1 +music_note_1: rb 1 +music_instrument_2: rb 1 +music_counter_2: rb 1 +music_note_2: rb 1 +music_instrument_3: rb 1 +music_counter_3: rb 1 +music_note_3: rb 1 +music_counter_4: rb 1 +music_drum: rb 1 + +audio_freq1: rb 2 +audio_freq2: rb 2 +audio_freq3: rb 2 +audio_noise: rb 1 +audio_mix: rb 1 +audio_vol1: rb 1 +audio_vol2: rb 1 +audio_vol3: rb 1 + +audio_control: rb 1 +audio_vol4hw: rb 1 + endif + + if SGM + org $2000 ; Start for variables. + endif +cvb_C: rb 1 +cvb_F: rb 1 +cvb_X: rb 1 +cvb_Y: rb 1 +cvb_WAS_ON: rb 1 +cvb_STANDING_ON: rb 1 +cvb_JUMP_STATE: rb 1 +cvb_#PUNTOS: rb 2 +array_CLOUD_E: rb 4 +array_CLOUD_X: rb 4 +array_CLOUD_Y: rb 4 +ram_end: diff --git a/brinquitos.rom b/brinquitos.rom new file mode 100644 index 0000000000000000000000000000000000000000..5ee79972d748a473acbcde79b14d55f2cd96da20 GIT binary patch literal 32768 zcmeI0e{dV+na7`9$tzj1^&|9pa!rz5tEG--uF>r{nN+biN^xptE+L-KnrZJK{-c~z z?xuF9P!wW2YRgP?Ob9L|#6tryff7$H#pXw913Bl7L|n^Tal}42#)c4=i>7mlruK2p zs0HNvzPqv=(m$>@bAP_CweOGTdEW2)zMpsX?#dtiHNBDkr;5ci(IQWOcKMMKpE|qu zT4L&KrhDpa*R@!wlG}pHLbi$Kr$#fDB(jh5+ZM7rX#T?wXGU$OcWTsY#wYet<_a9# zzKZB3Z~VnnlAD_7ink)ZwZS(^lz%q$3^n4)WM3wHF28*~dzj8$cyP>p=WHgsNRo6s zyP49GWYvFb*Js`H&GS1idCrIA8;jv?7upg$ZB%PZrM{EXiixdoeIeV8B{GEg6-yxoRtX!g7 z(SVAvez+mOYqCwMDn?Xqe0aRE*0DF_G$M+0xh~1vU0lB1oo%HsRA)0+I&PtLJnd+j zpIunD?iLs7SM0$dS8|t}mLqzQ<=m>0{iU`1!#uw+%KT3*UzkdLQguFYax?BS;^Ja5(&BH8%wtr}9KL^-_+i-to zz17a-{MRm_mB~;ksXUQNEiEmUrKP2SzZO#C{hhUQDzWi^8tV&DtUuO2(7T7))R+|q zYb>S)2v-1gqJd7ea{w+?EkMvtcJL>q7K%0^H=+|noyop|@nk2dZF~X+wB3QWgjGh| zut!>YdkcX86%uo9w|kBvvBX>w_5%7NAwJ1Jyo{qKv>|R4yi{X+6h1$q0{$?pQ z+ZuybHZ#3!ggo^C?(dVi+&p##5Y#uii~G7vX7+uM-rOQi1PVsj;Uo*|&$VOi0ba z7RR*WSdVQd%%}iPk=tUIu;bj%iFexZNsw&A@K`^E+T$Jq`evFTahjF5)Z1{Hzk|M+vzWUUC4Iy>E{jf(2}OfkLVp zQ`HdqTZx#e;)Y>}iwy*jcXmR!vxOg8I2`TcQj!(azvgowzt!jD_OgvUS6n=IN$Jg` z9c1Ry63IcwVm4o<<>eqclLLndjzWlOq)HSr=5S_mgTuB}O9?VAz@`xkN=({M8!zOC z>>iR-I-YNkCW6plN#{mk9MBj{QM>s;8TbQ~x{B4Q6H5Aah09!&h=P>(%nYr=x->(T zuA3qHEL`TjzFzA#-<+M#Z!-^_e|zSv{xc?xCd}5_RT@>}@q@WrPo8R5Xp?P;KElSF z`XekDA|=sr3p4*E|7?1zi$|qzvx}W}(Tbuf6?GY|sf)_u%zN!K?{~~xEV@!(avL;t zapt|XJ}Gj~%=>G7?#SJSWLxCO9o$kL*>1?T#Sz)cEfk3w4sJ2qeV*E{to1n~>kOwI zQWjZblv%z9eBRnsYkf+j(ok%lD+d-Yys2b&$LY#uB{^ZMgd!5WiTWwC33n!tP2?xcyO0mA*B@ok!)*AC8gJc0EL`&t(;jB^_4U!m*l?{c`Z#MSDylT7KhA1h zR$ShF;oR)}$N3$`v8nyWSzI6BTEumgm-;KrxT?R*j1hg1X+NpJzW3-qhwu}urjHHk zM_GgZB*UXII>>VD+9pH|cC^xM*>LJ;d0ij7{Ppnd;nwiov(cY3SETIQ zpQlh6K(3*9v8a{}LMBuEG}TaE_XG<~Attv4>ha>1+MvsobLda8I4s97=F@ENvbCS> zh4nbB&#(uVt>ZxC*V8z05Z8=nU3~1moo{-6+U&_xc)cD^dAZx|aw$q# znbYaynZpqu`)501x9ixQRc3>^dh)m@ymu_LGa@-X*3-NANs(lyOxKr{K3`>JMFmv7 zUKGn^eC)rjllzPeNwRd~<*Be#tnMBpF2_sUfko%0>gbE0*5r-8#D*uDyx=|v&~>L+ z%}G`_z`BY~b5=N834duN{4FayCyhs6VGXsR=nJeEP_9nTc$IwgWj0c)#PP*I z%qz$;#sY43aC||zUHR{_r^|MfNoB7(?{{u+{=vZ<4?FI3eA)3w`CsJ|@{i=Z5&bl)JI!vvBSWn+>Ty=!se(s}cAC}q6xHd43QbXs`&R6(&$Ngx8&2)_ zf$SraMpSc#8AE!889n+qGq&r$X2uuvF=iz6^X!Ozju|pW%N`0~Vphoq=govZ%#410 z1VOJe!=b;%v%^g52xkAy9ete@wdwPfhEx9)s~f>o4VL|lY*Z+3W#5-=gEM=T8$8)7 za$51B$MD3pN_?aL%nnBoc*K%BVrd*%h>ozvh3GJQ$Gs5!6)=G{2&C%CbanTy1e`1&4lI6rMFKc`c zJ3Y5pbzwNaD|-jtWC#_mQ8&C2hSeY}ycFXu#q>|y2F2G)w+mnXI|1w&kYK}_qpz|N z1Yo6M+y+atob;_MZ4^C;j+aGClNHppC8?J53#`nrxAm$#HH=+TD0l)y-=aMe!-FU+129@{ec6`!*Hu6Qi@u zcCQIpZuo6?JY>1sIyZOsik5rAneLTZq2+IlBzw z^!p;(VYF*dY9+r~@~?%T$1k;ON`9^6SK-%6{Dnp{+mnvm)dHDt+xjLHHiO0 z$zQ#s_rLf<@K>Q<72>N=R-^xFK5j{m>#Jzjpv~7+Q_^3W|EB=)xhkIF!dwY4%U2Qg zrGFWTQV-`KHBy<=PR NR-%8uKNzR&{{tv9dsqMf literal 0 HcmV?d00001 diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index e35c884..1ef9353 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -35,7 +35,16 @@ rom_end: if PV2000 TIMES $10000-$ DB $ff endif - + if SG1000 + forg $7FF0 + org $7FF0 + db "TMR SEGA" + db 0,0 + db 0,0 ; Checksum + db $11,$78 ; Product code + db $00 ; Version + db $4c ; SMS Export + 32KB for checksum + endif if COLECO+SG1000+MSX+SVI+SORD+PV2000 org BASE_RAM endif From cf3165b151e998066e76fafcf1c5d92fa45a51d5 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 14 Apr 2025 12:38:33 -0600 Subject: [PATCH 016/155] Solved bug when compiling LEN, it didn't assign a type so it returned trash --- brinquitos.asm | 4856 ------------------------------------------------ brinquitos.rom | Bin 32768 -> 0 bytes cvbasic.c | 1 + 3 files changed, 1 insertion(+), 4856 deletions(-) delete mode 100644 brinquitos.asm delete mode 100644 brinquitos.rom diff --git a/brinquitos.asm b/brinquitos.asm deleted file mode 100644 index c998a2d..0000000 --- a/brinquitos.asm +++ /dev/null @@ -1,4856 +0,0 @@ - ; CVBasic compiler v0.8.0 Nov/12/2024 - ; Command: ./cvbasic --sg1000 examples/brinquitos.bas brinquitos.asm - ; Created: Mon Apr 14 12:13:08 2025 - -COLECO: equ 0 -SG1000: equ 1 -MSX: equ 0 -SGM: equ 0 -SVI: equ 0 -SORD: equ 0 -MEMOTECH: equ 0 -EINSTEIN: equ 0 -CPM: equ 0 -PENCIL: equ 0 -PV2000: equ 0 -TI99: equ 0 -NABU: equ 0 - -CVBASIC_MUSIC_PLAYER: equ 1 -CVBASIC_COMPRESSION: equ 0 -CVBASIC_BANK_SWITCHING: equ 0 - -BASE_RAM: equ $c000 ; Base of RAM -STACK: equ $c400 ; Base stack pointer -VDP: equ $be ; VDP port (write) -VDPR: equ $be ; VDP port (read) -PSG: equ $7f ; PSG port (write) - - ; - ; CVBasic prologue (BASIC compiler for Colecovision) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. - ; Added 16-bit multiply, division, modulo, and abs. - ; Added random generator. Added sound routines. - ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. - ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/14/2024. Added _sgn16. - ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. - ; Revision date: Apr/11/2024. Added support for formatting numbers. Added - ; support for Super Game Module. - ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. - ; Shorter mode setting subroutines. - ; Revision date: Apr/26/2024. Interruption handler saves current bank. - ; Revision date: Apr/27/2024. Music player now supports bank switching. - ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller - ; support with keyboard (code by SiRioKD) - ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. - ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. - ; Revision date: Jun/17/2024. Added SVI-328 support. - ; Revision date: Aug/01/2024. Added Sord M5 support. - ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech - ; support. - ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support - ; for Casio PV-2000. - ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, - ; and Casio PV-2000. - ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision - ; with flicker flag). - ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number - ; keys values were inverted. - ; Revision date: Nov/12/2024. Saves the VDP status. - ; - -JOYSEL: equ $c0 -KEYSEL: equ $80 - -JOY1: equ $fc-$20*SG1000 -JOY2: equ $ff-$22*SG1000 - - if COLECO - org $8000 - if PENCIL - db "COPYRIGHT SOUNDIC" - jp START - jp nmi_handler - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - db "CVBASIC!POWERED BY!2024!" - else - db $55,$aa - dw 0 - dw 0 - dw 0 - dw 0 - dw START - - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - - jp nmi_handler - endif - endif - if SG1000+SVI - org $0000 - di - ld sp,STACK - jp START - db $ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp nmi_handler ; It should be called int_handler. - endif - if MSX - ORG $4000 - db "AB" - dw START - dw $0000 - dw $0000 - dw $0000 - dw $0000 - -WRTPSG: equ $0093 -RDPSG: equ $0096 - - endif - if SORD - ORG $2000 - db $02 ; Avoid checking $4000 - dw START ; Start address. - dw $002e ; Prestart address (just point to RET in BIOS). - endif - if PV2000 - ORG $C000 - jp START - endif - - if MEMOTECH - if CPM - org $0100 - else - org $40fc - dw rom_start - dw rom_end-rom_start - endif -rom_start: - jp START - db 0,0,0,0,0 - dw nmi_handler - dw null_vector - dw null_vector - dw rom_start - -null_vector: - ei - reti - endif - if EINSTEIN - org $0100 -rom_start: - jp START - db 0,0,0,0,0 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - endif - if NABU - if CPM - org $0100 - else - org $140d - endif - nop - nop - nop - jp START - times $100-($&255) db $ff -nabu_int: - dw null_vector - dw null_vector - dw keyboard_handler - dw nmi_handler - dw null_vector - dw null_vector - dw null_vector - dw null_vector - -null_vector: - ei - reti - endif - - if SVI -WRTPSG: - out ($88),a - push af - ld a,e - out ($8c),a - pop af - ret - -RDPSG: - out ($88),a - push af - pop af - in a,($90) - ret - endif - - if EINSTEIN -WRTPSG: - out ($02),a - push af - ld a,e - out ($03),a - pop af - ret - -RDPSG: - out ($02),a - push af - pop af - in a,($02) - ret - endif - - if NABU -WRTPSG: - out ($41),a - push af - ld a,e - out ($40),a - pop af - ret - -RDPSG: - out ($41),a - push af - pop af - in a,($40) - ret - endif - - if PV2000 -WRTVDP: - ld a,b - ld (VDP+1),a - ld a,c - or $80 - ld (VDP+1),a - ret - -SETWRT: - ld a,l - ld (VDP+1),a - ld a,h - or $40 - ld (VDP+1),a - ret - -SETRD: - ld a,l - ld (VDP+1),a - ld a,h - and $3f - ld (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - ld (VDP),a - ret - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - ld a,(VDP) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: ld (VDP),a ; 13 14 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 37 42 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - ld a,(VDP) - ld (de),a - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - EX DE,HL - CALL SETWRT - EX DE,HL - DEC BC - INC C - LD A,B - LD B,C - INC A - LD C,A -.1: - LD A,(HL) ; 7 8 - LD (VDP),A ; 13 14 - INC HL ; 6 7 - DJNZ .1 ; 13 14 - DEC C ; 4 5 - JP NZ,.1 ; 10 11 - RET - else -WRTVDP: - ld a,b - out (VDP+1),a - ld a,c - or $80 - out (VDP+1),a - ret - -SETWRT: - ld a,l - out (VDP+1),a - ld a,h - or $40 - out (VDP+1),a - ret - -SETRD: - ld a,l - out (VDP+1),a - ld a,h - and $3f - out (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - out (VDP),a - ret - - if SG1000 - db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff - - ; Located at $0066 - ei ; NMI handler (pause button) - retn - endif - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - in a,(VDPR) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: out (VDP),a ; 11 12 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 35 40 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - in a,(VDP) - ld (de),a - if SORD - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - ex de,hl - call SETWRT - ex de,hl - dec bc - inc c - ld a,b - ld b,c - inc a - ld c,VDP -.1: - if SORD - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - outi - jp nz,.1 - dec a - jp nz,.1 - ret - endif - -LDIRVM3: - call .1 - call .1 -.1: push hl - push de - push bc - call LDIRVM - pop bc - pop de - ld a,d - add a,8 - ld d,a - pop hl - ret - -DISSCR: - call nmi_off - ld bc,$a201 - call WRTVDP - jp nmi_on - -ENASCR: - call nmi_off - ld bc,$e201 - call WRTVDP - jp nmi_on - -CPYBLK: - pop hl - ex af,af' - pop af - ld b,a - pop af - ld c,a - pop de - ex (sp),hl - call nmi_off -.1: push bc - push hl - push de - ld b,0 - call LDIRVM - pop hl - ld bc,$0020 - add hl,bc - ex de,hl - pop hl - ex af,af' - ld c,a - ld b,0 - add hl,bc - ex af,af' - pop bc - djnz .1 - jp nmi_on - -nmi_off: - if COLECO+PV2000 - push hl - ld hl,mode - set 0,(hl) - pop hl - endif - if SG1000+MSX+SVI+SORD+MEMOTECH+NABU - di - endif - ret - -nmi_on: - if COLECO+PV2000 - push af - push hl - ld hl,mode - res 0,(hl) - nop - bit 1,(hl) - jp nz,nmi_handler.0 - pop hl - pop af - endif - if SG1000+MSX+SVI+SORD+MEMOTECH+NABU - ei - endif - ret - - if COLECO -keypad_table: - db $0f,$08,$04,$05,$0c,$07,$0b,$02 - db $0d,$0a,$00,$09,$03,$01,$06,$0f - endif - -cls: - ld hl,$1800 - ld (cursor),hl - ld bc,$0300 - ld a,$20 - call nmi_off - call FILVRM - jp nmi_on - -print_string: - ld c,a - ld b,0 - ld de,(cursor) - ld a,d - and $07 - or $18 - ld d,a - push de - push bc - call nmi_off - call LDIRVM - call nmi_on - pop bc - pop hl - add hl,bc - ld (cursor),hl - ret - -print_number: - ld b,0 - call nmi_off -print_number5: - ld de,10000 - call print_digit -print_number4: - ld de,1000 - call print_digit -print_number3: - ld de,100 - call print_digit -print_number2: - ld de,10 - call print_digit -print_number1: - ld de,1 - ld b,e - call print_digit - jp nmi_on - -print_digit: - ld a,$2f - or a -.2: inc a - sbc hl,de - jp nc,.2 - add hl,de - cp $30 - jr nz,.3 - ld a,b - or a - ret z - dec a - jr z,.4 - ld a,c - jr .5 -.4: - ld a,$30 -.3: ld b,1 -.5: push hl - ld hl,(cursor) - ex af,af' - ld a,h - and $07 - or $18 - ld h,a - ex af,af' - call WRTVRM - inc hl - ld (cursor),hl - pop hl - ret - -define_sprite: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - ld h,$07 - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - ex de,hl - call nmi_off - call LDIRVM - jp nmi_on - -define_char: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - call nmi_off - ld a,(mode) - and 8 - jr nz,.1 - call LDIRVM3 - jp nmi_on - -.1: call LDIRVM - jp nmi_on - -define_color: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d - call nmi_off - call LDIRVM3 - jp nmi_on - -update_sprite: - pop bc - ld (sprite_data+3),a - pop af - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - push bc - ld de,sprites - add a,a - add a,a - if SORD - or $80 - endif - ld e,a - ld hl,sprite_data - ld bc,4 - ldir - ret - - ; Fast 16-bit multiplication. -_mul16: - ld b,h - ld c,l - ld a,16 - ld hl,0 -.1: - srl d - rr e - jr nc,.2 - add hl,bc -.2: sla c - rl b - dec a - jp nz,.1 - ret - - ; 16-bit signed modulo. - ; hl = hl % de -_mod16s: - ld a,h - or a - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _mod16 - pop af - ret p - jp _neg16 - - ; 16-bit signed division. - ; hl = hl / de -_div16s: - ld a,h - xor d - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _div16 - pop af - ret p - jp _neg16 - -_abs16: - bit 7,h - ret z -_neg16: - ld a,h - cpl - ld h,a - ld a,l - cpl - ld l,a - inc hl - ret - - ; Fast 16-bit division. - ; hl = hl / de -_div16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - rl c - rl b - ld h,b - ld l,c - ret - - ; Fast 16-bit modulo. -_mod16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - ret - -_sgn16: - ld a,h - or l - ret z - bit 7,h - ld hl,$ffff - ret nz - inc hl - inc hl - ret - - ; Random number generator. - ; From my game Mecha Eight. -random: - ld hl,(lfsr) - ld a,h - or l - jr nz,.0 - ld hl,$7811 -.0: ld a,h - and $80 - ld b,a - ld a,h - and $02 - rrca - rrca - xor b - ld b,a - ld a,h - and $01 - rrca - xor b - ld b,a - ld a,l - and $20 - rlca - rlca - xor b - rlca - rr h - rr l - ld (lfsr),hl - ret - -sn76489_freq: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - ld b,a - ld a,l - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - and $3f - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_vol: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - cpl - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_control: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - and $0f - or $e0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -ay3_reg: - if COLECO - push af - ld a,b - out ($50),a - pop af - out ($51),a - ret - endif - if SG1000+SORD+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,a - ld a,b - jp WRTPSG - endif - -ay3_freq: - if COLECO - out ($50),a - push af - ld a,l - out ($51),a - pop af - inc a - out ($50),a - push af - ld a,h - and $0f - out ($51),a - pop af - ret - endif - if SG1000+SORD+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,l - call WRTPSG - ld e,h - inc a - jp WRTPSG - endif - - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ; Required for SG1000 as it doesn't have a BIOS - ; Required for SVI because we don't have access to BIOS in cartridge. - ; Required for Sord M5 because it doesn't provide an ASCII charset. - ; Required for Memotech/Einstein because CP/M uses the memory. - ; My personal font for TMS9928. - ; - ; Patterned after the TMS9928 programming manual 6x8 letters - ; with better lowercase letters, also I made a proper - ; AT sign. - ; -font_bitmaps: - db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space - db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! - db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " - db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # - db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ - db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % - db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & - db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' - db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( - db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) - db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * - db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + - db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , - db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - - db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . - db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / - db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 - db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 - db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 - db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 - db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 - db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 - db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 - db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 - db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 - db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 - db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : - db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; - db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < - db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = - db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > - db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? - db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ - db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A - db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B - db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C - db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D - db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E - db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F - db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G - db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H - db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I - db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J - db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K - db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L - db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M - db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N - db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O - db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P - db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q - db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R - db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S - db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T - db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U - db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V - db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W - db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X - db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y - db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z - db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ - db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ - db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] - db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E - db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ - db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 - db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a - db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b - db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c - db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d - db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e - db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f - db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g - db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h - db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i - db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j - db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k - db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l - db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m - db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n - db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o - db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p - db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q - db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r - db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s - db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t - db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u - db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v - db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w - db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x - db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y - db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z - db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { - db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | - db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } - db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e - db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f - endif - -vdp_generic_mode: - call nmi_off - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0602 ; $1800 for pattern table. - call WRTVDP - ld b,d - ld c,$03 ; for color table. - call WRTVDP - ld b,e - ld c,$04 ; for bitmap table. - call WRTVDP - ld bc,$3605 ; $1b00 for sprite attribute table. - call WRTVDP - ld bc,$0706 ; $3800 for sprites bitmaps. - call WRTVDP - ld bc,$0107 - jp WRTVDP - -mode_0: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM3 - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - call cls -vdp_generic_sprites: - call nmi_off - ld hl,$1b00 - ld bc,$0080 - ld a,$d1 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,127 - ld (hl),$d1 - ldir - call nmi_on - call nmi_off - ld bc,$e201 ; Enable screen and interrupts. - call WRTVDP - jp nmi_on - -mode_1: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - ld hl,$0000 - ld bc,$1800 - xor a - call FILVRM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - ld hl,$1800 -.1: call nmi_off - ld b,32 -.2: ld a,l - call WRTVRM - inc hl - djnz .2 - call nmi_on - ld a,h - cp $1b - jp nz,.1 - jp vdp_generic_sprites - -mode_2: - ld hl,mode - set 3,(hl) - ld bc,$0000 - ld de,$8000 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$0020 - ld a,$f0 - call FILVRM - call nmi_on - call cls - jp vdp_generic_sprites - - if MSX -ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) -RSLREG: EQU $0138 ; Read slot status in A - - ; - ; Get slot mapping - ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) - ; A = Current slot selection status (CALL RSLREG) - ; -get_slot_mapping: - call rotate_slot - ld c,a - add a,$C1 ; EXPTBL - ld l,a - ld h,$FC - ld a,(hl) - and $80 ; Get expanded flag - or c - ld c,a - inc hl - inc hl - inc hl - inc hl - ld a,(hl) ; SLTTBL - call rotate_slot - rlca - rlca - or c ; A contains bit 7 = Marks expanded - ; bit 6 - 4 = Doesn't care - ; bit 3 - 2 = Secondary mapper - ; bit 1 - 0 = Primary mapper - ret - -rotate_slot: - push bc - dec b - inc b - jr z,.1 -.0: rrca - rrca - djnz .0 -.1: and 3 - pop bc - ret - - endif - -nmi_handler: - push af - push hl - ld hl,mode - bit 0,(hl) - jr z,.1 - set 1,(hl) - pop hl - pop af - retn - -.0: res 1,(hl) - -.1: push bc - push de - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000 - ld a,($7fff) - endif - if MSX - ld a,($bfff) - endif - push af - endif - if SORD+MEMOTECH - call ctc_reti - endif - if SG1000+MSX+SVI+SORD+MEMOTECH+NABU - in a,(VDPR+1) - ld (vdp_status),a - endif - ld bc,$8000+VDP - bit 2,(hl) - jr z,.4 - - ld hl,$1b00 - call SETWRT - ld hl,sprites -.7: - if PV2000 - ld a,(hl) - ld (VDP),a - inc hl - djnz .7 - else - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp nz,.7 - endif - jr .5 - -.4: - ld hl,$1b00 - call SETWRT - ld a,(flicker) - add a,$04 - ld (flicker),a - ld de,24 - ld b,128 - ld l,a - if SORD - else - ld h,sprites>>8 - endif -.6: - if SORD - set 7,l - ld h,sprites>>8 - else - res 7,l - endif - if PV2000 - ld a,(hl) ; 7 8 - ld (VDP),a ; 13 14 - inc hl ; 6 7 - dec b ; 4 5 - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - else - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - endif - add hl,de - jp nz,.6 -.5: - - if COLECO - out (JOYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - or $b0 - ld b,a - in a,(JOY2) - or $b0 - ld c,a - - out (KEYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - ld d,a - in a,(JOY2) - ld e,a - - ld a,d - rlca - or $7f - and b - cpl - ld (joy1_data),a - - ld a,e - rlca - or $7f - and c - cpl - ld (joy2_data),a - - ld a,d - and $0f - ld c,a - ld b,0 - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key1_data),a - - ld a,e - and $0f - ld c,a - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key2_data),a - endif - if SG1000 - ld a,$07 - out ($de),a - ld b,$ff - in a,(JOY1) - ld h,a - in a,(JOY2) - ld l,a - in a,($de) - cp 7 - jp nz,.sg1000 - - ld a,$00 - out ($de),a - in a,($dc) - rra - ld c,1 - jr nc,.sg1 - in a,($dd) - rra - ld c,8 - jr nc,.sg1 - ld a,$01 - out ($de),a - in a,($dc) - rra - ld c,2 - jr nc,.sg1 - in a,($dd) - rra - ld c,9 - jr nc,.sg1 - ld a,$02 - out ($de),a - in a,($dc) - rra - ld c,3 - jr nc,.sg1 - in a,($dd) - rra - ld c,0 - jr nc,.sg1 - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a - ld c,10 - jr z,.sg1 - rra - ld c,4 - jr nc,.sg1 - ld a,$04 - out ($de),a - in a,($dc) - rra - ld c,5 - jr nc,.sg1 - ld a,$05 - out ($de),a - in a,($dc) - bit 6,a - ld c,11 - jr z,.sg1 - rra - ld c,6 - jr nc,.sg1 - ld a,$06 - out ($de),a - in a,($dc) - rra - ld c,7 - jr nc,.sg1 - ld c,15 -.sg1: ld a,c - ld (key1_data),a - - ld a,$04 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard down. - jr nz,$+4 - res 1,h - ld a,$05 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard left. - jr nz,$+4 - res 2,h - ld a,$06 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard right. - jr nz,$+4 - res 3,h - bit 6,a ; Keyboard up. - jr nz,$+4 - res 0,h - ld a,$02 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Ins - jr nz,$+4 - res 4,h - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Del - jr nz,$+4 - res 5,h -.sg1000: - bit 0,h - jr nz,$+4 - res 0,b - bit 1,h - jr nz,$+4 - res 2,b - bit 2,h - jr nz,$+4 - res 3,b - bit 3,h - jr nz,$+4 - res 1,b - bit 4,h - jr nz,$+4 - res 6,b - bit 5,h - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - - ld a,$ff - bit 6,h - jr nz,$+4 - res 0,a - bit 7,h - jr nz,$+4 - res 2,a - - bit 0,l - jr nz,$+4 - res 3,a - bit 1,l - jr nz,$+4 - res 1,a - bit 2,l - jr nz,$+4 - res 4,a - bit 3,l - jr nz,$+4 - res 5,a - cpl - ld (joy2_data),a - - endif - if MSX - ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php - ld a,15 - call RDPSG - and $b0 - or $4f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - ld b,$ff - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy2_data),a - - in a,($aa) - and $f0 - or $00 - out ($aa),a - in a,($a9) - cp $ff - ld c,$ff - jr nz,.key1 - in a,($aa) - and $f0 - or $01 - out ($aa),a - in a,($a9) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - in a,($aa) - and $f0 - or $07 - out ($aa),a - in a,($a9) - bit 5,a ; BS - ld c,$0a - jr z,.key2 - bit 7,a ; RET - ld c,$0b - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - in a,($aa) - and $f0 - or $08 - out ($aa),a - in a,($a9) - bit 5,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 6,a - jr nz,$+4 - res 2,b - bit 4,a - jr nz,$+4 - res 3,b - bit 0,a - jr nz,$+4 - res 6,b - in a,($aa) - and $f0 - or $04 - out ($aa),a - in a,($a9) - bit 2,a - jr nz,$+4 - res 7,b - - ld a,15 - call RDPSG - and $b0 - or $0f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - - ld a,b - cpl - ld (joy1_data),a - endif - if SVI - ld a,14 - call RDPSG - ld b,$ff - bit 4,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 5,a - jr nz,$+4 - res 2,b - bit 6,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 5,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy2_data),a - - ld a,$10 - out ($96),a - in a,($99) - cp $ff - ld c,$ff - jr nz,.key1 - ld a,$11 - out ($96),a - in a,($99) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - ld a,$16 - out ($96),a - in a,($99) - bit 6,a - ld c,$0b - jr z,.key2 - ld a,$15 - out ($96),a - in a,($99) - bit 6,a - ld c,$0a - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - ld a,$15 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 0,b - ld a,$18 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 1,b - ld a,$17 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 2,b - ld a,$16 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 3,b - ld a,$18 - out ($96),a - in a,($99) - bit 0,a - jr nz,$+4 - res 6,b - ld a,$13 - out ($96),a - in a,($99) - bit 5,a - jr nz,$+4 - res 7,b - - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 4,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy1_data),a - endif - if SORD - ld bc,$ffff - in a,($37) ; Read joystick - rra - jr nc,$+4 - res 1,b - rra - jr nc,$+4 - res 0,b - rra - jr nc,$+4 - res 3,b - rra - jr nc,$+4 - res 2,b - rra - jr nc,$+4 - res 1,c - rra - jr nc,$+4 - res 0,c - rra - jr nc,$+4 - res 3,c - rra - jr nc,$+4 - res 2,c - in a,($31) - rra - jr nc,$+4 - res 6,b - rra - jr nc,$+4 - res 7,b - rra - rra - rra - jr nc,$+4 - res 6,c - rra - jr nc,$+4 - res 7,c - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - in a,($31) ; Keyboard 1-8 - or a - ld c,$00 - jr nz,.key3 - in a,($35) - bit 0,a ; 9 - ld c,$09 - jr nz,.key5 - bit 1,a ; 0 - ld c,$00 - jr nz,.key5 - bit 7,a ; Backspace - ld c,$0a - jr nz,.key5 - in a,($30) - bit 7,a ; Enter - ld c,$0b - jr nz,.key5 - ld c,$0f - jr .key5 - -.key3: rra - inc c - jr nc,.key3 -.key5: - ld a,c - ld (key1_data),a - - endif - if MEMOTECH - ld bc,$ffff - - ld a,$fb - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 0,b ; Up direction. - bit 3,a ; Y - jr nz,$+4 - res 0,c ; Up direction. - - ld a,$ef - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 1,b ; Right key. - ld a,$bf - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 2,b ; Down key. - ld a,$f7 - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 3,b ; Left key. - ld a,$df - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a ; Home key. - jr nz,$+4 - res 6,b ; Button 1 - - ld a,$7F - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 2,a ; B - jr nz,$+4 - res 0,c ; Up key. - bit 1,a ; C - jr nz,$+4 - res 1,c ; Right key. - bit 3,a ; M - jr nz,$+4 - res 2,c ; Down key. - bit 0,a ; Z - jr nz,$+4 - res 3,c ; Left key. - bit 5,a ; - - jr nz,$+4 - res 7,c ; Button 2 for player 2. - bit 7,a ; - - jr nz,$+4 - res 7,b ; Button 2 for player 1. - in a,($06) ; Read keyboard data. - bit 0,a ; Space - jr nz,$+4 - res 6,c ; Button 1. - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$fe - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - ld b,1 - jr nc,.mt1 - rra - ld b,3 - jr nc,.mt1 - rra - ld b,5 - jr nc,.mt1 - rra - ld b,7 - jr nc,.mt1 - rra - ld b,9 - jr nc,.mt1 - ld a,$df - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - bit 6,a - ld b,11 - jr z,.mt1 - ld a,$fd - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - rra - ld b,2 - jr nc,.mt1 - rra - ld b,4 - jr nc,.mt1 - rra - ld b,6 - jr nc,.mt1 - rra - ld b,8 - jr nc,.mt1 - rra - ld b,0 - jr nc,.mt1 - in a,($06) - rra - ld b,10 - jr nc,.mt1 - ld b,15 -.mt1: - ld a,b - ld (key1_data),a - endif - if EINSTEIN - ld bc,$ffff - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 0,b ; Up - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 4,a - jr nz,$+4 - res 1,b ; Right - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - jr nz,$+4 - res 2,b ; Down - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - jr nz,$+4 - res 3,b ; Left - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 6,b ; Fire - ld a,$0e - out ($02),a - ld a,$7f - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 0,a - jr nz,$+4 - res 7,b ; 2nd fire - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$0e - out ($02),a - ld a,$ef - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - rra - ld b,7 - jr nc,.te1 - rra - ld b,6 - jr nc,.te1 - rra - ld b,5 - jr nc,.te1 - rra - ld b,4 - jr nc,.te1 - rra - ld b,3 - jr nc,.te1 - rra - ld b,2 - jr nc,.te1 - rra - ld b,1 - jr nc,.te1 - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - ld b,8 - jr z,.te1 - bit 4,a - ld b,10 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - ld b,9 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - ld b,11 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 7,a - ld b,0 - jr z,.te1 - ld b,15 -.te1: - ld a,b - ld (key1_data),a - endif - if PV2000 - ld bc,$ffff - ld a,7 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 0,b - bit 0,a - jr z,$+4 - res 3,b - ld a,6 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 1,b - bit 0,a - jr z,$+4 - res 2,b - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 0,a - jr z,$+4 - res 6,b - bit 1,a - jr z,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - ld a,0 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - and $0f - ld b,$04 - jr nz,.pv1 - in a,($10) - and $0f - ld b,$08 - jr nz,.pv1 - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($10) - ld b,11 - bit 0,a - jr nz,.pv2 - ld a,4 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - ld b,10 - bit 3,a - jr nz,.pv2 - in a,($10) - ld b,9 - bit 0,a - jr nz,.pv2 - ld b,0 - bit 3,a - jr nz,.pv2 - ld b,15 - jr .pv2 - -.pv1: rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b -.pv2: ld a,b - ld (key1_data),a - endif - if NABU - ld a,(nabu_data0) - and $cf - ld (joy1_data),a - ld a,(nabu_data1) - and $cf - ld (joy2_data),a - ld a,(nabu_data2) - ld (key1_data),a - ld a,$0f - ld (nabu_data2),a - endif - - if CVBASIC_MUSIC_PLAYER - ld a,(music_mode) - or a - call nz,music_hardware - endif - - ld hl,(frame) - inc hl - ld (frame),hl - - ld hl,lfsr ; Make LFSR more random - inc (hl) - inc (hl) - inc (hl) - - if CVBASIC_MUSIC_PLAYER - ; - ; Music is played with a 50hz clock. - ; - ld a,(ntsc) - or a - jr z,.2 - ld a,(music_tick) - inc a - cp 6 - jr nz,$+3 - xor a - ld (music_tick),a - jr z,.3 -.2: - ld a,(music_mode) - or a - call nz,music_generate -.3: - endif - - if CVBASIC_BANK_SWITCHING - pop af - if COLECO - ld l,a - ld h,$ff - ld a,(hl) - endif - if SG1000 - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - pop de - pop bc - pop hl - if COLECO - in a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - if SG1000+SVI+NABU - pop af - ei - reti - endif - if MSX - pop af - ret - endif - if SORD+MEMOTECH - pop af - ei - ret - -ctc_reti: - reti - endif - if EINSTEIN - pop af - ret - endif - if PV2000 - ld a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - - if NABU -keyboard_handler: - push af - push bc - push hl - in a,($90) - ld c,a - cp $0d ; Enter - ld a,11 - jr z,.8 - ld a,c - cp $7f ; Del - ld a,10 - jr z,.8 - ld a,c - cp $30 - jr c,.7 - cp $3a - jr nc,.7 - sub $30 -.8: ld (nabu_data2),a - jr .1 -.7: - cp $a0 - jr c,.2 - cp $c0 - jr c,.joystick -.2: - ld hl,nabu_data0 - cp $80 - jr nz,.3 - res 4,(hl) - jr .1 -.3: - cp $81 - jr nz,.4 - set 4,(hl) - jr .1 -.4: - cp $e0 - jr c,.1 - and $0f - ld b,2 - jr z,.5 - dec a - ld b,8 - jr z,.5 - dec a - ld b,1 - jr z,.5 - dec a - ld b,4 - jr z,.5 - dec a - ld b,$80 - jr z,.5 - dec a - ld b,$40 - jr nz,.1 -.5: bit 4,c - jr nz,.6 - ld a,(hl) - or b - ld (hl),a - jr .1 - -.6: - ld a,b - cpl - and (hl) - ld (hl),a - jr .1 - -.joystick: - ld hl,nabu_data0 - bit 4,(hl) - jr z,$+5 - ld hl,nabu_data1 - ld b,$00 - bit 3,c - jr z,$+4 - set 0,b - bit 2,c - jr z,$+4 - set 1,b - bit 1,c - jr z,$+4 - set 2,b - bit 0,c - jr z,$+4 - set 3,b - bit 4,c - jr z,$+4 - set 6,b - ld (hl),b -.1: - pop hl - pop bc - pop af - ei - reti - endif - if SORD -wait: - ld de,(frame) -.1: - ld hl,(frame) - or a - sbc hl,de - jr z,.1 - ret - endif - if EINSTEIN -wait: - in a,(VDP+1) - nop - in a,(VDP+1) - bit 7,a - jr z,$-4 - ld (vdp_status),a - jp nmi_handler - endif - - ; - ; The music player code comes from my - ; game Princess Quest for Colecovision (2012) - ; - - ; - ; Init music player. - ; -music_init: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - ld a,$9f - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$bf - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$df - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ff - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ec - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - if COLECO+SG1000+MSX+SVI+SORD+MEMOTECH+PV2000 -MIX_BASE: equ $b8 - endif - if EINSTEIN+NABU -MIX_BASE: equ $78 - endif - if MSX+SVI+EINSTEIN+NABU - ld a,$08 - ld e,$00 - call WRTPSG - ld a,$09 - ld e,$00 - call WRTPSG - ld a,$0a - ld e,$00 - call WRTPSG - ld a,$07 - ld e,MIX_BASE - call WRTPSG - endif - if SGM - ld b,$08 - xor a - call ay3_reg - ld b,$09 - call ay3_reg - ld b,$0a - call ay3_reg - ld b,$07 - ld a,$b8 - call ay3_reg - endif - if CVBASIC_MUSIC_PLAYER - else - ret - endif - - if CVBASIC_MUSIC_PLAYER - ld a,$ff - ld (audio_vol4hw),a - ld a,$ec - ld (audio_control),a - ld a,MIX_BASE - ld (audio_mix),a - ld hl,music_silence - ; - ; Play a music. - ; HL = Pointer to music. - ; -music_play: - call nmi_off - ld a,(hl) - ld (music_timing),a - inc hl - ld (music_start),hl - ld (music_pointer),hl - xor a - ld (music_note_counter),a - inc a - ld (music_playing),a - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000 - ld a,($7fff) - endif - if MSX - ld a,($bfff) - endif - ld (music_bank),a - endif - jp nmi_on - - ; - ; Generates music. - ; -music_generate: - ld a,(audio_mix) - and $c0 - or $38 - ld (audio_mix),a - xor a ; Turn off all the sound channels. - ld l,a - ld h,a - ld (audio_vol1),hl ; audio_vol1/audio_vol2 - ld (audio_vol3),a - ld a,$ff - ld (audio_vol4hw),a - - ld a,(music_note_counter) - or a - jp nz,.6 - ld hl,(music_pointer) -.15: push hl - if CVBASIC_BANK_SWITCHING - ld a,(music_bank) - if COLECO - ld e,a - ld d,$ff - ld a,(de) - endif - if SG1000 - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - ld b,(hl) - inc hl - ld c,(hl) - inc hl - ld d,(hl) - inc hl - ld e,(hl) - pop hl - ld a,(music_timing) - rlca - jr nc,.16 - ld e,d - ld d,0 - jr .17 - -.16: rlca - jr nc,.17 - ld e,0 -.17: ld a,b ; Read first byte. - cp -2 ; End of music? - jr nz,.19 ; No, jump. - xor a ; Keep at same place. - ld (music_playing),a - ret - -.19: cp -3 ; Repeat music? - jp nz,.0 - ld hl,(music_start) - jr .15 - -.0: ld a,(music_timing) - and $3f ; Restart note time. - ld (music_note_counter),a - ld a,b - cp $3f ; Sustain? - jr z,.1 - rlca - rlca - and 3 - ld (music_instrument_1),a - ld a,b - and $3f - ld (music_note_1),a - xor a - ld (music_counter_1),a -.1: ld a,c - cp $3f - jr z,.2 - rlca - rlca - and 3 - ld (music_instrument_2),a - ld a,c - and $3f - ld (music_note_2),a - xor a - ld (music_counter_2),a -.2: ld a,d - cp $3f - jr z,.3 - rlca - rlca - and 3 - ld (music_instrument_3),a - ld a,d - and $3f - ld (music_note_3),a - xor a - ld (music_counter_3),a -.3: ld a,e - ld (music_drum),a - xor a - ld (music_counter_4),a - inc hl - inc hl - inc hl - ld a,(music_timing) - and $c0 - jr nz,.14 - inc hl -.14: ld (music_pointer),hl - -.6: ld a,(music_note_1) - or a - jr z,.7 - ld bc,(music_instrument_1) - call music_note2freq - ld (audio_freq1),hl - ld (audio_vol1),a - -.7: ld a,(music_note_2) - or a - jr z,.8 - ld bc,(music_instrument_2) - call music_note2freq - ld (audio_freq2),hl - ld (audio_vol2),a - -.8: ld a,(music_note_3) - or a - jr z,.9 - ld bc,(music_instrument_3) - call music_note2freq - ld (audio_freq3),hl - ld (audio_vol3),a - -.9: ld a,(music_drum) - or a - jr z,.4 - dec a ; 1 - Long drum. - jr nz,.5 - ld a,(music_counter_4) - cp 3 - jp nc,.4 -.10: ld a,5 - ld (audio_noise),a - call enable_drum - jr .4 - -.5: dec a ; 2 - Short durm. - jr nz,.11 - ld a,(music_counter_4) - or a - jp nz,.4 - ld a,8 - ld (audio_noise),a - call enable_drum - jr .4 - -.11: ;dec a ; 3 - Roll. - ;jp nz,.4 - ld a,(music_timing) - and $3e - rrca - ld b,a - ld a,(music_counter_4) - cp 2 - jp c,.10 - cp b - jp c,.4 - dec a - dec a - cp b - jp c,.10 -.4: - ld a,(music_counter_1) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_1),a - - ld a,(music_counter_2) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_2),a - - ld a,(music_counter_3) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_3),a - - ld hl,music_counter_4 - inc (hl) - ld hl,music_note_counter - dec (hl) - ret - - ; - ; Converts note to frequency. - ; Input: - ; A = Note (1-62). - ; B = Instrument counter. - ; C = Instrument. - ; Output: - ; HL = Frequency. - ; A = Volume. - ; -music_note2freq: - add a,a - ld e,a - ld d,0 - ld hl,music_notes_table - add hl,de - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - ld a,c - or a - jp z,music_piano - dec a - jp z,music_clarinet - dec a - jp z,music_flute - ; - ; Bass instrument. - ; -music_bass: - add hl,hl - - ; - ; Piano instrument. - ; -music_piano: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ret - -.1: - db 12,11,11,10,10,9,9,8 - db 8,7,7,6,6,5,5,4 - db 4,4,5,5,4,4,3,3 - - ; - ; Clarinet instrument. - ; -music_clarinet: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - srl h - rr l - jp nc,.2 - inc hl -.2: ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - - db 13,14,14,13,13,12,12,12 - db 11,11,11,11,12,12,12,12 - db 11,11,11,11,12,12,12,12 - - ; - ; Flute instrument. - ; -music_flute: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - - db 10,12,13,13,12,12,12,12 - db 11,11,11,11,10,10,10,10 - db 11,11,11,11,10,10,10,10 - - ; - ; Emit sound. - ; -music_hardware: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.7 ; Yes, jump. - ld a,(audio_vol2) - or a - jp nz,.7 - ld a,(audio_vol3) - or a - jp z,.7 - ld (audio_vol2),a - xor a - ld (audio_vol3),a - ld hl,(audio_freq3) - ld (audio_freq2),hl -.7: - ld hl,(audio_freq1) - ld a,h - cp 4 - ld a,$9f - jp nc,.1 - ld a,l - and $0f - or $80 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol1) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $90 -.1: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld hl,(audio_freq2) - ld a,h - cp 4 - ld a,$bf - jp nc,.2 - ld a,l - and $0f - or $a0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol2) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $b0 -.2: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.6 ; Yes, jump. - - ld hl,(audio_freq3) - ld a,h - cp 4 - ld a,$df - jp nc,.3 - ld a,l - and $0f - or $c0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol3) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $d0 -.3: out (PSG),a - if MEMOTECH - in a,($03) - endif - -.6: - ld a,(music_mode) - and 1 ; NO DRUMS? - ret z ; Yes, return. - - ld a,(audio_vol4hw) - inc a - jr z,.4 - ld a,(audio_noise) - cp 16 - ld b,$ec - jp c,.5 - ld b,$ed -; ld b,$ee -.5: ld a,(audio_control) - cp b - jr z,.4 - ld a,b - ld (audio_control),a - out (PSG),a - if MEMOTECH - in a,($03) - endif -.4: ld a,(audio_vol4hw) - out (PSG),a - if MEMOTECH - in a,($03) - endif - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.8 ; Yes, jump. - ld hl,audio_freq1 - ld bc,$0b00 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret -.8: - ld hl,audio_freq1 - ld bc,$0400 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - inc hl - inc hl - inc c - inc c - ld a,(music_mode) - and 1 - jr z,.9 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - jr .10 -.9: inc hl - inc c - inc hl - inc c -.10: ld b,$02 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret - endif - - ; - ; Enable drum. - ; -enable_drum: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - ld a,$f5 - ld (audio_vol4hw),a - else - ld hl,audio_mix - ld a,(audio_vol2) - or a - jr nz,.1 - ld a,10 - ld (audio_vol2),a - set 1,(hl) -.1: res 4,(hl) - endif - ret - - ; - ; Musical notes table. - ; -music_notes_table: - ; Silence - 0 - dw 0 - if MEMOTECH+EINSTEIN - ; Values for 4.00 mhz. - ; 2nd octave - Index 1 - dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 - ; 3rd octave - Index 13 - dw 956,902,851,804,758,716,676,638,602,568,536,506 - ; 4th octave - Index 25 - dw 478,451,426,402,379,358,338,319,301,284,268,253 - ; 5th octave - Index 37 - dw 239,225,213,201,190,179,169,159,150,142,134,127 - ; 6th octave - Index 49 - dw 119,113,106,100,95,89,84,80,75,71,67,63 - ; 7th octave - Index 61 - dw 60,56,53 - else - ; Values for 3.58 mhz. - ; 2nd octave - Index 1 - dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 - ; 3rd octave - Index 13 - dw 855,807,762,719,679,641,605,571,539,508,480,453 - ; 4th octave - Index 25 - dw 428,404,381,360,339,320,302,285,269,254,240,226 - ; 5th octave - Index 37 - dw 214,202,190,180,170,160,151,143,135,127,120,113 - ; 6th octave - Index 49 - dw 107,101,95,90,85,80,76,71,67,64,60,57 - ; 7th octave - Index 61 - dw 53,50,48 - endif - - if COLECO+SG1000+SORD+MEMOTECH+PV2000 - ; - ; Converts AY-3-8910 volume to SN76489 - ; -ay2sn: - db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 - endif - -music_silence: - db 8 - db 0,0,0,0 - db -2 - endif - - if CVBASIC_COMPRESSION -define_char_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - ld a,(mode) - and 8 - jp z,unpack3 - jp unpack - -define_color_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d -unpack3: - call .1 - call .1 -.1: - push de - push hl - call unpack - pop hl - pop de - ld a,d - add a,8 - ld d,a - ret - - ; - ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) - ; -unpack: -; Initialization - ld a,(hl) - inc hl - exx - ld de,0 - add a,a - inc a - rl e - add a,a - rl e - add a,a - rl e - rl e - ld hl,.modes - add hl,de - ld c,(hl) - inc hl - ld b,(hl) - push bc - pop ix - ld e,1 - exx - ld iy,.loop - -; Main depack loop -.literal: - ex af,af' - call nmi_off - ld a,(hl) - ex de,hl - call WRTVRM - ex de,hl - inc hl - inc de - call nmi_on - ex af,af' -.loop: add a,a - call z,.getbit - jr nc,.literal - -; Compressed data - exx - ld h,d - ld l,e -.getlen: add a,a - call z,.getbitexx - jr nc,.lenok -.lus: add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr nc,.lenok - add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr c,.lus -.lenok: inc hl - exx - ld c,(hl) - inc hl - ld b,0 - bit 7,c - jr z,.offsok - jp (ix) - -.mode6: add a,a - call z,.getbit - rl b -.mode5: add a,a - call z,.getbit - rl b -.mode4: add a,a - call z,.getbit - rl b -.mode3: add a,a - call z,.getbit - rl b -.mode2: add a,a - call z,.getbit - rl b - add a,a - call z,.getbit - jr nc,.offsok - or a - inc b - res 7,c -.offsok: inc bc - push hl - exx - push hl - exx - ld l,e - ld h,d - sbc hl,bc - pop bc - ex af,af' -.loop2: - call nmi_off - call RDVRM ; unpack - ex de,hl - call WRTVRM - ex de,hl ; 4 - call nmi_on - inc hl ; 6 - inc de ; 6 - dec bc ; 6 - ld a,b ; 4 - or c ; 4 - jr nz,.loop2 ; 10 - ex af,af' - pop hl - jp (iy) - -.getbit: ld a,(hl) - inc hl - rla - ret - -.getbitexx: - exx - ld a,(hl) - inc hl - exx - rla - ret - -.modes: - dw .offsok - dw .mode2 - dw .mode3 - dw .mode4 - dw .mode5 - dw .mode6 - - endif - -START: - if SVI+SG1000 - im 1 - endif - if MEMOTECH -Z80_CTC: equ $08 - endif - if EINSTEIN -Z80_CTC: equ $28 - endif - - if EINSTEIN+MEMOTECH - di - im 2 - ld a,rom_start>>8 - ld i,a - ld a,$03 ; Reset Z80 CTC - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - ld a,$08 ; Interrupt vector offset - out (Z80_CTC+0),a - endif - if MEMOTECH - ld a,$25 ; Disable channel 2 interrupt. - out (Z80_CTC+2),a - ld a,$9c - out (Z80_CTC+2),a - ld a,$25 ; Disable channel 1 interrupt. - out (Z80_CTC+1),a - ld a,$9c - out (Z80_CTC+1),a - ld a,$c5 ; Enable channel 0 interrupt (VDP). - out (Z80_CTC+0),a - ld a,$01 - out (Z80_CTC+0),a - endif - if SORD - ld hl,$186c ; Disable handling of CTC Channel 1 interruption. - ld ($7002),hl - ld hl,$7040 - set 0,(hl) ; Avoid BIOS VDP handling. - endif - if SVI - ld e,$00 - ld a,$08 - call WRTPSG - ld a,$09 - call WRTPSG - ld a,$0A - call WRTPSG - ld a,$07 - ld e,$b8 - call WRTPSG - ld a,$92 ; Setup 8255 for keyboard/joystick reading. - out ($97),a - endif - if SG1000 - ; Contributed by SiRioKD - ld a,$9F ; Turn off PSG - out (PSG),a - ld a,$BF - out (PSG),a - ld a,$DF - out (PSG),a - ld a,$FF - out (PSG),a - ld a,$92 ; Setup 8255 for SC3000. - out ($df),a - endif - if SG1000+SVI - ; Wait for VDP ready (around 1000 ms) - ld b,11 - ld de,$FFFF -.delay1: - ld hl,$39DE -.delay2: - add hl,de - jr c,.delay2 - djnz .delay1 - else - di - ld sp,STACK - endif - if NABU - im 2 - ld a,nabu_int>>8 - ld i,a - ld a,$03 ; Disable ROM - out ($00),a - ld a,$07 - out ($41),a - ld a,$78 ; Setup output ports and mixer. - out ($40),a - ld a,$0e - out ($41),a - ld a,$30 ; Enable video and keyboard. - out ($40),a - endif - if PV2000 - ld hl,nmi_handler - ld ($7499),hl - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - else - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - endif - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffc0) ; Megacart - endif - if SG1000 - ld a,1 ; Sega mapper - ld ($fffe),a - endif - if MSX - ld a,1 ; ASCII 16K - ld ($7000),a - endif - endif - if MEMOTECH+EINSTEIN+NABU - ld ix,(lfsr) - ld hl,ram_start - ld de,ram_start+1 - ld bc,ram_end-ram_start-1 - ld (hl),0 - ldir - ld (lfsr),ix - else - ld hl,(lfsr) ; Save RAM trash for random generator. - ld de,BASE_RAM - xor a - ld (de),a - inc de - if PV2000 - bit 7,d - else - bit 2,d - endif - jp z,$-4 - ld (lfsr),hl - endif - - if SGM -WRITE_REGISTER: equ $1fd9 -FILL_VRAM: equ $1f82 -WRITE_VRAM: equ $1fdf - - ld b,$00 ; First step. -.0: ld hl,$2000 ; RAM at $2000. -.1: ld (hl),h ; Try to write a byte. - inc h - jp p,.1 ; Repeat until reaching $8000. - ld h,$20 ; Go back at $2000. -.2: ld a,(hl) ; Read back byte. - cp h ; Is it correct? - jr nz,.3 ; No, jump. - inc h - jp p,.2 ; Repeat until reaching $8000. - jp .4 ; Memory valid! - -.3: ld a,$01 ; Enable SGM - out ($53),a - inc b - bit 1,b ; Already enabled? - jr z,.0 ; No, test RAM again. - - ld bc,$0000 - call WRITE_REGISTER - ld bc,$0180 - call WRITE_REGISTER - ld bc,$0206 - call WRITE_REGISTER - ld bc,$0380 - call WRITE_REGISTER - ld bc,$0400 - call WRITE_REGISTER - ld bc,$0536 - call WRITE_REGISTER - ld bc,$0607 - call WRITE_REGISTER - ld bc,$070D - call WRITE_REGISTER - ld bc,$03F0 - ld de,$00E8 - ld hl,$158B ; Note! direct access to Colecovision ROM - call WRITE_VRAM - ld hl,$2000 - ld de,32 - ld a,$FD - call FILL_VRAM - ld hl,$1B00 - ld de,128 - ld a,$D1 - call FILL_VRAM - ld hl,$1800 - ld de,769 - ld a,$20 - call FILL_VRAM - ld bc,$0020 - ld de,$1980 - ld hl,.5 - call WRITE_VRAM - ld bc,$01C0 - call WRITE_REGISTER - jr $ - -.5: db " SUPER GAME MODULE NOT DETECTED " - -.4: - ld ix,(lfsr) - ld hl,$2000 - ld de,$2001 - ld bc,$5FFF - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO - ld a,($0069) - cp 50 - ld a,1 - jr nz,$+3 - dec a - endif - if SG1000+SVI+SORD+PV2000+NABU - ld a,1 ; Always NTSC. - endif - if MEMOTECH+EINSTEIN - ld a,0 ; Always PAL. - endif - if MSX - call RSLREG - ld b,1 ; $4000-$7fff - call get_slot_mapping - ld h,$80 - call ENASLT ; Map into $8000-$BFFF - - ld a,($002b) - cpl - rlca - and $01 - endif - ld (ntsc),a - - call music_init - - xor a - ld (mode),a - - call mode_0 - - xor a - ld (joy1_data),a - ld (joy2_data),a - if NABU - ld (nabu_data0),a - ld (nabu_data1),a - endif - ld a,$0f - ld (key1_data),a - ld (key2_data),a - if NABU - ld (nabu_data2),a - endif - - if MSX - ld hl,nmi_handler - ld ($fd9b),hl - ld a,$c3 - ld ($fd9a),a - endif - if SORD - ld hl,nmi_handler - ld ($7006),hl - endif - - ; CVBasic program start. - ; ' - ; ' Brinquitos: Demo game - ; ' - ; ' by Oscar Toledo Gutiérrez - ; ' https://nanochess.org/ - ; ' - ; ' Creation date: Oct/06/2024. - ; ' - ; - ; CONST MAX_CLOUDS = 4 -const_MAX_CLOUDS: equ $0004 - ; - ; ' - ; ' Cloud information - ; ' - ; DIM cloud_x(MAX_CLOUDS) ' X-coordinate - ; DIM cloud_y(MAX_CLOUDS) ' Y-coordinate - ; DIM cloud_e(MAX_CLOUDS) ' State - ; - ; ' - ; ' Restart game - ; ' - ; restart_game: -cvb_RESTART_GAME: - ; ' Clear the screen - ; CLS - CALL cls - ; MODE 2 - CALL mode_2 - ; ' Blue background, green foreground - ; FOR c = 0 TO 31 - SUB A - LD (cvb_C),A -cv1: - ; VPOKE $2000 + c, $34 - LD HL,(cvb_C) - LD H,0 - LD DE,8192 - ADD HL,DE - LD A,52 - CALL NMI_OFF - CALL WRTVRM - CALL NMI_ON - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 32 - JP C,cv1 - ; ' Turquoise numbers. - ; VPOKE $2006, $74 - LD HL,8198 - LD A,116 - CALL NMI_OFF - CALL WRTVRM - CALL NMI_ON - ; VPOKE $2007, $74 - LD HL,8199 - LD A,116 - CALL NMI_OFF - CALL WRTVRM - CALL NMI_ON - ; - ; ' Define sprites - ; DEFINE SPRITE 0,4,sprites_bitmaps - LD HL,0 - PUSH HL - LD A,4 - LD HL,cvb_SPRITES_BITMAPS - CALL define_sprite - ; - ; #puntos = 0 - LD HL,0 - LD (cvb_#PUNTOS),HL - ; - ; ' Setup initial clouds - ; cloud_y(3) = 176 - LD A,176 - LD (array_CLOUD_Y+3),A - ; cloud_y(2) = 126 - LD A,126 - LD (array_CLOUD_Y+2),A - ; cloud_y(1) = 76 - LD A,76 - LD (array_CLOUD_Y+1),A - ; cloud_y(0) = 26 - LD A,26 - LD (array_CLOUD_Y),A - ; - ; cloud_x(3) = 128 - LD A,128 - LD (array_CLOUD_X+3),A - ; cloud_e(3) = 0 - SUB A - LD (array_CLOUD_E+3),A - ; - ; c = 2 - LD A,2 - LD (cvb_C),A - ; GOSUB setup_cloud - CALL cvb_SETUP_CLOUD - ; c = 1 - LD A,1 - LD (cvb_C),A - ; GOSUB setup_cloud - CALL cvb_SETUP_CLOUD - ; c = 0 - SUB A - LD (cvb_C),A - ; GOSUB setup_cloud - CALL cvb_SETUP_CLOUD - ; - ; ' Setup player - ; x = 128 ' X-coordinate - LD A,128 - LD (cvb_X),A - ; y = 160 ' Y-coordinate - LD A,160 - LD (cvb_Y),A - ; jump_state = 0 ' Jump state - SUB A - LD (cvb_JUMP_STATE),A - ; standing_on = 3 ' Standing on cloud 3 - LD A,3 - LD (cvb_STANDING_ON),A - ; - ; PLAY SIMPLE - LD A,3 - LD (music_mode),A - ; PLAY music_gladiators - LD HL,cvb_MUSIC_GLADIATORS - CALL music_play - ; - ; ' - ; ' Main loop - ; ' - ; main_loop: -cvb_MAIN_LOOP: - ; - ; ' - ; ' Jump sound effect. - ; ' - ; IF jump_state >= 33 THEN ' Jumping - LD A,(cvb_JUMP_STATE) - CP 33 - JP C,cv2 - ; f = 4 - LD A,4 - LD (cvb_F),A - ; SOUND 2, y, 12 - LD HL,(cvb_Y) - LD H,0 - LD A,$c0 - CALL sn76489_freq - LD A,12 - LD B,$d0 - CALL sn76489_vol - ; SOUND 7, y, 12 - LD HL,(cvb_Y) - LD H,0 - LD A,$04 - CALL ay3_freq - LD A,12 - LD B,$0a - CALL ay3_reg - ; ELSEIF jump_state THEN ' Falling - JP cv3 -cv2: - LD A,(cvb_JUMP_STATE) - OR A - JP Z,cv4 - ; f = 8 - LD A,8 - LD (cvb_F),A - ; SOUND 2, y, 12 - LD HL,(cvb_Y) - LD H,0 - LD A,$c0 - CALL sn76489_freq - LD A,12 - LD B,$d0 - CALL sn76489_vol - ; SOUND 7, y, 12 - LD HL,(cvb_Y) - LD H,0 - LD A,$04 - CALL ay3_freq - LD A,12 - LD B,$0a - CALL ay3_reg - ; ELSE ' Standing - JP cv3 -cv4: - ; f = 0 - SUB A - LD (cvb_F),A - ; SOUND 2, , 0 - SUB A - LD B,$d0 - CALL sn76489_vol - ; SOUND 7, , 0 - SUB A - LD B,$0a - CALL ay3_reg - ; END IF -cv3: - ; - ; ' Show the player sprite - ; SPRITE 0, y - 1, x - 8, f, 10 - SUB A - PUSH AF - LD A,(cvb_Y) - DEC A - PUSH AF - LD A,(cvb_X) - SUB 8 - PUSH AF - LD A,(cvb_F) - PUSH AF - LD A,10 - CALL update_sprite - ; - ; ' Show sprites for clouds - ; FOR c = 0 TO 3 - SUB A - LD (cvb_C),A -cv5: - ; SPRITE c + 1, cloud_y(c) - 1, cloud_x(c) - 8, 12, 15 - LD A,(cvb_C) - INC A - PUSH AF - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_Y - ADD HL,DE - LD A,(HL) - DEC A - PUSH AF - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - LD A,(HL) - SUB 8 - PUSH AF - LD A,12 - PUSH AF - LD A,15 - CALL update_sprite - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 4 - JP C,cv5 - ; - ; ' Video synchronization - ; WAIT - HALT - ; - ; ' Update score - ; PRINT AT 1,<>#puntos - LD HL,1 - LD (cursor),HL - LD HL,(cvb_#PUNTOS) - CALL print_number - ; - ; ' Detect if it should do vertical displacement... - ; ' ...of the screen. - ; IF y < 110 AND jump_state = 0 THEN - LD A,(cvb_JUMP_STATE) - AND A - LD A,0 - JR NZ,$+3 - DEC A - LD B,A - LD A,(cvb_Y) - CP 110 - LD A,0 - SBC A,A - AND B - JP Z,cv6 - ; y = y + 1 - LD HL,cvb_Y - INC (HL) - ; FOR c = 0 TO MAX_CLOUDS - 1 - SUB A - LD (cvb_C),A -cv7: - ; cloud_y(c) = cloud_y(c) + 1 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_Y - ADD HL,DE - INC (HL) - ; IF cloud_y(c) = 192 THEN - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_Y - ADD HL,DE - LD A,(HL) - CP 192 - JP NZ,cv8 - ; cloud_y(c) = -8 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_Y - ADD HL,DE - LD (HL),248 - ; GOSUB setup_cloud - CALL cvb_SETUP_CLOUD - ; END IF -cv8: - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 4 - JP C,cv7 - ; END IF -cv6: - ; - ; ' Detect if the player stands on a cloud - ; IF jump_state <> 0 AND jump_state < 33 AND standing_on = 255 THEN - LD A,(cvb_JUMP_STATE) - CP 33 - LD A,0 - SBC A,A - LD B,A - LD A,(cvb_JUMP_STATE) - AND A - LD A,0 - JR Z,$+3 - DEC A - AND B - LD B,A - LD A,(cvb_STANDING_ON) - CP 255 - LD A,0 - JR NZ,$+3 - DEC A - AND B - JP Z,cv9 - ; FOR c = 0 TO MAX_CLOUDS - 1 - SUB A - LD (cvb_C),A -cv10: - ; IF ABS(cloud_x(c) + 1 - x) < 8 AND ABS(cloud_y(c) - 16 - y) < 3 THEN - LD HL,(cvb_Y) - LD H,0 - PUSH HL - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_Y - ADD HL,DE - LD L,(HL) - LD H,0 - LD DE,65520 - ADD HL,DE - POP DE - OR A - SBC HL,DE - CALL _abs16 - LD DE,3 - OR A - SBC HL,DE - LD A,0 - SBC A,A - LD B,A - LD HL,(cvb_X) - LD H,0 - PUSH HL - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - LD L,(HL) - LD H,0 - INC HL - POP DE - OR A - SBC HL,DE - CALL _abs16 - LD DE,8 - OR A - SBC HL,DE - LD A,0 - SBC A,A - AND B - JP Z,cv11 - ; jump_state = 0 - SUB A - LD (cvb_JUMP_STATE),A - ; y = cloud_y(c) - 16 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_Y - ADD HL,DE - LD A,(HL) - SUB 16 - LD (cvb_Y),A - ; standing_on = c - LD A,(cvb_C) - LD (cvb_STANDING_ON),A - ; IF was_on <> standing_on THEN - LD B,A - LD A,(cvb_WAS_ON) - CP B - JP Z,cv12 - ; #puntos = #puntos + 1 - LD HL,(cvb_#PUNTOS) - INC HL - LD (cvb_#PUNTOS),HL - ; END IF -cv12: - ; END IF -cv11: - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 4 - JP C,cv10 - ; END IF -cv9: - ; - ; ' Move the clouds - ; FOR c = 0 TO MAX_CLOUDS - 1 - SUB A - LD (cvb_C),A -cv13: - ; IF cloud_e(c) = 1 THEN ' 1- Left - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_E - ADD HL,DE - LD A,(HL) - CP 1 - JP NZ,cv14 - ; IF standing_on = c THEN x = x - 2 - LD A,(cvb_C) - LD B,A - LD A,(cvb_STANDING_ON) - CP B - JP NZ,cv15 - LD HL,cvb_X - DEC (HL) - DEC (HL) -cv15: - ; cloud_x(c) = cloud_x(c) - 2 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - DEC (HL) - DEC (HL) - ; IF cloud_x(c) < 18 THEN cloud_e(c) = 2 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - LD A,(HL) - CP 18 - JP NC,cv16 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_E - ADD HL,DE - LD (HL),2 -cv16: - ; ELSEIF cloud_e(c) = 2 THEN ' 2- Right - JP cv17 -cv14: - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_E - ADD HL,DE - LD A,(HL) - CP 2 - JP NZ,cv18 - ; IF standing_on = c THEN x = x + 2 - LD A,(cvb_C) - LD B,A - LD A,(cvb_STANDING_ON) - CP B - JP NZ,cv19 - LD HL,cvb_X - INC (HL) - INC (HL) -cv19: - ; cloud_x(c) = cloud_x(c) + 2 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - INC (HL) - INC (HL) - ; IF cloud_x(c) > 238 THEN cloud_e(c) = 1 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - LD A,(HL) - CP 239 - JP C,cv20 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_E - ADD HL,DE - LD (HL),1 -cv20: - ; END IF -cv17: -cv18: - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 4 - JP C,cv13 - ; - ; ' Handle jumping. - ; IF jump_state THEN - LD A,(cvb_JUMP_STATE) - OR A - JP Z,cv21 - ; IF jump_state >= 33 THEN - LD A,(cvb_JUMP_STATE) - CP 33 - JP C,cv22 - ; jump_state = jump_state - 1 - LD HL,cvb_JUMP_STATE - DEC (HL) - ; y = y - 2 - LD HL,cvb_Y - DEC (HL) - DEC (HL) - ; ELSE - JP cv23 -cv22: - ; y = y + 2 - LD HL,cvb_Y - INC (HL) - INC (HL) - ; IF y = 200 OR y = 201 THEN GOTO end_of_game - LD A,(HL) - CP 201 - LD A,0 - JR NZ,$+3 - DEC A - LD B,A - LD A,(HL) - CP 200 - LD A,0 - JR NZ,$+3 - DEC A - OR B - JP Z,cv24 - JP cvb_END_OF_GAME -cv24: - ; END IF -cv23: - ; END IF -cv21: - ; - ; ' Jump if button pressed - ; IF cont.button THEN - LD HL,(joy1_data) - LD A,H - OR L - AND 64 - JP Z,cv25 - ; IF jump_state = 0 THEN - LD A,(cvb_JUMP_STATE) - AND A - JP NZ,cv26 - ; jump_state = 64 - LD A,64 - LD (cvb_JUMP_STATE),A - ; was_on = standing_on - LD A,(cvb_STANDING_ON) - LD (cvb_WAS_ON),A - ; standing_on = 255 - LD A,255 - LD (cvb_STANDING_ON),A - ; END IF -cv26: - ; END IF -cv25: - ; - ; GOTO main_loop - JP cvb_MAIN_LOOP - ; - ; ' - ; ' End of game - ; ' - ; end_of_game: -cvb_END_OF_GAME: - ; ' Turn off jumping sound effect - ; SOUND 2, , 0 - SUB A - LD B,$d0 - CALL sn76489_vol - ; SOUND 7, , 0 - SUB A - LD B,$0a - CALL ay3_reg - ; - ; ' Final music - ; PLAY music_end - LD HL,cvb_MUSIC_END - CALL music_play - ; - ; PRINT AT 135,"G A M E O V E R" - LD HL,135 - LD (cursor),HL - LD HL,cv27 - LD A,17 - CALL print_string - JP cv28 -cv27: - DB $47,$20,$41,$20,$4d,$20,$45,$20 - DB $20,$20,$4f,$20,$56,$20,$45,$20 - DB $52 -cv28: - ; - ; FOR c = 1 TO 240 - LD A,1 - LD (cvb_C),A -cv29: - ; WAIT - HALT - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 241 - JP C,cv29 - ; - ; GOTO restart_game - JP cvb_RESTART_GAME - ; - ; ' - ; ' Setup a cloud - ; ' - ; setup_cloud: PROCEDURE -cvb_SETUP_CLOUD: - ; - ; ' - ; ' Choose a position with margin of 32 pixels at each side. - ; ' Make sure the minimum distance of 64 pixels... - ; ' ...against the next cloud so the jump is possible. - ; ' - ; DO -cv30: - ; cloud_x(c) = RANDOM(96) * 2 + 32 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - PUSH HL - CALL random - LD DE,96 - CALL _mod16 - LD A,L - ADD A,A - ADD A,32 - POP HL - LD (HL),A - ; LOOP WHILE ABS(cloud_x(c) + 1 - cloud_x((c + 1) % MAX_CLOUDS)) < 64 - LD HL,(cvb_C) - LD H,0 - INC HL - LD A,L - AND 3 - LD L,A - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - LD L,(HL) - LD H,0 - PUSH HL - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_X - ADD HL,DE - LD L,(HL) - LD H,0 - INC HL - POP DE - OR A - SBC HL,DE - CALL _abs16 - LD DE,64 - OR A - SBC HL,DE - JP NC,cv32 - JP cv30 -cv32: - ; - ; ' Assign a movement direction. - ; cloud_e(c) = RANDOM(2) + 1 - LD HL,(cvb_C) - LD H,0 - LD DE,array_CLOUD_E - ADD HL,DE - PUSH HL - CALL random - LD A,L - AND 1 - INC A - POP HL - LD (HL),A - ; END - RET - ; - ; ' - ; ' Game sprites - ; ' - ; sprites_bitmaps: -cvb_SPRITES_BITMAPS: - ; BITMAP "................" ' Standing - ; BITMAP "................" - ; BITMAP "................" - ; BITMAP "......XXXX......" - ; BITMAP ".....XXXXXX....." - ; BITMAP "....XXXXXXXXX..." - ; BITMAP "...XX..XX..XX..." - ; BITMAP "...XX..XX..XX..." - ; BITMAP "..XXXXXXXXXXXX.." - ; BITMAP ".XXXXX.XX.XXXXX." - ; BITMAP "XX.X..XXXX..X.XX" - ; BITMAP "XX.XX......XX.XX" - ; BITMAP "XX.XXXXXXXXXX.XX" - ; BITMAP "XXX..XX..XX..XXX" - ; BITMAP "....XXX..XXX...." - ; BITMAP "...XXXX..XXXX..." - DB $00,$00,$00,$03,$07,$0f,$19,$19 - DB $3f,$7d,$d3,$d8,$df,$e6,$0e,$1e - DB $00,$00,$00,$c0,$e0,$f8,$98,$98 - DB $fc,$be,$cb,$1b,$fb,$67,$70,$78 - ; - ; BITMAP ".XX..........XX." ' Jumping - ; BITMAP "XXX..........XXX" - ; BITMAP "XXX...XXXX...XXX" - ; BITMAP ".XX..XXXXXX..XX." - ; BITMAP ".XX.X..XX..X.XX." - ; BITMAP ".X.XX..XX..XX.X." - ; BITMAP ".X.XXXXXXXXXX.X." - ; BITMAP "..XXXX.XX.XXXX.." - ; BITMAP "...X..XXXX..X..." - ; BITMAP "...XX..XX..XX..." - ; BITMAP "...XXX....XXX..." - ; BITMAP "...XXXXXXXXXX..." - ; BITMAP ".....XX..XX....." - ; BITMAP ".....XX..XX....." - ; BITMAP ".....XX..XX....." - ; BITMAP "....XXX..XXX...." - DB $60,$e0,$e3,$67,$69,$59,$5f,$3d - DB $13,$19,$1c,$1f,$06,$06,$06,$0e - DB $06,$07,$c7,$e6,$96,$9a,$fa,$bc - DB $c8,$98,$38,$f8,$60,$60,$60,$70 - ; - ; BITMAP ".XX..........XX." ' Falling - ; BITMAP "XXX...XXXX...XXX" - ; BITMAP ".XX..XXXXXX..XX." - ; BITMAP ".XX.X..XX..X.XX." - ; BITMAP ".X.XX..XX..XX.X." - ; BITMAP ".X.XXXXXXXXXX.X." - ; BITMAP "..XXXX.XX.XXXX.." - ; BITMAP "...XXXX..XXXX..." - ; BITMAP "...XX......XX..." - ; BITMAP "...XXX....XXX..." - ; BITMAP "...XXXXXXXXXX..." - ; BITMAP ".....XX..XX....." - ; BITMAP ".....XX..XX....." - ; BITMAP ".....XX..XX....." - ; BITMAP ".....XX..XX....." - ; BITMAP "....XXX..XXX...." - DB $60,$e3,$67,$69,$59,$5f,$3d,$1e - DB $18,$1c,$1f,$06,$06,$06,$06,$0e - DB $06,$c7,$e6,$96,$9a,$fa,$bc,$78 - DB $18,$38,$f8,$60,$60,$60,$60,$70 - ; - ; BITMAP "..XXX.XXX.X....." ' Cloud - ; BITMAP ".XXXXX.XXX.XX..." - ; BITMAP ".XXXXXX.XXX.XX.." - ; BITMAP "XXX..XX.XXX.XX.." - ; BITMAP "XX.XXX..XXX..X.." - ; BITMAP "..XXX.XX...XX..." - ; BITMAP ".XXXX.XXX.XXXX.." - ; BITMAP ".XXXX.XXX.XXXXX." - ; BITMAP "..XXXX..XX..XX.." - ; BITMAP "................" - ; BITMAP "................" - ; BITMAP "................" - ; BITMAP "................" - ; BITMAP "................" - ; BITMAP "................" - ; BITMAP "................" - DB $3b,$7d,$7e,$e6,$dc,$3b,$7b,$7b - DB $3c,$00,$00,$00,$00,$00,$00,$00 - DB $a0,$d8,$ec,$ec,$e4,$18,$bc,$be - DB $cc,$00,$00,$00,$00,$00,$00,$00 - ; - ; ' - ; ' Gladiators music (circus entry) - ; ' - ; music_gladiators: -cvb_MUSIC_GLADIATORS: - ; DATA BYTE 7 - DB $07 - ; MUSIC C5,C3,-,- - db $25,$0d,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC B4,G3,-,- - db $24,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC A4#,G2,-,- - db $23,$08,$00,$00 - ; MUSIC B4,S,-,- - db $24,$3f,$00,$00 - ; MUSIC A4#,G3,-,- - db $23,$14,$00,$00 - ; MUSIC A4,S,-,- - db $22,$3f,$00,$00 - ; - ; MUSIC G4#,C3,-,- - db $21,$0d,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC G4,G3,-,- - db $20,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC F4#,G2,-,- - db $1f,$08,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC G4,G3,-,- - db $20,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; - ; MUSIC A4,C3,-,- - db $22,$0d,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC G4#,G3,-,- - db $21,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC G4,G2,-,- - db $20,$08,$00,$00 - ; MUSIC G4#,S,-,- - db $21,$3f,$00,$00 - ; MUSIC G4,G3,-,- - db $20,$14,$00,$00 - ; MUSIC F4#,S,-,- - db $1f,$3f,$00,$00 - ; - ; MUSIC F4,C3,-,- - db $1e,$0d,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC E4,G3,-,- - db $1d,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC D4#,G2,-,- - db $1c,$08,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC E4,G3,-,- - db $1d,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; - ; MUSIC G4,B2,-,- - db $20,$0c,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC F4,G3,-,- - db $1e,$14,$00,$00 - ; MUSIC F4,S,-,- - db $1e,$3f,$00,$00 - ; MUSIC C4#,G2,-,- - db $1a,$08,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC D4,G3,-,- - db $1b,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; - ; MUSIC G4,B2,-,- - db $20,$0c,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC F4,G3,-,- - db $1e,$14,$00,$00 - ; MUSIC F4,S,-,- - db $1e,$3f,$00,$00 - ; MUSIC C4#,G2,-,- - db $1a,$08,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC D4,G3,-,- - db $1b,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; - ; MUSIC B3,B2,-,- - db $18,$0c,$00,$00 - ; MUSIC C4,S,-,- - db $19,$3f,$00,$00 - ; MUSIC C4S,G3,-,- - db $19,$14,$00,$00 - ; MUSIC D4,S,-,- - db $1b,$3f,$00,$00 - ; MUSIC D4S,G2,-,- - db $1b,$08,$00,$00 - ; MUSIC E4,S,-,- - db $1d,$3f,$00,$00 - ; MUSIC F4,G3,-,- - db $1e,$14,$00,$00 - ; MUSIC F4S,S,-,- - db $1e,$3f,$00,$00 - ; - ; MUSIC G4,B2,-,- - db $20,$0c,$00,$00 - ; MUSIC G4S,S,-,- - db $20,$3f,$00,$00 - ; MUSIC A4,G3,-,- - db $22,$14,$00,$00 - ; MUSIC B4,S,-,- - db $24,$3f,$00,$00 - ; MUSIC A4,G2,-,- - db $22,$08,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; MUSIC G4,G3,-,- - db $20,$14,$00,$00 - ; MUSIC S,S,-,- - db $3f,$3f,$00,$00 - ; - ; MUSIC REPEAT - db $fd,$00,$00,$00 - ; - ; ' - ; ' Music for end of game. - ; ' - ; music_end: -cvb_MUSIC_END: - ; DATA BYTE 20 - DB $14 - ; MUSIC C4,-,-,- - db $19,$00,$00,$00 - ; MUSIC G3,-,-,- - db $14,$00,$00,$00 - ; MUSIC C3,-,-,- - db $0d,$00,$00,$00 - ; MUSIC S,-,-,- - db $3f,$00,$00,$00 - ; MUSIC S,-,-,- - db $3f,$00,$00,$00 - ; MUSIC S,-,-,- - db $3f,$00,$00,$00 - ; MUSIC STOP - db $fe,$00,$00,$00 - ; - ; - ; CVBasic epilogue (BASIC compiler for Colecovision) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and - ; read_pointer variables. - ; Revision date: Mar/04/2024. Added music player. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/13/2024. Added Pletter decompressor. - ; Revision date: Mar/19/2024. Added support for sprite flicker. - ; Revision date: Apr/11/2024. Added support for Super Game Module. - ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. - ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it - ; can remain accessible in bank 0 (bank switching). - ; Revision date: Aug/02/2024. Added rom_end label for Memotech. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. - ; Revision date: Nov/12/2024. Added vdp_status. - ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. - ; - -rom_end: - - ; ROM final size rounding - if MSX+COLECO+SG1000+SVI+SORD - TIMES (($+$1FFF)&$1e000)-$ DB $ff - endif - if MEMOTECH+EINSTEIN+NABU - ; Align following data to a 256-byte page. - TIMES $100-($&$ff) DB $4f - endif - if PV2000 - TIMES $10000-$ DB $ff - endif - if SG1000 - forg $7FF0 - org $7FF0 - db "TMR SEGA" - db 0,0 - db 0,0 ; Checksum - db $11,$78 ; Product code - db $00 ; Version - db $4c ; SMS Export + 32KB for checksum - endif - if COLECO+SG1000+MSX+SVI+SORD+PV2000 - org BASE_RAM - endif -ram_start: - -sprites: - rb 128 -sprite_data: - rb 4 -frame: - rb 2 -read_pointer: - rb 2 -cursor: - rb 2 -lfsr: - rb 2 -mode: - rb 1 -flicker: - rb 1 -joy1_data: - rb 1 -joy2_data: - rb 1 -key1_data: - rb 1 -key2_data: - rb 1 -ntsc: - rb 1 -vdp_status: - rb 1 - if NABU -nabu_data0: rb 1 -nabu_data1: rb 1 -nabu_data2: rb 1 - endif - - if CVBASIC_MUSIC_PLAYER -music_tick: rb 1 -music_mode: rb 1 - - if CVBASIC_BANK_SWITCHING -music_bank: rb 1 - endif -music_start: rb 2 -music_pointer: rb 2 -music_playing: rb 1 -music_timing: rb 1 -music_note_counter: rb 1 -music_instrument_1: rb 1 -music_counter_1: rb 1 -music_note_1: rb 1 -music_instrument_2: rb 1 -music_counter_2: rb 1 -music_note_2: rb 1 -music_instrument_3: rb 1 -music_counter_3: rb 1 -music_note_3: rb 1 -music_counter_4: rb 1 -music_drum: rb 1 - -audio_freq1: rb 2 -audio_freq2: rb 2 -audio_freq3: rb 2 -audio_noise: rb 1 -audio_mix: rb 1 -audio_vol1: rb 1 -audio_vol2: rb 1 -audio_vol3: rb 1 - -audio_control: rb 1 -audio_vol4hw: rb 1 - endif - - if SGM - org $2000 ; Start for variables. - endif -cvb_C: rb 1 -cvb_F: rb 1 -cvb_X: rb 1 -cvb_Y: rb 1 -cvb_WAS_ON: rb 1 -cvb_STANDING_ON: rb 1 -cvb_JUMP_STATE: rb 1 -cvb_#PUNTOS: rb 2 -array_CLOUD_E: rb 4 -array_CLOUD_X: rb 4 -array_CLOUD_Y: rb 4 -ram_end: diff --git a/brinquitos.rom b/brinquitos.rom deleted file mode 100644 index 5ee79972d748a473acbcde79b14d55f2cd96da20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI0e{dV+na7`9$tzj1^&|9pa!rz5tEG--uF>r{nN+biN^xptE+L-KnrZJK{-c~z z?xuF9P!wW2YRgP?Ob9L|#6tryff7$H#pXw913Bl7L|n^Tal}42#)c4=i>7mlruK2p zs0HNvzPqv=(m$>@bAP_CweOGTdEW2)zMpsX?#dtiHNBDkr;5ci(IQWOcKMMKpE|qu zT4L&KrhDpa*R@!wlG}pHLbi$Kr$#fDB(jh5+ZM7rX#T?wXGU$OcWTsY#wYet<_a9# zzKZB3Z~VnnlAD_7ink)ZwZS(^lz%q$3^n4)WM3wHF28*~dzj8$cyP>p=WHgsNRo6s zyP49GWYvFb*Js`H&GS1idCrIA8;jv?7upg$ZB%PZrM{EXiixdoeIeV8B{GEg6-yxoRtX!g7 z(SVAvez+mOYqCwMDn?Xqe0aRE*0DF_G$M+0xh~1vU0lB1oo%HsRA)0+I&PtLJnd+j zpIunD?iLs7SM0$dS8|t}mLqzQ<=m>0{iU`1!#uw+%KT3*UzkdLQguFYax?BS;^Ja5(&BH8%wtr}9KL^-_+i-to zz17a-{MRm_mB~;ksXUQNEiEmUrKP2SzZO#C{hhUQDzWi^8tV&DtUuO2(7T7))R+|q zYb>S)2v-1gqJd7ea{w+?EkMvtcJL>q7K%0^H=+|noyop|@nk2dZF~X+wB3QWgjGh| zut!>YdkcX86%uo9w|kBvvBX>w_5%7NAwJ1Jyo{qKv>|R4yi{X+6h1$q0{$?pQ z+ZuybHZ#3!ggo^C?(dVi+&p##5Y#uii~G7vX7+uM-rOQi1PVsj;Uo*|&$VOi0ba z7RR*WSdVQd%%}iPk=tUIu;bj%iFexZNsw&A@K`^E+T$Jq`evFTahjF5)Z1{Hzk|M+vzWUUC4Iy>E{jf(2}OfkLVp zQ`HdqTZx#e;)Y>}iwy*jcXmR!vxOg8I2`TcQj!(azvgowzt!jD_OgvUS6n=IN$Jg` z9c1Ry63IcwVm4o<<>eqclLLndjzWlOq)HSr=5S_mgTuB}O9?VAz@`xkN=({M8!zOC z>>iR-I-YNkCW6plN#{mk9MBj{QM>s;8TbQ~x{B4Q6H5Aah09!&h=P>(%nYr=x->(T zuA3qHEL`TjzFzA#-<+M#Z!-^_e|zSv{xc?xCd}5_RT@>}@q@WrPo8R5Xp?P;KElSF z`XekDA|=sr3p4*E|7?1zi$|qzvx}W}(Tbuf6?GY|sf)_u%zN!K?{~~xEV@!(avL;t zapt|XJ}Gj~%=>G7?#SJSWLxCO9o$kL*>1?T#Sz)cEfk3w4sJ2qeV*E{to1n~>kOwI zQWjZblv%z9eBRnsYkf+j(ok%lD+d-Yys2b&$LY#uB{^ZMgd!5WiTWwC33n!tP2?xcyO0mA*B@ok!)*AC8gJc0EL`&t(;jB^_4U!m*l?{c`Z#MSDylT7KhA1h zR$ShF;oR)}$N3$`v8nyWSzI6BTEumgm-;KrxT?R*j1hg1X+NpJzW3-qhwu}urjHHk zM_GgZB*UXII>>VD+9pH|cC^xM*>LJ;d0ij7{Ppnd;nwiov(cY3SETIQ zpQlh6K(3*9v8a{}LMBuEG}TaE_XG<~Attv4>ha>1+MvsobLda8I4s97=F@ENvbCS> zh4nbB&#(uVt>ZxC*V8z05Z8=nU3~1moo{-6+U&_xc)cD^dAZx|aw$q# znbYaynZpqu`)501x9ixQRc3>^dh)m@ymu_LGa@-X*3-NANs(lyOxKr{K3`>JMFmv7 zUKGn^eC)rjllzPeNwRd~<*Be#tnMBpF2_sUfko%0>gbE0*5r-8#D*uDyx=|v&~>L+ z%}G`_z`BY~b5=N834duN{4FayCyhs6VGXsR=nJeEP_9nTc$IwgWj0c)#PP*I z%qz$;#sY43aC||zUHR{_r^|MfNoB7(?{{u+{=vZ<4?FI3eA)3w`CsJ|@{i=Z5&bl)JI!vvBSWn+>Ty=!se(s}cAC}q6xHd43QbXs`&R6(&$Ngx8&2)_ zf$SraMpSc#8AE!889n+qGq&r$X2uuvF=iz6^X!Ozju|pW%N`0~Vphoq=govZ%#410 z1VOJe!=b;%v%^g52xkAy9ete@wdwPfhEx9)s~f>o4VL|lY*Z+3W#5-=gEM=T8$8)7 za$51B$MD3pN_?aL%nnBoc*K%BVrd*%h>ozvh3GJQ$Gs5!6)=G{2&C%CbanTy1e`1&4lI6rMFKc`c zJ3Y5pbzwNaD|-jtWC#_mQ8&C2hSeY}ycFXu#q>|y2F2G)w+mnXI|1w&kYK}_qpz|N z1Yo6M+y+atob;_MZ4^C;j+aGClNHppC8?J53#`nrxAm$#HH=+TD0l)y-=aMe!-FU+129@{ec6`!*Hu6Qi@u zcCQIpZuo6?JY>1sIyZOsik5rAneLTZq2+IlBzw z^!p;(VYF*dY9+r~@~?%T$1k;ON`9^6SK-%6{Dnp{+mnvm)dHDt+xjLHHiO0 z$zQ#s_rLf<@K>Q<72>N=R-^xFK5j{m>#Jzjpv~7+Q_^3W|EB=)xhkIF!dwY4%U2Qg zrGFWTQV-`KHBy<=PR NR-%8uKNzR&{{tv9dsqMf diff --git a/cvbasic.c b/cvbasic.c index 8f2bd83..2ef8646 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -1656,6 +1656,7 @@ struct node *evaluate_level_7(int *type) emit_error("missing right parenthesis in LEN"); else get_lex(); + *type = TYPE_16; return node_create(N_NUM16, c, NULL, NULL); } if (strcmp(name, "POS") == 0) { /* Access to current screen position */ From 7d09044293fc6b2accf1fee1d6e2698d13504d93 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 14 Apr 2025 13:36:04 -0600 Subject: [PATCH 017/155] Correction in handling of strings inside DEF FN and replacement --- cvbasic.c | 48 +++++++++++++++++++++++----- examples/strings.bas | 74 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 examples/strings.bas diff --git a/cvbasic.c b/cvbasic.c index 2ef8646..f983693 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -648,8 +648,14 @@ void get_lex(void) { if (accumulated.length > 0) { --accumulated.length; lex = accumulated.definition[accumulated.length].lex; - strcpy(name, accumulated.definition[accumulated.length].name); value = accumulated.definition[accumulated.length].value; + if (lex == C_STRING) { + name_size = value; + if (name_size) + memcpy(name, accumulated.definition[accumulated.length].name, name_size); + } else { + strcpy(name, accumulated.definition[accumulated.length].name); + } free(accumulated.definition[accumulated.length].name); return; } @@ -1861,12 +1867,20 @@ void accumulated_push(enum lexical_component lex, int value, char *name) } accumulated.definition[accumulated.length].lex = lex; accumulated.definition[accumulated.length].value = value; - accumulated.definition[accumulated.length].name = malloc(strlen(name) + 1); + if (lex == C_STRING) + accumulated.definition[accumulated.length].name = malloc(value + 1); + else + accumulated.definition[accumulated.length].name = malloc(strlen(name) + 1); if (accumulated.definition[accumulated.length].name == NULL) { emit_error("out of memory in accumulated_push"); exit(1); } - strcpy(accumulated.definition[accumulated.length].name, name); + if (lex == C_STRING) { + if (value > 0) + memcpy(accumulated.definition[accumulated.length].name, name, value); + } else { + strcpy(accumulated.definition[accumulated.length].name, name); + } accumulated.length++; } @@ -1924,13 +1938,23 @@ int replace_macro(void) argument[c].max_length = (argument[c].max_length + 1) * 2; } argument[c].definition[argument[c].length].lex = lex; + if (lex == C_STRING) + value = name_size; argument[c].definition[argument[c].length].value = value; - argument[c].definition[argument[c].length].name = malloc(strlen(name) + 1); + if (lex == C_STRING) + argument[c].definition[argument[c].length].name = malloc(name_size + 1); + else + argument[c].definition[argument[c].length].name = malloc(strlen(name) + 1); if (argument[c].definition[argument[c].length].name == NULL) { emit_error("out of memory in call to FN"); return 1; } - strcpy(argument[c].definition[argument[c].length].name, name); + if (lex == C_STRING) { + if (name_size) + memcpy(argument[c].definition[argument[c].length].name, name, name_size); + } else { + strcpy(argument[c].definition[argument[c].length].name, name); + } argument[c].length++; get_lex(); } @@ -5183,13 +5207,23 @@ void compile_statement(int check_for_else) macro->max_length = (macro->max_length + 1) * 2; } macro->definition[macro->length].lex = lex; + if (lex == C_STRING) + value = name_size; macro->definition[macro->length].value = value; - macro->definition[macro->length].name = malloc(strlen(name) + 1); + if (lex == C_STRING) + macro->definition[macro->length].name = malloc(name_size + 1); + else + macro->definition[macro->length].name = malloc(strlen(name) + 1); if (macro->definition[macro->length].name == NULL) { emit_error("Out of memory in DEF FN"); break; } - strcpy(macro->definition[macro->length].name, name); + if (lex == C_STRING) { + if (value) + memcpy(macro->definition[macro->length].name, name, value); + } else { + strcpy(macro->definition[macro->length].name, name); + } macro->length++; get_lex(); } diff --git a/examples/strings.bas b/examples/strings.bas new file mode 100644 index 0000000..29e87e1 --- /dev/null +++ b/examples/strings.bas @@ -0,0 +1,74 @@ + ' + ' String handling in CVBASIC + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Apr/14/2025. + ' + + ' + ' CVBasic doesn't support directly strings, but enough + ' support to provide the data and do processing. + ' + + ' This is a macro, CVBasic doesn't process strings + DEF FN center_string(pos, str) = PRINT AT pos - LEN(str)/2, str + + DEF FN wait_for_button(a) = FOR c = 0 TO 15:WAIT:NEXT:DO:WAIT:LOOP WHILE cont.button = 0 + + DEF FN get_string(where, num) = RESTORE where: c = num: WHILE c > 0: DO: READ BYTE char: LOOP WHILE char <> 0: c = c - 1: WEND + + DEF FN print_string(a) = WHILE 1: READ BYTE char: IF char <> 0 THEN PRINT " ": VPOKE $1800 + POS(0) - 1, char: WEND + + WHILE 1 + + CLS + + center_string(80, "Hello, World!") + + wait_for_button(0) + + CLS + + get_string(messages_1, RANDOM(10)) + + print_string(0) + + get_string(messages_2, RANDOM(5)) + + print_string(0) + + get_string(messages_3, RANDOM(5)) + + print_string(0) + + wait_for_button(0) + + WEND + +messages_1: + DATA BYTE "William",0 + DATA BYTE "Olivia",0 + DATA BYTE "Jack",0 + DATA BYTE "Amelia",0 + DATA BYTE "Michael",0 + DATA BYTE "Eleanor",0 + DATA BYTE "Noah",0 + DATA BYTE "Lily",0 + DATA BYTE "James",0 + DATA BYTE "Emma",0 + +messages_2: + DATA BYTE " likes ",0 + DATA BYTE " dislikes ",0 + DATA BYTE " loves ",0 + DATA BYTE " hates ",0 + DATA BYTE " enjoys ",0 + +messages_3: + DATA BYTE "frogs",0 + DATA BYTE "horses",0 + DATA BYTE "dogs",0 + DATA BYTE "cats",0 + DATA BYTE "turtles",0 From 9e0f6e34b9c113e2892926f5dbeeca5a0eabec40 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 26 Apr 2025 17:49:31 -0600 Subject: [PATCH 018/155] Optimizes with DI/EI in some platforms. Added CHR for PRINT. Mode 4 for Sega Master System (only text subsystem currently) --- cvbasic.c | 231 ++++++++++++------------ cvbasic.h | 47 +++++ cvbasic_6502_prologue.asm | 6 +- cvbasic_9900_prologue.asm | 4 +- cvbasic_epilogue.asm | 10 +- cvbasic_prologue.asm | 361 ++++++++++++++++++++++++++++++++------ driver.c | 33 +++- driver.h | 2 + examples/strings.bas | 2 +- manual.txt | 20 ++- 10 files changed, 538 insertions(+), 178 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index f983693..26b73dd 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3,7 +3,7 @@ ** ** by Oscar Toledo G. ** - ** © Copyright 2024 Óscar Toledo G. + ** © Copyright 2024-2025 Óscar Toledo G. ** https://nanochess.org/ ** ** Creation date: Feb/27/2024. @@ -11,6 +11,7 @@ ** Revision date: Feb/29/2024. Implemented controller support. Added arrays, SOUND, ** RESTORE/READ/DATA. Added small local optimization. ** Revision date: Aug/23/2024. Added TI-99/4A. + ** Revision date: Apr/26/2025. Added Sega Master System. */ #include @@ -31,7 +32,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.8.0 Nov/12/2024" +#define VERSION "v0.8.0 Apr/26/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -41,81 +42,57 @@ /* ** Supported platforms. */ -static enum { - COLECOVISION, - SG1000, - MSX, - COLECOVISION_SGM, - SVI, - SORD, - MEMOTECH, - CREATIVISION, - PENCIL, - EINSTEIN, - PV2000, - TI994A, - NABU, - TOTAL_TARGETS -} machine; +enum supported_machine machine; enum cpu_target target; /* ** Base information about each platform. */ -static struct console { - char *name; /* Machine name */ - char *options; /* Options */ - char *description; /* Description (for usage guide) */ - char *canonical; /* Canonical name */ - int base_ram; /* Where the RAM starts */ - int stack; /* Where the stack will start */ - int memory_size; /* Memory available */ - int vdp_port_write; /* VDP port for writing */ - int vdp_port_read; /* VDP port for reading (needed for SVI-318/328, sigh) */ - int psg_port; /* PSG port (SN76489) */ - enum cpu_target target; -} consoles[TOTAL_TARGETS] = { +struct console consoles[TOTAL_TARGETS] = { /* RAM STACK Size VDP R VDP W PSG */ {"colecovision","", "Standard Colecovision (1K RAM)", "Colecovision", - 0x7000, 0x7400, 0x0400, 0xbe, 0xbe, 0xff, CPU_Z80}, + 0x7000, 0x7400, 0x0400, 0xbe, 0xbe, 0xff, 0, CPU_Z80}, {"sg1000", "", "Sega SG-1000/SC-3000 (1K RAM)", "Sega SG-1000/SC-3000", - 0xc000, 0xc400, 0x0400, 0xbe, 0xbe, 0x7f, CPU_Z80}, + 0xc000, 0xc400, 0x0400, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, {"msx", "-ram16", "MSX (8K RAM), use -ram16 for 16K of RAM", "MSX", - 0xe000, 0xf380, 0x1380, 0x98, 0x98, 0, CPU_Z80}, + 0xe000, 0xf380, 0x1380, 0x98, 0x98, 0, 1, CPU_Z80}, {"sgm", "", "Colecovision with Opcode's Super Game Module", "Colecovision with SGM", - 0x7c00, 0x8000, 0x5c00, 0xbe, 0xbe, 0xff, CPU_Z80}, /* Note: Real RAM at 0x2000 */ + 0x7c00, 0x8000, 0x5c00, 0xbe, 0xbe, 0xff, 0, CPU_Z80}, /* Note: Real RAM at 0x2000 */ {"svi", "", "Spectravideo SVI-318/328 (16K of RAM)", "Spectravideo SVI-318/328", - 0xc000, 0xf000, 0x3000, 0x80, 0x84, 0, CPU_Z80}, + 0xc000, 0xf000, 0x3000, 0x80, 0x84, 0, 1, CPU_Z80}, {"sord", "", "Sord M5 (1K RAM)", "Sord M5", - 0x7080, 0x7080, 0x0380, 0x10, 0x10, 0x20, CPU_Z80}, + 0x7080, 0x7080, 0x0380, 0x10, 0x10, 0x20, 1, CPU_Z80}, {"memotech","-cpm", "Memotech MTX (64K RAM), generates .run files, use -cpm for .com files", "Memotech MTX", - 0, 0xa000, 0, 0x01, 0x01, 0x06, CPU_Z80}, + 0, 0xa000, 0, 0x01, 0x01, 0x06, 1, CPU_Z80}, {"creativision","-rom16","Vtech Creativision (Dick Smith's Wizzard/Laser 2001), 6502+1K RAM.", "Creativision/Wizzard", - 0x0050, 0x017f, 0x0400, 0, 0, 0, CPU_6502}, + 0x0050, 0x017f, 0x0400, 0, 0, 0, 1, CPU_6502}, {"pencil", "", "Soundic/Hanimex Pencil II (2K RAM)", "Soundic Pencil II", - 0x7000, 0x7800, 0x0800, 0xbe, 0xbe, 0xff, CPU_Z80}, + 0x7000, 0x7800, 0x0800, 0xbe, 0xbe, 0xff, 0, CPU_Z80}, {"einstein","", "Tatung Einstein, generates .com files", "Tatung Einstein", - 0, 0xa000, 0, 0x08, 0x08, 0, CPU_Z80}, + 0, 0xa000, 0, 0x08, 0x08, 0, 0, CPU_Z80}, {"pv2000", "", "Casio PV-2000", "Casio PV-2000", - 0x7600, 0x8000, 0x0a00,0x4000, 0x4000, 0x40, CPU_Z80}, + 0x7600, 0x8000, 0x0a00,0x4000, 0x4000, 0x40, 0, CPU_Z80}, {"ti994a", "", "Texas Instruments TI-99/4A (32K RAM). Support by tursilion", "TI-99/4A (support by tursilion)", - 0x2080, 0x4000, 0x1f80, 0x8800, 0x8c00,0xff, CPU_9900}, + 0x2080, 0x4000, 0x1f80, 0x8800, 0x8c00,0xff, 1, CPU_9900}, {"nabu", "-cpm", "NABU PC (64K RAM)", "Nabu PC", - 0, 0xe000, 0, 0xa0, 0xa0, 0, CPU_Z80}, + 0, 0xe000, 0, 0xa0, 0xa0, 0, 1, CPU_Z80}, + {"sms", "", "Sega Master System (8K RAM)", + "Sega Master System", + 0xc000, 0xe000, 0x1000, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, }; static int err_code; @@ -686,6 +663,10 @@ void get_lex(void) { if (p - name < MAX_LINE_SIZE - 1) *p++ = toupper(line[line_pos]); line_pos++; + if (p - name == 3 && name[0] == 'C' && name[1] == 'H' && name[2] == 'R' && line[line_pos] == '$' && line[line_pos + 1] != ':') { /* Hack to support CHR$ */ + *p++ = line[line_pos]; + line_pos++; + } } *p = '\0'; name_size = (int) (p - name); @@ -1680,7 +1661,11 @@ struct node *evaluate_level_7(int *type) else get_lex(); *type = TYPE_16; - return node_create(N_MINUS16, 0, node_create(N_POS, 0, NULL, NULL), node_create(N_NUM16, 0x1800, NULL, NULL)); + tree = node_create(N_POS, 0, NULL, NULL); + tree = node_create(N_MINUS16, 0, tree, node_create(N_NUM16, (machine == SMS) ? 0x3800 : 0x1800, NULL, NULL)); + if (machine == SMS) + tree = node_create(N_DIV16, 0, tree, node_create(N_NUM16, 2, NULL, NULL)); + return tree; } if (macro_search(name) != NULL) { /* Function (macro) */ if (replace_macro()) @@ -2861,19 +2846,19 @@ void compile_statement(int check_for_else) cpu6502_noop("PLA"); cpu6502_noop("TAX"); cpu6502_1op("LDA", "temp"); - cpu6502_noop("SEI"); + generic_interrupt_disable(); cpu6502_1op("JSR", "WRTVRM"); - cpu6502_noop("CLI"); + generic_interrupt_enable(); } else if (target == CPU_9900) { node_generate(value, 0); cpu9900_1op("dect", "r10"); cpu9900_2op("mov", "r0", "*r10"); node_generate(address, 0); cpu9900_2op("mov", "*r10+", "r2"); - cpu9900_1op("limi","0"); + generic_interrupt_disable(); cpu9900_1op("bl","@JSR"); cpu9900_1op("data", "WRTVRM"); - cpu9900_1op("limi","2"); + generic_interrupt_enable(); } else { if ((value->regs & REG_HL) == 0) { node_generate(address, 0); @@ -2887,9 +2872,9 @@ void compile_statement(int check_for_else) node_generate(value, 0); cpuz80_1op("POP", "HL"); } - cpuz80_1op("CALL", "NMI_OFF"); + generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVRM"); - cpuz80_1op("CALL", "NMI_ON"); + generic_interrupt_enable(); } node_delete(address); node_delete(value); @@ -3192,7 +3177,7 @@ void compile_statement(int check_for_else) emit_error("missing comma in OUT"); value = evaluate_save_expression(1, TYPE_8); if (target == CPU_6502) { - emit_warning("Ignoring OUT (not supported in target)"); + emit_warning("Ignoring OUT (not supported for 6502)"); } else if (target == CPU_9900) { /* ** We don't have ports (though we could map this to CRU) @@ -3236,6 +3221,9 @@ void compile_statement(int check_for_else) if (lex == C_NAME && strcmp(name, "AT") == 0) { get_lex(); tree = evaluate_save_expression(1, TYPE_16); + if (machine == SMS) { + tree = node_create(N_MUL16, 0, tree, node_create(N_NUM16, 2, NULL, NULL)); + } if (target == CPU_6502) { if (tree->type == N_NUM16) { cursor_value = 2; @@ -3415,7 +3403,7 @@ void compile_statement(int check_for_else) if (format == 0) { cpu6502_1op("JSR", "print_number"); } else if (format == 1) { - cpu6502_noop("SEI"); + generic_interrupt_disable(); cpu6502_1op("LDX", "#2"); cpu6502_1op("STX", "temp"); cpu6502_1op("LDX", "#32"); @@ -3423,7 +3411,7 @@ void compile_statement(int check_for_else) sprintf(temp, "print_number%d", size); cpu6502_1op("JSR", temp); } else if (format == 2) { - cpu6502_noop("SEI"); + generic_interrupt_disable(); cpu6502_1op("LDX", "#2"); cpu6502_1op("STX", "temp"); cpu6502_1op("LDX", "#48"); @@ -3437,13 +3425,13 @@ void compile_statement(int check_for_else) cpu9900_1op("bl", "@JSR"); cpu9900_1op("data", "print_number"); } else if (format == 1) { - cpu9900_1op("limi","0"); /* print_number will turn it back on */ + generic_interrupt_disable(); cpu9900_2op("li", "r5", ">0220"); sprintf(temp, "print_number%d", size); cpu9900_1op("bl", "@JSR"); cpu9900_1op("data", temp); } else if (format == 2) { - cpu9900_1op("limi","0"); /* print_number will turn it back on */ + generic_interrupt_disable(); cpu9900_2op("li", "r5", ">0230"); sprintf(temp, "print_number%d", size); cpu9900_1op("bl", "@JSR"); @@ -3453,12 +3441,12 @@ void compile_statement(int check_for_else) if (format == 0) { cpuz80_1op("CALL", "print_number"); } else if (format == 1) { - cpuz80_1op("CALL", "nmi_off"); + generic_interrupt_disable(); cpuz80_2op("LD", "BC", "$0220"); sprintf(temp, "print_number%d", size); cpuz80_1op("CALL", temp); } else if (format == 2) { - cpuz80_1op("CALL", "nmi_off"); + generic_interrupt_disable(); cpuz80_2op("LD", "BC", "$0230"); sprintf(temp, "print_number%d", size); cpuz80_1op("CALL", temp); @@ -3477,11 +3465,28 @@ void compile_statement(int check_for_else) cpu6502_1op("STY", "cursor+1"); } } - type = evaluate_expression(1, TYPE_16, 0); - if (target == CPU_9900) { - cpu9900_2op("mov", "r0", "r3"); + if (lex == C_NAME && strcmp(name, "CHR$") == 0) { + get_lex(); + if (lex != C_LPAREN) + emit_error("syntax error in CHR$"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (lex != C_RPAREN) + emit_error("syntax error in CHR$"); + else + get_lex(); + if (target == CPU_6502) + cpu6502_noop("TAX"); + else if (target == CPU_9900) + cpu9900_2op("mov", "r0", "r2"); + generic_call("print_char"); + } else { + type = evaluate_expression(1, TYPE_16, 0); + if (target == CPU_9900) + cpu9900_2op("mov", "r0", "r3"); + generic_call("print_number"); } - generic_call("print_number"); } cursor_value = 0; } @@ -3852,27 +3857,18 @@ void compile_statement(int check_for_else) generic_call("unpack"); compression_used = 1; } else { - if (target == CPU_6502) { - cpu6502_noop("SEI"); - } else if (target == CPU_9900) { + if (target == CPU_9900) { cpu9900_2op("mov","r0","r2"); cpu9900_2op("mov","r5","r3"); cpu9900_2op("mov","r4","r0"); - cpu9900_1op("limi","0"); - } else { - cpuz80_1op("CALL", "nmi_off"); } + generic_interrupt_disable(); if (vram_read) { generic_call("LDIRMV"); } else { generic_call("LDIRVM"); } - if (target == CPU_6502) - cpu6502_noop("CLI"); - else if (target == CPU_9900) - cpu9900_1op("limi","2"); - else - cpuz80_1op("CALL", "nmi_on"); + generic_interrupt_enable(); } node_delete(length); node_delete(target2); @@ -3948,20 +3944,22 @@ void compile_statement(int check_for_else) else emit_error("missing comma in SPRITE"); type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_6502) - cpu6502_1op("STA", "sprite_data+2"); - else if (target == CPU_9900) - cpu9900_2op("movb","r0","r7"); - else - cpuz80_1op("PUSH", "AF"); - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in SPRITE"); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_6502) { - cpu6502_1op("STA", "sprite_data+3"); - cpu6502_noop("PLA"); + if (machine != SMS) { + if (target == CPU_6502) + cpu6502_1op("STA", "sprite_data+2"); + else if (target == CPU_9900) + cpu9900_2op("movb","r0","r7"); + else + cpuz80_1op("PUSH", "AF"); + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in SPRITE"); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_6502) { + cpu6502_1op("STA", "sprite_data+3"); + cpu6502_noop("PLA"); + } } generic_call("update_sprite"); } @@ -4033,26 +4031,24 @@ void compile_statement(int check_for_else) type = evaluate_expression(1, TYPE_8, 0); if (target == CPU_6502) { cpu6502_1op("LDX", "#7"); - cpu6502_noop("SEI"); + generic_interrupt_disable(); cpu6502_1op("JSR", "WRTVDP"); - cpu6502_noop("CLI"); } else if (target == CPU_9900) { /* this is just a lot faster inline than jumping through hoops... */ cpu9900_2op("srl","r0","8"); cpu9900_2op("ori","r0",">8700"); cpu9900_1op("swpb","r0"); - cpu9900_1op("limi","0"); + generic_interrupt_disable(); cpu9900_2op("movb","r0","@VDPWADR"); cpu9900_1op("swpb","r0"); cpu9900_2op("movb","r0","@VDPWADR"); - cpu9900_1op("limi","2"); } else { cpuz80_2op("LD", "B", "A"); cpuz80_2op("LD", "C", "7"); - cpuz80_1op("CALL", "nmi_off"); + generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); - cpuz80_1op("CALL", "nmi_on"); } + generic_interrupt_enable(); } else if (strcmp(name, "SIGNED") == 0) { struct signedness *c; @@ -4183,17 +4179,31 @@ void compile_statement(int check_for_else) } } else if (strcmp(name, "MODE") == 0) { get_lex(); - if (lex != C_NUM || (value != 0 && value != 1 && value != 2)) { + if (lex != C_NUM || (value != 0 && value != 1 && value != 2 && value != 4)) { emit_error("bad syntax for MODE"); break; } get_lex(); - if (value == 0) + if (value == 0) { + if (machine == SMS) + emit_error("Use SG1000 if you want to use MODE 0"); generic_call("mode_0"); - if (value == 1) + } + if (value == 1) { + if (machine == SMS) + emit_error("Use SG1000 if you want to use MODE 1"); generic_call("mode_1"); - if (value == 2) + } + if (value == 2) { + if (machine == SMS) + emit_error("Use SG1000 if you want to use MODE 2"); generic_call("mode_2"); + } + if (value == 4) { + if (machine != SMS) + emit_error("MODE 4 only supported for Sega Master System"); + generic_call("mode_4"); + } } else if (strcmp(name, "SCREEN") == 0) { /* Copy screen */ struct label *array; @@ -4365,25 +4375,23 @@ void compile_statement(int check_for_else) cpu6502_1op("LDY", "#24"); cpu6502_1op("STA", "pointer"); cpu6502_1op("STY", "pointer+1"); - cpu6502_noop("SEI"); + generic_interrupt_disable(); cpu6502_1op("JSR", "LDIRVM"); - cpu6502_noop("CLI"); } else if (target == CPU_9900) { cpu9900_2op("li","r0",">1800"); cpu9900_2op("li","r2",assigned); cpu9900_2op("li","r3",">0300"); - cpu9900_1op("limi","0"); + generic_interrupt_disable(); cpu9900_1op("bl","@jsr"); cpu9900_1op("data","LDIRVM"); - cpu9900_1op("limi","2"); } else { cpuz80_2op("LD", "HL", assigned); cpuz80_2op("LD", "DE", "$1800"); cpuz80_2op("LD", "BC", "$0300"); - cpuz80_1op("CALL", "nmi_off"); + generic_interrupt_disable(); cpuz80_1op("CALL", "LDIRVM"); - cpuz80_1op("CALL", "nmi_on"); } + generic_interrupt_enable(); } } } else if (strcmp(name, "PLAY") == 0) { @@ -5325,7 +5333,7 @@ void compile_statement(int check_for_else) c &= 0x1f; else c &= 0x3f; - if (machine == SG1000) { + if (machine == SG1000 || machine == SMS) { sprintf(temp, "%d", c & 0x3f); cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "($fffe)", "A"); @@ -5397,7 +5405,7 @@ void compile_statement(int check_for_else) bank_finish(); sprintf(temp, "$%05x", c << 14); cpuz80_1op("FORG", temp); - if (machine == SG1000) { + if (machine == SG1000 || machine == SMS) { cpuz80_1op("ORG", "$4000"); } else if (machine == MSX) { cpuz80_1op("ORG", "$8000"); @@ -5435,9 +5443,9 @@ void compile_statement(int check_for_else) if (target == CPU_6502) { sprintf(temp, "#%d", vdp_reg); cpu6502_1op("LDX", temp); - cpu6502_noop("SEI"); + generic_interrupt_disable(); cpu6502_1op("JSR", "WRTVDP"); - cpu6502_noop("CLI"); + generic_interrupt_enable(); } else if (target == CPU_9900) { /* Simpler to do inline */ sprintf(temp, "%d ; %d*256+0x8000", vdp_reg*256+0x8000, vdp_reg); @@ -5452,9 +5460,9 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "B", "A"); sprintf(temp, "%d", vdp_reg); cpuz80_2op("LD", "C", temp); - cpuz80_1op("CALL", "nmi_off"); + generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); - cpuz80_1op("CALL", "nmi_on"); + generic_interrupt_enable(); } } else if (macro_search(name) != NULL) { /* Function (macro) */ if (!replace_macro()) { @@ -5750,7 +5758,7 @@ int main(int argc, char *argv[]) date = localtime(&actual); fprintf(stderr, "\nCVBasic compiler " VERSION "\n"); - fprintf(stderr, "(c) 2024 Oscar Toledo G. https://nanochess.org/\n\n"); + fprintf(stderr, "(c) 2024-2025 Oscar Toledo G. https://nanochess.org/\n\n"); if (argc < 3) { fprintf(stderr, "Usage:\n"); @@ -5947,6 +5955,7 @@ int main(int argc, char *argv[]) fprintf(output, "PV2000:\tequ %d\n", (machine == PV2000) ? 1 : 0); fprintf(output, "TI99:\tequ %d\n", (machine == TI994A) ? 1 : 0); fprintf(output, "NABU:\tequ %d\n", (machine == NABU) ? 1 : 0); + fprintf(output, "SMS:\tequ %d\n", (machine == SMS) ? 1 : 0); fprintf(output, "\n"); fprintf(output, "CVBASIC_MUSIC_PLAYER:\tequ %d\n", music_used); fprintf(output, "CVBASIC_COMPRESSION:\tequ %d\n", compression_used); diff --git a/cvbasic.h b/cvbasic.h index b738514..a21a739 100644 --- a/cvbasic.h +++ b/cvbasic.h @@ -15,6 +15,32 @@ #define MAX_LINE_SIZE 1024 +/* + ** Supported platforms. + */ +enum supported_machine { + COLECOVISION, + SG1000, + MSX, + COLECOVISION_SGM, + SVI, + SORD, + MEMOTECH, + CREATIVISION, + PENCIL, + EINSTEIN, + PV2000, + TI994A, + NABU, + SMS, + TOTAL_TARGETS +}; + +extern enum supported_machine machine; + +/* + ** Supported target CPUs + */ enum cpu_target { CPU_Z80, CPU_6502, @@ -22,6 +48,27 @@ enum cpu_target { }; extern enum cpu_target target; + +/* + ** Information about supported machines + */ +struct console { + char *name; /* Machine name */ + char *options; /* Options */ + char *description; /* Description (for usage guide) */ + char *canonical; /* Canonical name */ + int base_ram; /* Where the RAM starts */ + int stack; /* Where the stack will start */ + int memory_size; /* Memory available */ + int vdp_port_write; /* VDP port for writing */ + int vdp_port_read; /* VDP port for reading (needed for SVI-318/328, sigh) */ + int psg_port; /* PSG port (SN76489) */ + int int_pin; /* Indicates if it uses the INT pin for video frame interrupt */ + enum cpu_target target; +}; + +extern struct console consoles[TOTAL_TARGETS]; + extern char temp[MAX_LINE_SIZE]; extern int optimized; extern FILE *output; diff --git a/cvbasic_6502_prologue.asm b/cvbasic_6502_prologue.asm index a3ef3ee..4e44ad7 100644 --- a/cvbasic_6502_prologue.asm +++ b/cvbasic_6502_prologue.asm @@ -451,14 +451,16 @@ print_digit: .4: DEX BEQ .6 LDX temp+1 - BNE .5 + BNE print_char .6: LDX #$30 .3: PHA LDA #1 STA temp PLA -.5: PHA + +print_char: + PHA TYA PHA LDA cursor+1 diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index c59b78e..8158433 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -416,13 +416,13 @@ print_digit ci r5,>0200 jl !6 mov r5,r2 - jne !5 + jne print_char !6 li r2,>30 !3 andi r5,>00ff ori r5,>0100 -!5 +print_char mov @cursor,r0 ; get cursor andi r0,>07ff ; enforce position - large range for two screen pages ai r0,>1800 ; add is safer than OR, and we have that option diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 1ef9353..eaacad3 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -25,7 +25,7 @@ rom_end: ; ROM final size rounding - if MSX+COLECO+SG1000+SVI+SORD + if MSX+COLECO+SG1000+SMS+SVI+SORD TIMES (($+$1FFF)&$1e000)-$ DB $ff endif if MEMOTECH+EINSTEIN+NABU @@ -35,7 +35,7 @@ rom_end: if PV2000 TIMES $10000-$ DB $ff endif - if SG1000 + if SG1000+SMS forg $7FF0 org $7FF0 db "TMR SEGA" @@ -45,13 +45,17 @@ rom_end: db $00 ; Version db $4c ; SMS Export + 32KB for checksum endif - if COLECO+SG1000+MSX+SVI+SORD+PV2000 + if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 org BASE_RAM endif ram_start: sprites: + if SMS + rb 256 + else rb 128 + endif sprite_data: rb 4 frame: diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index f515608..4664eea 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1,5 +1,5 @@ ; - ; CVBasic prologue (BASIC compiler for Colecovision) + ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) ; ; by Oscar Toledo G. ; https://nanochess.org/ @@ -44,8 +44,8 @@ JOYSEL: equ $c0 KEYSEL: equ $80 -JOY1: equ $fc-$20*SG1000 -JOY2: equ $ff-$22*SG1000 +JOY1: equ $fc-$20*(SG1000+SMS) +JOY2: equ $ff-$22*(SG1000+SMS) if COLECO org $8000 @@ -84,7 +84,7 @@ JOY2: equ $ff-$22*SG1000 jp nmi_handler endif endif - if SG1000+SVI + if SG1000+SMS+SVI org $0000 di ld sp,STACK @@ -236,6 +236,7 @@ RDPSG: endif if PV2000 + ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) WRTVDP: ld a,b ld (VDP+1),a @@ -323,6 +324,7 @@ LDIRVM: JP NZ,.1 ; 10 11 RET else + ; Normal platforms with VDP connected via ports (IORQ) WRTVDP: ld a,b out (VDP+1),a @@ -354,7 +356,7 @@ WRTVRM: out (VDP),a ret - if SG1000 + if SG1000+SMS db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff ; Located at $0066 @@ -392,7 +394,7 @@ LDIRMV: .1: in a,(VDP) ld (de),a - if SORD + if SORD+SMS nop endif if SG1000+MEMOTECH+EINSTEIN @@ -417,7 +419,7 @@ LDIRVM: inc a ld c,VDP .1: - if SORD + if SORD+SMS nop endif if SG1000+MEMOTECH+EINSTEIN @@ -431,6 +433,8 @@ LDIRVM: ret endif + if SMS + else LDIRVM3: call .1 call .1 @@ -445,6 +449,7 @@ LDIRVM3: ld d,a pop hl ret + endif DISSCR: call nmi_off @@ -494,7 +499,7 @@ nmi_off: set 0,(hl) pop hl endif - if SG1000+MSX+SVI+SORD+MEMOTECH+NABU + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU di endif ret @@ -511,7 +516,7 @@ nmi_on: pop hl pop af endif - if SG1000+MSX+SVI+SORD+MEMOTECH+NABU + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU ei endif ret @@ -523,6 +528,23 @@ keypad_table: endif cls: + if SMS + ld hl,$3800 + ld (cursor),hl + di + call SETWRT +.1: ld a,$20 ; 7 + out (VDP),a ; 11 + inc hl ; 6 + inc hl ; 6 + ld a,$00 ; 7 + out (VDP),a ; 11 + ld a,h ; 4 + cp $3e ; 7 + jp nz,.1 ; 10 + ei + ret + else ld hl,$1800 ld (cursor),hl ld bc,$0300 @@ -530,23 +552,49 @@ cls: call nmi_off call FILVRM jp nmi_on + endif print_string: ld c,a ld b,0 ld de,(cursor) + if SMS + ld a,d + and $07 + or $38 + ld d,a + else ld a,d and $07 or $18 ld d,a + endif push de push bc call nmi_off + if SMS + ex de,hl +.1: ld a,(de) + call WRTVRM + inc de + inc hl + xor a + call WRTVRM + inc hl + dec bc + ld a,b + or c + jp nz,.1 + else call LDIRVM + endif call nmi_on pop bc pop hl add hl,bc + if SMS + add hl,bc + endif ld (cursor),hl ret @@ -586,33 +634,46 @@ print_digit: dec a jr z,.4 ld a,c - jr .5 + jr print_char .4: ld a,$30 .3: ld b,1 -.5: push hl + +print_char: + push hl ld hl,(cursor) ex af,af' ld a,h and $07 + if SMS + or $38 + else or $18 + endif ld h,a ex af,af' call WRTVRM inc hl + if SMS + xor a + call WRTVRM + inc hl + endif ld (cursor),hl pop hl ret -define_sprite: +define_char: ex de,hl ld l,a ld h,0 add hl,hl ; x2 add hl,hl ; x4 add hl,hl ; x8 + if SMS add hl,hl ; x16 add hl,hl ; x32 + endif ld c,l ld b,h pop af @@ -620,16 +681,33 @@ define_sprite: push af add hl,hl ; x2 add hl,hl ; x4 - ld h,$07 add hl,hl ; x8 + if SMS add hl,hl ; x16 add hl,hl ; x32 + endif ex de,hl - call nmi_off + if SMS + di call LDIRVM + ei + ret + else + call nmi_off + ld a,(mode) + and 8 + jr nz,.1 + call LDIRVM3 jp nmi_on -define_char: +.1: call LDIRVM + jp nmi_on + endif + +define_color: + if SMS + ret + else ex de,hl ld l,a ld h,0 @@ -645,23 +723,24 @@ define_char: add hl,hl ; x4 add hl,hl ; x8 ex de,hl + set 5,d call nmi_off - ld a,(mode) - and 8 - jr nz,.1 call LDIRVM3 jp nmi_on - -.1: call LDIRVM - jp nmi_on + endif -define_color: +define_sprite: ex de,hl ld l,a ld h,0 add hl,hl ; x2 add hl,hl ; x4 add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif ld c,l ld b,h pop af @@ -669,14 +748,47 @@ define_color: push af add hl,hl ; x2 add hl,hl ; x4 + if SMS + set 1,h + else + ld h,$07 + endif add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif ex de,hl - set 5,d call nmi_off - call LDIRVM3 + call LDIRVM jp nmi_on + endif update_sprite: + if SMS + pop bc + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + and $3f + ld e,a + ld d,sprites>>8 + ld a,(sprite_data) + ld (de),a + sla e + set 7,e + ld a,(sprite_data+1) + ld (de),a + inc e + ld a,(sprite_data+2) + ld (de),a + else pop bc ld (sprite_data+3),a pop af @@ -686,6 +798,7 @@ update_sprite: pop af ld (sprite_data),a pop af + ; A = Sprite number push bc ld de,sprites add a,a @@ -697,6 +810,7 @@ update_sprite: ld hl,sprite_data ld bc,4 ldir + endif ret ; Fast 16-bit multiplication. @@ -851,7 +965,7 @@ random: ret sn76489_freq: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 ld b,a ld a,l and $0f @@ -874,7 +988,7 @@ sn76489_freq: ret sn76489_vol: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 cpl and $0f or b @@ -886,7 +1000,7 @@ sn76489_vol: ret sn76489_control: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 and $0f or $e0 out (PSG),a @@ -905,7 +1019,7 @@ ay3_reg: out ($51),a ret endif - if SG1000+SORD+MEMOTECH+PV2000 + if SG1000+SORD+SMS+MEMOTECH+PV2000 ret endif if MSX+SVI+EINSTEIN+NABU @@ -930,7 +1044,7 @@ ay3_freq: pop af ret endif - if SG1000+SORD+MEMOTECH+PV2000 + if SG1000+SMS+SORD+MEMOTECH+PV2000 ret endif if MSX+SVI+EINSTEIN+NABU @@ -941,8 +1055,8 @@ ay3_freq: jp WRTPSG endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ; Required for SG1000 as it doesn't have a BIOS + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ; Required for SG1000 and Sega Master System as both don't have a BIOS ; Required for SVI because we don't have access to BIOS in cartridge. ; Required for Sord M5 because it doesn't provide an ASCII charset. ; Required for Memotech/Einstein because CP/M uses the memory. @@ -1051,6 +1165,79 @@ font_bitmaps: db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f endif + if SMS +set_palette: + push hl + di + ld hl,$c000 + call SETWRT + pop hl + ld bc,16*256+VDP + outi + jp nz,$-2 + ei + ret + +mode_4: + di + ld bc,$0400 + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0e02 ; $3800 for pattern table. + call WRTVDP + ld bc,$ff03 ; Not used. + call WRTVDP + ld bc,$0304 ; Not used. + call WRTVDP + ld bc,$7e05 ; $3f00 for sprite attribute table. + call WRTVDP + ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) + call WRTVDP + ld bc,$0007 + call WRTVDP + ld bc,$0008 ; Background X scroll + call WRTVDP + ld bc,$0009 ; Background Y scroll + call WRTVDP + ld hl,$20*32 ; Point to space character bitmap + call SETWRT + ld hl,font_bitmaps + ld c,96 +.1: ld b,8 +.2: ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + inc hl + djnz .2 + dec c + jp nz,.1 + ei + call cls + di + ld hl,$3f00 + ld bc,$0040 + ld a,$e0 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,63 + ld (hl),$e0 + ldir + ei + ld hl,.3 + call set_palette + jp ENASCR + + ; From https://www.smspower.org/Development/Palette +.3: db $00,$00,$08,$0c,$10,$30,$01,$3c,$02,$03,$05,$0f,$04,$33,$15,$3f + + else vdp_generic_mode: call nmi_off call WRTVDP @@ -1116,10 +1303,7 @@ vdp_generic_sprites: ld (hl),$d1 ldir call nmi_on - call nmi_off - ld bc,$e201 ; Enable screen and interrupts. - call WRTVDP - jp nmi_on + jp ENASCR mode_1: ld hl,mode @@ -1166,7 +1350,7 @@ mode_2: ld de,-128 add hl,de endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU ld hl,font_bitmaps endif if MSX @@ -1185,6 +1369,7 @@ mode_2: call nmi_on call cls jp vdp_generic_sprites + endif if MSX ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) @@ -1252,7 +1437,7 @@ nmi_handler: if COLECO ld a,($ffbf) endif - if SG1000 + if SG1000+SMS ld a,($7fff) endif if MSX @@ -1263,10 +1448,64 @@ nmi_handler: if SORD+MEMOTECH call ctc_reti endif - if SG1000+MSX+SVI+SORD+MEMOTECH+NABU + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU in a,(VDPR+1) ld (vdp_status),a endif + + ; + ; Update of sprite attribute table + ; + if SMS + bit 2,(hl) + jr z,.4 + ld hl,$3f00 + call SETWRT + ld hl,sprites + ld bc,$4000+VDP + outi + jp nz,$-2 + ld hl,$3f80 + call SETWRT + ld hl,sprites + ld bc,$8000+VDP + outi + jp nz,$-2 + jr .5 + +.4: ld hl,$3f00 + call SETWRT + ld a,(flicker) + inc a + and $3f + ld (flicker),a + ld l,a + ld h,sprites>>8 + ld bc,$4000+VDP + ld de,6 + outi + add hl,de + res 7,l + jp nz,$-5 + ld hl,$3f80 + call SETWRT + ld a,(flicker) + add a,a + or $80 + ld l,a + ld h,sprites>>8 + ld bc,$8000+VDP + ld de,12 + outi + nop + nop + nop + outi + add hl,de + res 7,l + jp nz,$-10 +.5: + else ld bc,$8000+VDP bit 2,(hl) jr z,.4 @@ -1356,6 +1595,7 @@ nmi_handler: add hl,de jp nz,.6 .5: + endif if COLECO out (JOYSEL),a @@ -1407,7 +1647,7 @@ nmi_handler: ld a,(hl) ld (key2_data),a endif - if SG1000 + if SG1000+SMS ld a,$07 out ($de),a ld b,$ff @@ -2350,7 +2590,7 @@ nmi_handler: ld h,$ff ld a,(hl) endif - if SG1000 + if SG1000+SMS ld ($fffe),a endif if MSX @@ -2366,7 +2606,7 @@ nmi_handler: pop af retn endif - if SG1000+SVI+NABU + if SG1000+SMS+SVI+NABU pop af ei reti @@ -2526,7 +2766,7 @@ wait: ; Init music player. ; music_init: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 ld a,$9f out (PSG),a if MEMOTECH @@ -2553,7 +2793,7 @@ music_init: in a,($03) endif endif - if COLECO+SG1000+MSX+SVI+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 MIX_BASE: equ $b8 endif if EINSTEIN+NABU @@ -2617,7 +2857,7 @@ music_play: if COLECO ld a,($ffbf) endif - if SG1000 + if SG1000+SMS ld a,($7fff) endif if MSX @@ -2655,7 +2895,7 @@ music_generate: ld d,$ff ld a,(de) endif - if SG1000 + if SG1000+SMS ld ($fffe),a endif if MSX @@ -2965,7 +3205,7 @@ music_flute: ; Emit sound. ; music_hardware: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 ld a,(music_mode) cp 4 ; PLAY SIMPLE? jr c,.7 ; Yes, jump. @@ -3175,7 +3415,7 @@ music_hardware: ; Enable drum. ; enable_drum: - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 ld a,$f5 ld (audio_vol4hw),a else @@ -3226,7 +3466,7 @@ music_notes_table: dw 53,50,48 endif - if COLECO+SG1000+SORD+MEMOTECH+PV2000 + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 ; ; Converts AY-3-8910 volume to SN76489 ; @@ -3249,12 +3489,21 @@ define_char_unpack: add hl,hl ; x2 add hl,hl ; x4 add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif ex de,hl + if SMS + else ld a,(mode) and 8 jp z,unpack3 + endif jp unpack + if SMS + else define_color_unpack: ex de,hl pop af @@ -3278,6 +3527,7 @@ unpack3: add a,8 ld d,a ret + endif ; ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) @@ -3425,7 +3675,7 @@ unpack: endif START: - if SVI+SG1000 + if SVI+SG1000+SMS im 1 endif if MEMOTECH @@ -3486,7 +3736,7 @@ Z80_CTC: equ $28 ld a,$92 ; Setup 8255 for keyboard/joystick reading. out ($97),a endif - if SG1000 + if SG1000+SMS ; Contributed by SiRioKD ld a,$9F ; Turn off PSG out (PSG),a @@ -3499,7 +3749,7 @@ Z80_CTC: equ $28 ld a,$92 ; Setup 8255 for SC3000. out ($df),a endif - if SG1000+SVI + if SG1000+SMS+SVI ; Wait for VDP ready (around 1000 ms) ld b,11 ld de,$FFFF @@ -3549,7 +3799,7 @@ Z80_CTC: equ $28 if COLECO ld a,($ffc0) ; Megacart endif - if SG1000 + if SG1000+SMS ld a,1 ; Sega mapper ld ($fffe),a endif @@ -3663,7 +3913,7 @@ WRITE_VRAM: equ $1fdf jr nz,$+3 dec a endif - if SG1000+SVI+SORD+PV2000+NABU + if SG1000+SMS+SVI+SORD+PV2000+NABU ld a,1 ; Always NTSC. endif if MEMOTECH+EINSTEIN @@ -3687,8 +3937,11 @@ WRITE_VRAM: equ $1fdf xor a ld (mode),a - + if SMS + call mode_4 + else call mode_0 + endif xor a ld (joy1_data),a diff --git a/driver.c b/driver.c index 52deec5..c2fbbb1 100644 --- a/driver.c +++ b/driver.c @@ -265,5 +265,36 @@ void generic_comparison_16bit(int min, int max, char *label) } } +/* + ** Generic disable interrupt + */ +void generic_interrupt_disable(void) +{ + if (consoles[machine].int_pin == 0) { + generic_call("nmi_off"); + } else { + if (target == CPU_Z80) + cpuz80_noop("DI"); + else if (target == CPU_6502) + cpu6502_noop("SEI"); + else if (target == CPU_9900) + cpu9900_1op("limi", "0"); + } +} - +/* + ** Generic enable interrupt + */ +void generic_interrupt_enable(void) +{ + if (consoles[machine].int_pin == 0) { + generic_call("nmi_on"); + } else { + if (target == CPU_Z80) + cpuz80_noop("EI"); + else if (target == CPU_6502) + cpu6502_noop("CLI"); + else if (target == CPU_9900) + cpu9900_1op("limi", "2"); + } +} diff --git a/driver.h b/driver.h index e0c4eb0..54a3ae2 100644 --- a/driver.h +++ b/driver.h @@ -16,3 +16,5 @@ extern void generic_jump(char *); extern void generic_jump_zero(char *); extern void generic_comparison_8bit(int, int, char *); extern void generic_comparison_16bit(int, int, char *); +extern void generic_interrupt_disable(void); +extern void generic_interrupt_enable(void); diff --git a/examples/strings.bas b/examples/strings.bas index 29e87e1..b2788b0 100644 --- a/examples/strings.bas +++ b/examples/strings.bas @@ -19,7 +19,7 @@ DEF FN get_string(where, num) = RESTORE where: c = num: WHILE c > 0: DO: READ BYTE char: LOOP WHILE char <> 0: c = c - 1: WEND - DEF FN print_string(a) = WHILE 1: READ BYTE char: IF char <> 0 THEN PRINT " ": VPOKE $1800 + POS(0) - 1, char: WEND + DEF FN print_string(a) = WHILE 1: READ BYTE char: IF char <> 0 THEN PRINT CHR$(char): WEND WHILE 1 diff --git a/manual.txt b/manual.txt index 3667178..1bc47d5 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Nov/12/2024. +Last revision: Apr/26/2025 >>>>>>>>>>>>>> Legal notice @@ -22,8 +22,12 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.8.0 Nov/12/2024 o Added support for VDP.STATUS (for reading VDP status) - o Added SELECT CASE / END CASE +v0.8.0 Apr/26/2025 o Added support for VDP.STATUS (for reading VDP status) + o Added SELECT CASE / END SELECT + o Added support for CHR$ in PRINT (for portable printing of + arbitrary characters in the current cursor position) + o Optimizes code using directly DI/EI instructions in Z80 + platforms if possible. v0.7.1 Oct/15/2024 o Added support for NABU PC using --nabu (with -cpm option) o Added support for USR/CALL with up to 5 arguments (only Z80) @@ -353,7 +357,7 @@ The following statements are available: [statement] CASE ELSE [statement] - END CASE + END SELECT It evaluates the expression, and selects the statements to execute from the CASE statements. CASE ELSE should be the last statement if it is required to @@ -693,6 +697,14 @@ The following statements are available: PRINT AT 8,"Score:",<5>#score,"00" + PRINT CHR$(expr) + + Displays expr as a character on the video screen. + + Example: + + PRINT CHR$(65) + BORDER color Select the border color. It can be a number from 0 to 15. From 0d1286469985d8e726eac63343ea962d8feeca7e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 26 Apr 2025 19:31:16 -0600 Subject: [PATCH 019/155] For SMS, adjusted BITMAP for 16 colors, SCREEN for x2 width/offset, added PALETTE, SCROLL, and BORDER flags --- cvbasic.c | 208 +- cvbasic_prologue.asm | 29 +- examples/happy_face_sms.bas | 71 + happy_face_sms.asm | 4304 +++++++++++++++++++++++++++++++ happy_face_sms.rom | Bin 0 -> 32768 bytes manual.txt | 71 +- music.asm | 4792 +++++++++++++++++++++++++++++++++++ music.rom | Bin 0 -> 32768 bytes 8 files changed, 9419 insertions(+), 56 deletions(-) create mode 100644 examples/happy_face_sms.bas create mode 100644 happy_face_sms.asm create mode 100644 happy_face_sms.rom create mode 100644 music.asm create mode 100644 music.rom diff --git a/cvbasic.c b/cvbasic.c index 26b73dd..fe65785 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3524,10 +3524,15 @@ void compile_statement(int check_for_else) } else { cpuz80_2op("ADD", "HL", "HL"); cpuz80_2op("ADD", "HL", "HL"); - cpuz80_2op("LD", "H", "$07"); + if (machine == SMS) + cpuz80_2op("SET", "1", "H"); + else + cpuz80_2op("LD", "H", "$07"); cpuz80_2op("ADD", "HL", "HL"); cpuz80_2op("ADD", "HL", "HL"); cpuz80_2op("ADD", "HL", "HL"); + if (machine == SMS) + cpuz80_2op("ADD", "HL", "HL"); cpuz80_2op("EX", "DE", "HL"); } if (lex == C_COMMA) @@ -3966,9 +3971,9 @@ void compile_statement(int check_for_else) } else if (strcmp(name, "BITMAP") == 0) { generic_dump(); get_lex(); - if (lex != C_STRING || (name_size != 8 && name_size != 16)) { + if (lex != C_STRING ) { emit_error("syntax error in BITMAP"); - } else if (name_size == 16) { /* Sprites */ + } else if (name_size == 16 && machine != SMS) { /* Sprites */ int c; value = 0; @@ -3997,18 +4002,50 @@ void compile_statement(int check_for_else) } } - } else { + } else if (name_size == 8) { int c; value = 0; - for (c = 0; c < 8; c++) { - if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ - && name[c] != 0x20 && name[c] != 0x2e) /* space and . */ - value |= 0x80 >> c; + if (machine == SMS) { + int first_time = 1; + + for (c = 0; c < 8; c++) { + if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ + && name[c] != 0x20 && name[c] != 0x2e) { /* space and . */ + int d; + + if (isxdigit(name[c])) { + d = toupper(name[c]) - 0x30; + if (d > 9) + d -= 7; + } else { + if (first_time) { + emit_warning("invalid hexadecimal value in BITMAP"); + first_time = 0; + } + d = 0; + } + value |= ((d & 1) << 7) >> c; + value |= ((d & 2) << 6) >> c << 8; + value |= ((d & 4) << 5) >> c << 16; + value |= ((d & 8) << 4) >> c << 24; + } + } + get_lex(); + bitmap[bitmap_byte++] = value; + bitmap[bitmap_byte++] = value >> 8; + bitmap[bitmap_byte++] = value >> 16; + bitmap[bitmap_byte++] = value >> 24; + } else { + for (c = 0; c < 8; c++) { + if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ + && name[c] != 0x20 && name[c] != 0x2e) /* space and . */ + value |= 0x80 >> c; + } + get_lex(); + bitmap[bitmap_byte] = value; + bitmap_byte++; } - get_lex(); - bitmap[bitmap_byte] = value; - bitmap_byte++; if (bitmap_byte >= 8) { bitmap_byte = 0; c = 0; @@ -4023,32 +4060,123 @@ void compile_statement(int check_for_else) } fprintf(output, "%s", temp); } + } else { + emit_error("width error in BITMAP"); } } else if (strcmp(name, "BORDER") == 0) { int type; get_lex(); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_6502) { - cpu6502_1op("LDX", "#7"); - generic_interrupt_disable(); - cpu6502_1op("JSR", "WRTVDP"); - } else if (target == CPU_9900) { - /* this is just a lot faster inline than jumping through hoops... */ - cpu9900_2op("srl","r0","8"); - cpu9900_2op("ori","r0",">8700"); - cpu9900_1op("swpb","r0"); - generic_interrupt_disable(); - cpu9900_2op("movb","r0","@VDPWADR"); - cpu9900_1op("swpb","r0"); - cpu9900_2op("movb","r0","@VDPWADR"); + if (lex != C_COMMA) { + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_6502) { + cpu6502_1op("LDX", "#7"); + generic_interrupt_disable(); + cpu6502_1op("JSR", "WRTVDP"); + } else if (target == CPU_9900) { + /* this is just a lot faster inline than jumping through hoops... */ + cpu9900_2op("srl","r0","8"); + cpu9900_2op("ori","r0",">8700"); + cpu9900_1op("swpb","r0"); + generic_interrupt_disable(); + cpu9900_2op("movb","r0","@VDPWADR"); + cpu9900_1op("swpb","r0"); + cpu9900_2op("movb","r0","@VDPWADR"); + } else { + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "7"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + } + generic_interrupt_enable(); + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine != SMS) { + emit_error("The 2nd BORDER argument only available on Sega Master System"); + } else { + cpuz80_1op("AND", "$07"); + cpuz80_1op("OR", "$20"); + cpuz80_noop("RRCA"); + cpuz80_noop("RRCA"); + cpuz80_noop("RRCA"); + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "0"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + generic_interrupt_enable(); + } + } + } else if (strcmp(name, "SCROLL") == 0) { /* Sega Master System */ + int type; + + get_lex(); + if (machine != SMS) + emit_error("The SCROLL sentence is only available on Sega Master System"); + if (lex != C_COMMA) { + type = evaluate_expression(1, TYPE_8, 0); + if (machine == SMS) { + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "8"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + generic_interrupt_enable(); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == SMS) { + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "9"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + generic_interrupt_enable(); + } + } + } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System */ + int type; + struct node *source; + + get_lex(); + if (machine != SMS) + emit_error("The PALETTE sentence is only available on Sega Master System"); + if (lex == C_NAME && strcmp(name, "LOAD") == 0) { + get_lex(); + if (lex != C_NAME) { + emit_error("missing label in PALETTE LOAD"); + } else if (strcmp(name, "VARPTR") == 0) { + source = evaluate_save_expression(1, TYPE_16); /* CPU address (variable) */ + node_generate(source, 0); + node_delete(source); + } else { + if (machine == SMS) { + strcpy(temp, LABEL_PREFIX); + strcat(temp, name); + cpuz80_2op("LD", "HL", temp); + } + get_lex(); + } + generic_call("palette_load"); } else { - cpuz80_2op("LD", "B", "A"); - cpuz80_2op("LD", "C", "7"); generic_interrupt_disable(); - cpuz80_1op("CALL", "WRTVDP"); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == SMS) { + cpuz80_2op("LD", "L", "A"); + cpuz80_2op("LD", "H", "$C0"); + cpuz80_1op("CALL", "SETWRT"); + } + if (lex != C_COMMA) + emit_error("missing comma in PALETTE"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == SMS) { + cpuz80_2op("OUT", "(VDP)", "A"); + } + generic_interrupt_enable(); } - generic_interrupt_enable(); } else if (strcmp(name, "SIGNED") == 0) { struct signedness *c; @@ -4241,9 +4369,11 @@ void compile_statement(int check_for_else) get_lex(); addr = node_create(N_ADDR, 0, NULL, NULL); addr->label = array; - final = evaluate_level_0(&type); /* Source */ + final = evaluate_level_0(&type); /* Source offset */ if ((type & MAIN_TYPE) == TYPE_8) final = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, final, NULL); + if (machine == SMS) + final = node_create(N_MUL16, 0, final, node_create(N_NUM16, 2, NULL, NULL)); final = node_create(N_PLUS16, 0, addr, final); node_label(final); node_generate(final, 0); @@ -4262,10 +4392,12 @@ void compile_statement(int check_for_else) break; } get_lex(); - final = evaluate_level_0(&type); /* Target */ + final = evaluate_level_0(&type); /* Target offset */ if ((type & MAIN_TYPE) == TYPE_8) final = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, final, NULL); - final = node_create(N_PLUS16, 0, node_create(N_NUM16, 0x1800, NULL, NULL), final); + if (machine == SMS) + final = node_create(N_MUL16, 0, final, node_create(N_NUM16, 2, NULL, NULL)); + final = node_create(N_PLUS16, 0, node_create(N_NUM16, (machine == SMS ? 0x3800 : 0x1800), NULL, NULL), final); node_label(final); node_generate(final, 0); node_delete(final); @@ -4282,9 +4414,11 @@ void compile_statement(int check_for_else) break; } get_lex(); - final = evaluate_level_0(&type); /* Width */ + final = evaluate_level_0(&type); /* Source/target Width */ if ((type & MAIN_TYPE) == TYPE_16) final = node_create(N_REDUCE16, 0, final, NULL); + if (machine == SMS) + final = node_create(N_MUL8, 0, final, node_create(N_NUM8, 2, NULL, NULL)); node_label(final); node_generate(final, 0); node_delete(final); @@ -4300,7 +4434,7 @@ void compile_statement(int check_for_else) break; } get_lex(); - final = evaluate_level_0(&type); /* Height */ + final = evaluate_level_0(&type); /* Source/target height */ if ((type & MAIN_TYPE) == TYPE_16) final = node_create(N_REDUCE16, 0, final, NULL); node_label(final); @@ -4322,6 +4456,8 @@ void compile_statement(int check_for_else) } else { if ((type & MAIN_TYPE) == TYPE_16) final = node_create(N_REDUCE16, 0, final, NULL); + if (machine == SMS) + final = node_create(N_MUL8, 0, final, node_create(N_NUM8, 2, NULL, NULL)); } node_label(final); node_generate(final, 0); @@ -4386,8 +4522,8 @@ void compile_statement(int check_for_else) cpu9900_1op("data","LDIRVM"); } else { cpuz80_2op("LD", "HL", assigned); - cpuz80_2op("LD", "DE", "$1800"); - cpuz80_2op("LD", "BC", "$0300"); + cpuz80_2op("LD", "DE", (machine == SMS ? "$3800" : "$1800")); + cpuz80_2op("LD", "BC", (machine == SMS ? "$0600" : "$0300")); generic_interrupt_disable(); cpuz80_1op("CALL", "LDIRVM"); } diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 4664eea..76b8315 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -768,6 +768,7 @@ define_sprite: update_sprite: if SMS pop bc + add a,a ld (sprite_data+2),a pop af ld (sprite_data+1),a @@ -1166,13 +1167,13 @@ font_bitmaps: endif if SMS -set_palette: +palette_load: push hl di ld hl,$c000 call SETWRT pop hl - ld bc,16*256+VDP + ld bc,32*256+VDP outi jp nz,$-2 ei @@ -1184,13 +1185,13 @@ mode_4: call WRTVDP ld bc,$a201 call WRTVDP - ld bc,$0e02 ; $3800 for pattern table. + ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) call WRTVDP - ld bc,$ff03 ; Not used. + ld bc,$ff03 ; Not used (required value for SMS1) call WRTVDP - ld bc,$0304 ; Not used. + ld bc,$0704 ; Not used (required value for SMS1) call WRTVDP - ld bc,$7e05 ; $3f00 for sprite attribute table. + ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) call WRTVDP ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) call WRTVDP @@ -1231,11 +1232,13 @@ mode_4: ldir ei ld hl,.3 - call set_palette + call palette_load jp ENASCR - ; From https://www.smspower.org/Development/Palette -.3: db $00,$00,$08,$0c,$10,$30,$01,$3c,$02,$03,$05,$0f,$04,$33,$15,$3f + ; TMS9118-alike palette +.3: + db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f + db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f else vdp_generic_mode: @@ -1485,7 +1488,7 @@ nmi_handler: ld de,6 outi add hl,de - res 7,l + res 6,l jp nz,$-5 ld hl,$3f80 call SETWRT @@ -1493,17 +1496,17 @@ nmi_handler: add a,a or $80 ld l,a - ld h,sprites>>8 ld bc,$8000+VDP ld de,12 + ld h,sprites>>8 outi nop nop nop outi add hl,de - res 7,l - jp nz,$-10 + set 7,l + jp nz,$-12 .5: else ld bc,$8000+VDP diff --git a/examples/happy_face_sms.bas b/examples/happy_face_sms.bas new file mode 100644 index 0000000..81ea0ef --- /dev/null +++ b/examples/happy_face_sms.bas @@ -0,0 +1,71 @@ + ' + ' Bouncing happy face (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Feb/28/2024. + ' + + DEFINE SPRITE 0,2,happy_face + + PRINT AT 36,"Happy face!" + + x = 50 + y = 100 + dx = 1 + dy = 1 + +game_loop: + WAIT + WAIT + SPRITE 0,y-1,x,0 + SPRITE 1,y-1,x+8,1 + + x = x + dx + IF x = 0 THEN dx = -dx + IF x = 240 THEN dx = -dx + y = y + dy + IF y = 0 THEN dy = -dy + IF y = 176 THEN dy = -dy + GOTO game_loop + + ' The face includes the color for the sprite + ' A = Yellow in the default palette. + ' F = White + ' 4 = Yellow + ' 6 = Red +happy_face: + BITMAP "......AA" + BITMAP "....AAAA" + BITMAP "...AAAAA" + BITMAP "..AAAAAA" + BITMAP ".AAAAAAA" + BITMAP ".AAFFFAA" + BITMAP "AAAFFFAA" + BITMAP "AAAFF4AA" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + BITMAP ".AAAAAAA" + BITMAP ".AAA66AA" + BITMAP "..AAA666" + BITMAP "...AAA66" + BITMAP "....AAAA" + BITMAP "......AA" + + BITMAP "AA......" + BITMAP "AAAA...." + BITMAP "AAAAA..." + BITMAP "AAAAAA.." + BITMAP "AAAAAAA." + BITMAP "AAFFFAA." + BITMAP "AAFFFAAA" + BITMAP "AA4FFAAA" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAA." + BITMAP "AA66AAA." + BITMAP "666AAA.." + BITMAP "66AAA..." + BITMAP "AAAA...." + BITMAP "AA......" diff --git a/happy_face_sms.asm b/happy_face_sms.asm new file mode 100644 index 0000000..c1c4dcb --- /dev/null +++ b/happy_face_sms.asm @@ -0,0 +1,4304 @@ + ; CVBasic compiler v0.8.0 Apr/26/2025 + ; Command: ./cvbasic --sms examples/happy_face_sms.bas happy_face_sms.asm + ; Created: Sat Apr 26 19:18:25 2025 + +COLECO: equ 0 +SG1000: equ 0 +MSX: equ 0 +SGM: equ 0 +SVI: equ 0 +SORD: equ 0 +MEMOTECH: equ 0 +EINSTEIN: equ 0 +CPM: equ 0 +PENCIL: equ 0 +PV2000: equ 0 +TI99: equ 0 +NABU: equ 0 +SMS: equ 1 + +CVBASIC_MUSIC_PLAYER: equ 0 +CVBASIC_COMPRESSION: equ 0 +CVBASIC_BANK_SWITCHING: equ 0 + +BASE_RAM: equ $c000 ; Base of RAM +STACK: equ $e000 ; Base stack pointer +VDP: equ $be ; VDP port (write) +VDPR: equ $be ; VDP port (read) +PSG: equ $7f ; PSG port (write) + + ; + ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. + ; Added 16-bit multiply, division, modulo, and abs. + ; Added random generator. Added sound routines. + ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. + ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/14/2024. Added _sgn16. + ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. + ; Revision date: Apr/11/2024. Added support for formatting numbers. Added + ; support for Super Game Module. + ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. + ; Shorter mode setting subroutines. + ; Revision date: Apr/26/2024. Interruption handler saves current bank. + ; Revision date: Apr/27/2024. Music player now supports bank switching. + ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller + ; support with keyboard (code by SiRioKD) + ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. + ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. + ; Revision date: Jun/17/2024. Added SVI-328 support. + ; Revision date: Aug/01/2024. Added Sord M5 support. + ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech + ; support. + ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support + ; for Casio PV-2000. + ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, + ; and Casio PV-2000. + ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision + ; with flicker flag). + ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number + ; keys values were inverted. + ; Revision date: Nov/12/2024. Saves the VDP status. + ; + +JOYSEL: equ $c0 +KEYSEL: equ $80 + +JOY1: equ $fc-$20*(SG1000+SMS) +JOY2: equ $ff-$22*(SG1000+SMS) + + if COLECO + org $8000 + if PENCIL + db "COPYRIGHT SOUNDIC" + jp START + jp nmi_handler + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + db "CVBASIC!POWERED BY!2024!" + else + db $55,$aa + dw 0 + dw 0 + dw 0 + dw 0 + dw START + + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + + jp nmi_handler + endif + endif + if SG1000+SMS+SVI + org $0000 + di + ld sp,STACK + jp START + db $ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp nmi_handler ; It should be called int_handler. + endif + if MSX + ORG $4000 + db "AB" + dw START + dw $0000 + dw $0000 + dw $0000 + dw $0000 + +WRTPSG: equ $0093 +RDPSG: equ $0096 + + endif + if SORD + ORG $2000 + db $02 ; Avoid checking $4000 + dw START ; Start address. + dw $002e ; Prestart address (just point to RET in BIOS). + endif + if PV2000 + ORG $C000 + jp START + endif + + if MEMOTECH + if CPM + org $0100 + else + org $40fc + dw rom_start + dw rom_end-rom_start + endif +rom_start: + jp START + db 0,0,0,0,0 + dw nmi_handler + dw null_vector + dw null_vector + dw rom_start + +null_vector: + ei + reti + endif + if EINSTEIN + org $0100 +rom_start: + jp START + db 0,0,0,0,0 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + endif + if NABU + if CPM + org $0100 + else + org $140d + endif + nop + nop + nop + jp START + times $100-($&255) db $ff +nabu_int: + dw null_vector + dw null_vector + dw keyboard_handler + dw nmi_handler + dw null_vector + dw null_vector + dw null_vector + dw null_vector + +null_vector: + ei + reti + endif + + if SVI +WRTPSG: + out ($88),a + push af + ld a,e + out ($8c),a + pop af + ret + +RDPSG: + out ($88),a + push af + pop af + in a,($90) + ret + endif + + if EINSTEIN +WRTPSG: + out ($02),a + push af + ld a,e + out ($03),a + pop af + ret + +RDPSG: + out ($02),a + push af + pop af + in a,($02) + ret + endif + + if NABU +WRTPSG: + out ($41),a + push af + ld a,e + out ($40),a + pop af + ret + +RDPSG: + out ($41),a + push af + pop af + in a,($40) + ret + endif + + if PV2000 + ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) +WRTVDP: + ld a,b + ld (VDP+1),a + ld a,c + or $80 + ld (VDP+1),a + ret + +SETWRT: + ld a,l + ld (VDP+1),a + ld a,h + or $40 + ld (VDP+1),a + ret + +SETRD: + ld a,l + ld (VDP+1),a + ld a,h + and $3f + ld (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + ld (VDP),a + ret + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + ld a,(VDP) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: ld (VDP),a ; 13 14 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 37 42 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + ld a,(VDP) + ld (de),a + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + EX DE,HL + CALL SETWRT + EX DE,HL + DEC BC + INC C + LD A,B + LD B,C + INC A + LD C,A +.1: + LD A,(HL) ; 7 8 + LD (VDP),A ; 13 14 + INC HL ; 6 7 + DJNZ .1 ; 13 14 + DEC C ; 4 5 + JP NZ,.1 ; 10 11 + RET + else + ; Normal platforms with VDP connected via ports (IORQ) +WRTVDP: + ld a,b + out (VDP+1),a + ld a,c + or $80 + out (VDP+1),a + ret + +SETWRT: + ld a,l + out (VDP+1),a + ld a,h + or $40 + out (VDP+1),a + ret + +SETRD: + ld a,l + out (VDP+1),a + ld a,h + and $3f + out (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + out (VDP),a + ret + + if SG1000+SMS + db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Located at $0066 + ei ; NMI handler (pause button) + retn + endif + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + in a,(VDPR) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: out (VDP),a ; 11 12 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 35 40 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + in a,(VDP) + ld (de),a + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + ex de,hl + call SETWRT + ex de,hl + dec bc + inc c + ld a,b + ld b,c + inc a + ld c,VDP +.1: + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + outi + jp nz,.1 + dec a + jp nz,.1 + ret + endif + + if SMS + else +LDIRVM3: + call .1 + call .1 +.1: push hl + push de + push bc + call LDIRVM + pop bc + pop de + ld a,d + add a,8 + ld d,a + pop hl + ret + endif + +DISSCR: + call nmi_off + ld bc,$a201 + call WRTVDP + jp nmi_on + +ENASCR: + call nmi_off + ld bc,$e201 + call WRTVDP + jp nmi_on + +CPYBLK: + pop hl + ex af,af' + pop af + ld b,a + pop af + ld c,a + pop de + ex (sp),hl + call nmi_off +.1: push bc + push hl + push de + ld b,0 + call LDIRVM + pop hl + ld bc,$0020 + add hl,bc + ex de,hl + pop hl + ex af,af' + ld c,a + ld b,0 + add hl,bc + ex af,af' + pop bc + djnz .1 + jp nmi_on + +nmi_off: + if COLECO+PV2000 + push hl + ld hl,mode + set 0,(hl) + pop hl + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + di + endif + ret + +nmi_on: + if COLECO+PV2000 + push af + push hl + ld hl,mode + res 0,(hl) + nop + bit 1,(hl) + jp nz,nmi_handler.0 + pop hl + pop af + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + ei + endif + ret + + if COLECO +keypad_table: + db $0f,$08,$04,$05,$0c,$07,$0b,$02 + db $0d,$0a,$00,$09,$03,$01,$06,$0f + endif + +cls: + if SMS + ld hl,$3800 + ld (cursor),hl + di + call SETWRT +.1: ld a,$20 ; 7 + out (VDP),a ; 11 + inc hl ; 6 + inc hl ; 6 + ld a,$00 ; 7 + out (VDP),a ; 11 + ld a,h ; 4 + cp $3e ; 7 + jp nz,.1 ; 10 + ei + ret + else + ld hl,$1800 + ld (cursor),hl + ld bc,$0300 + ld a,$20 + call nmi_off + call FILVRM + jp nmi_on + endif + +print_string: + ld c,a + ld b,0 + ld de,(cursor) + if SMS + ld a,d + and $07 + or $38 + ld d,a + else + ld a,d + and $07 + or $18 + ld d,a + endif + push de + push bc + call nmi_off + if SMS + ex de,hl +.1: ld a,(de) + call WRTVRM + inc de + inc hl + xor a + call WRTVRM + inc hl + dec bc + ld a,b + or c + jp nz,.1 + else + call LDIRVM + endif + call nmi_on + pop bc + pop hl + add hl,bc + if SMS + add hl,bc + endif + ld (cursor),hl + ret + +print_number: + ld b,0 + call nmi_off +print_number5: + ld de,10000 + call print_digit +print_number4: + ld de,1000 + call print_digit +print_number3: + ld de,100 + call print_digit +print_number2: + ld de,10 + call print_digit +print_number1: + ld de,1 + ld b,e + call print_digit + jp nmi_on + +print_digit: + ld a,$2f + or a +.2: inc a + sbc hl,de + jp nc,.2 + add hl,de + cp $30 + jr nz,.3 + ld a,b + or a + ret z + dec a + jr z,.4 + ld a,c + jr print_char +.4: + ld a,$30 +.3: ld b,1 + +print_char: + push hl + ld hl,(cursor) + ex af,af' + ld a,h + and $07 + if SMS + or $38 + else + or $18 + endif + ld h,a + ex af,af' + call WRTVRM + inc hl + if SMS + xor a + call WRTVRM + inc hl + endif + ld (cursor),hl + pop hl + ret + +define_char: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + di + call LDIRVM + ei + ret + else + call nmi_off + ld a,(mode) + and 8 + jr nz,.1 + call LDIRVM3 + jp nmi_on + +.1: call LDIRVM + jp nmi_on + endif + +define_color: + if SMS + ret + else + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d + call nmi_off + call LDIRVM3 + jp nmi_on + endif + +define_sprite: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + if SMS + set 1,h + else + ld h,$07 + endif + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ex de,hl + call nmi_off + call LDIRVM + jp nmi_on + endif + +update_sprite: + if SMS + pop bc + add a,a + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + and $3f + ld e,a + ld d,sprites>>8 + ld a,(sprite_data) + ld (de),a + sla e + set 7,e + ld a,(sprite_data+1) + ld (de),a + inc e + ld a,(sprite_data+2) + ld (de),a + else + pop bc + ld (sprite_data+3),a + pop af + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + ld de,sprites + add a,a + add a,a + if SORD + or $80 + endif + ld e,a + ld hl,sprite_data + ld bc,4 + ldir + endif + ret + + ; Fast 16-bit multiplication. +_mul16: + ld b,h + ld c,l + ld a,16 + ld hl,0 +.1: + srl d + rr e + jr nc,.2 + add hl,bc +.2: sla c + rl b + dec a + jp nz,.1 + ret + + ; 16-bit signed modulo. + ; hl = hl % de +_mod16s: + ld a,h + or a + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _mod16 + pop af + ret p + jp _neg16 + + ; 16-bit signed division. + ; hl = hl / de +_div16s: + ld a,h + xor d + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _div16 + pop af + ret p + jp _neg16 + +_abs16: + bit 7,h + ret z +_neg16: + ld a,h + cpl + ld h,a + ld a,l + cpl + ld l,a + inc hl + ret + + ; Fast 16-bit division. + ; hl = hl / de +_div16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + rl c + rl b + ld h,b + ld l,c + ret + + ; Fast 16-bit modulo. +_mod16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + ret + +_sgn16: + ld a,h + or l + ret z + bit 7,h + ld hl,$ffff + ret nz + inc hl + inc hl + ret + + ; Random number generator. + ; From my game Mecha Eight. +random: + ld hl,(lfsr) + ld a,h + or l + jr nz,.0 + ld hl,$7811 +.0: ld a,h + and $80 + ld b,a + ld a,h + and $02 + rrca + rrca + xor b + ld b,a + ld a,h + and $01 + rrca + xor b + ld b,a + ld a,l + and $20 + rlca + rlca + xor b + rlca + rr h + rr l + ld (lfsr),hl + ret + +sn76489_freq: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld b,a + ld a,l + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + and $3f + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_vol: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + cpl + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_control: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + and $0f + or $e0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +ay3_reg: + if COLECO + push af + ld a,b + out ($50),a + pop af + out ($51),a + ret + endif + if SG1000+SORD+SMS+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,a + ld a,b + jp WRTPSG + endif + +ay3_freq: + if COLECO + out ($50),a + push af + ld a,l + out ($51),a + pop af + inc a + out ($50),a + push af + ld a,h + and $0f + out ($51),a + pop af + ret + endif + if SG1000+SMS+SORD+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,l + call WRTPSG + ld e,h + inc a + jp WRTPSG + endif + + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ; Required for SG1000 and Sega Master System as both don't have a BIOS + ; Required for SVI because we don't have access to BIOS in cartridge. + ; Required for Sord M5 because it doesn't provide an ASCII charset. + ; Required for Memotech/Einstein because CP/M uses the memory. + ; My personal font for TMS9928. + ; + ; Patterned after the TMS9928 programming manual 6x8 letters + ; with better lowercase letters, also I made a proper + ; AT sign. + ; +font_bitmaps: + db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space + db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! + db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " + db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # + db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ + db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % + db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & + db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' + db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( + db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) + db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * + db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + + db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , + db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - + db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . + db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / + db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 + db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 + db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 + db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 + db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 + db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 + db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 + db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 + db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 + db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 + db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : + db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; + db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < + db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = + db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > + db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? + db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ + db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A + db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B + db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C + db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D + db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E + db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F + db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G + db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H + db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I + db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J + db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K + db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L + db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M + db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N + db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O + db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P + db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q + db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R + db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S + db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T + db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U + db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V + db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W + db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X + db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y + db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z + db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ + db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ + db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] + db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E + db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ + db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 + db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a + db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b + db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c + db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d + db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e + db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f + db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g + db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h + db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i + db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j + db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k + db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l + db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m + db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n + db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o + db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p + db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q + db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r + db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s + db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t + db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u + db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v + db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w + db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x + db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y + db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z + db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { + db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | + db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } + db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e + db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f + endif + + if SMS +palette_load: + push hl + di + ld hl,$c000 + call SETWRT + pop hl + ld bc,32*256+VDP + outi + jp nz,$-2 + ei + ret + +mode_4: + di + ld bc,$0400 + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) + call WRTVDP + ld bc,$ff03 ; Not used (required value for SMS1) + call WRTVDP + ld bc,$0704 ; Not used (required value for SMS1) + call WRTVDP + ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) + call WRTVDP + ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) + call WRTVDP + ld bc,$0007 + call WRTVDP + ld bc,$0008 ; Background X scroll + call WRTVDP + ld bc,$0009 ; Background Y scroll + call WRTVDP + ld hl,$20*32 ; Point to space character bitmap + call SETWRT + ld hl,font_bitmaps + ld c,96 +.1: ld b,8 +.2: ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + inc hl + djnz .2 + dec c + jp nz,.1 + ei + call cls + di + ld hl,$3f00 + ld bc,$0040 + ld a,$e0 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,63 + ld (hl),$e0 + ldir + ei + ld hl,.3 + call palette_load + jp ENASCR + + ; TMS9118-alike palette +.3: + db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f + db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f + + else +vdp_generic_mode: + call nmi_off + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0602 ; $1800 for pattern table. + call WRTVDP + ld b,d + ld c,$03 ; for color table. + call WRTVDP + ld b,e + ld c,$04 ; for bitmap table. + call WRTVDP + ld bc,$3605 ; $1b00 for sprite attribute table. + call WRTVDP + ld bc,$0706 ; $3800 for sprites bitmaps. + call WRTVDP + ld bc,$0107 + jp WRTVDP + +mode_0: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls +vdp_generic_sprites: + call nmi_off + ld hl,$1b00 + ld bc,$0080 + ld a,$d1 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,127 + ld (hl),$d1 + ldir + call nmi_on + jp ENASCR + +mode_1: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld hl,$0000 + ld bc,$1800 + xor a + call FILVRM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + ld hl,$1800 +.1: call nmi_off + ld b,32 +.2: ld a,l + call WRTVRM + inc hl + djnz .2 + call nmi_on + ld a,h + cp $1b + jp nz,.1 + jp vdp_generic_sprites + +mode_2: + ld hl,mode + set 3,(hl) + ld bc,$0000 + ld de,$8000 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$0020 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites + endif + + if MSX +ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) +RSLREG: EQU $0138 ; Read slot status in A + + ; + ; Get slot mapping + ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) + ; A = Current slot selection status (CALL RSLREG) + ; +get_slot_mapping: + call rotate_slot + ld c,a + add a,$C1 ; EXPTBL + ld l,a + ld h,$FC + ld a,(hl) + and $80 ; Get expanded flag + or c + ld c,a + inc hl + inc hl + inc hl + inc hl + ld a,(hl) ; SLTTBL + call rotate_slot + rlca + rlca + or c ; A contains bit 7 = Marks expanded + ; bit 6 - 4 = Doesn't care + ; bit 3 - 2 = Secondary mapper + ; bit 1 - 0 = Primary mapper + ret + +rotate_slot: + push bc + dec b + inc b + jr z,.1 +.0: rrca + rrca + djnz .0 +.1: and 3 + pop bc + ret + + endif + +nmi_handler: + push af + push hl + ld hl,mode + bit 0,(hl) + jr z,.1 + set 1,(hl) + pop hl + pop af + retn + +.0: res 1,(hl) + +.1: push bc + push de + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fff) + endif + if MSX + ld a,($bfff) + endif + push af + endif + if SORD+MEMOTECH + call ctc_reti + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + in a,(VDPR+1) + ld (vdp_status),a + endif + + ; + ; Update of sprite attribute table + ; + if SMS + bit 2,(hl) + jr z,.4 + ld hl,$3f00 + call SETWRT + ld hl,sprites + ld bc,$4000+VDP + outi + jp nz,$-2 + ld hl,$3f80 + call SETWRT + ld hl,sprites + ld bc,$8000+VDP + outi + jp nz,$-2 + jr .5 + +.4: ld hl,$3f00 + call SETWRT + ld a,(flicker) + inc a + and $3f + ld (flicker),a + ld l,a + ld h,sprites>>8 + ld bc,$4000+VDP + ld de,6 + outi + add hl,de + res 6,l + jp nz,$-5 + ld hl,$3f80 + call SETWRT + ld a,(flicker) + add a,a + or $80 + ld l,a + ld bc,$8000+VDP + ld de,12 + ld h,sprites>>8 + outi + nop + nop + nop + outi + add hl,de + set 7,l + jp nz,$-12 +.5: + else + ld bc,$8000+VDP + bit 2,(hl) + jr z,.4 + + ld hl,$1b00 + call SETWRT + ld hl,sprites +.7: + if PV2000 + ld a,(hl) + ld (VDP),a + inc hl + djnz .7 + else + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp nz,.7 + endif + jr .5 + +.4: + ld hl,$1b00 + call SETWRT + ld a,(flicker) + add a,$04 + ld (flicker),a + ld de,24 + ld b,128 + ld l,a + if SORD + else + ld h,sprites>>8 + endif +.6: + if SORD + set 7,l + ld h,sprites>>8 + else + res 7,l + endif + if PV2000 + ld a,(hl) ; 7 8 + ld (VDP),a ; 13 14 + inc hl ; 6 7 + dec b ; 4 5 + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + else + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + endif + add hl,de + jp nz,.6 +.5: + endif + + if COLECO + out (JOYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + or $b0 + ld b,a + in a,(JOY2) + or $b0 + ld c,a + + out (KEYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + ld d,a + in a,(JOY2) + ld e,a + + ld a,d + rlca + or $7f + and b + cpl + ld (joy1_data),a + + ld a,e + rlca + or $7f + and c + cpl + ld (joy2_data),a + + ld a,d + and $0f + ld c,a + ld b,0 + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key1_data),a + + ld a,e + and $0f + ld c,a + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key2_data),a + endif + if SG1000+SMS + ld a,$07 + out ($de),a + ld b,$ff + in a,(JOY1) + ld h,a + in a,(JOY2) + ld l,a + in a,($de) + cp 7 + jp nz,.sg1000 + + ld a,$00 + out ($de),a + in a,($dc) + rra + ld c,1 + jr nc,.sg1 + in a,($dd) + rra + ld c,8 + jr nc,.sg1 + ld a,$01 + out ($de),a + in a,($dc) + rra + ld c,2 + jr nc,.sg1 + in a,($dd) + rra + ld c,9 + jr nc,.sg1 + ld a,$02 + out ($de),a + in a,($dc) + rra + ld c,3 + jr nc,.sg1 + in a,($dd) + rra + ld c,0 + jr nc,.sg1 + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a + ld c,10 + jr z,.sg1 + rra + ld c,4 + jr nc,.sg1 + ld a,$04 + out ($de),a + in a,($dc) + rra + ld c,5 + jr nc,.sg1 + ld a,$05 + out ($de),a + in a,($dc) + bit 6,a + ld c,11 + jr z,.sg1 + rra + ld c,6 + jr nc,.sg1 + ld a,$06 + out ($de),a + in a,($dc) + rra + ld c,7 + jr nc,.sg1 + ld c,15 +.sg1: ld a,c + ld (key1_data),a + + ld a,$04 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard down. + jr nz,$+4 + res 1,h + ld a,$05 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard left. + jr nz,$+4 + res 2,h + ld a,$06 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard right. + jr nz,$+4 + res 3,h + bit 6,a ; Keyboard up. + jr nz,$+4 + res 0,h + ld a,$02 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Ins + jr nz,$+4 + res 4,h + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Del + jr nz,$+4 + res 5,h +.sg1000: + bit 0,h + jr nz,$+4 + res 0,b + bit 1,h + jr nz,$+4 + res 2,b + bit 2,h + jr nz,$+4 + res 3,b + bit 3,h + jr nz,$+4 + res 1,b + bit 4,h + jr nz,$+4 + res 6,b + bit 5,h + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + + ld a,$ff + bit 6,h + jr nz,$+4 + res 0,a + bit 7,h + jr nz,$+4 + res 2,a + + bit 0,l + jr nz,$+4 + res 3,a + bit 1,l + jr nz,$+4 + res 1,a + bit 2,l + jr nz,$+4 + res 4,a + bit 3,l + jr nz,$+4 + res 5,a + cpl + ld (joy2_data),a + + endif + if MSX + ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php + ld a,15 + call RDPSG + and $b0 + or $4f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + ld b,$ff + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy2_data),a + + in a,($aa) + and $f0 + or $00 + out ($aa),a + in a,($a9) + cp $ff + ld c,$ff + jr nz,.key1 + in a,($aa) + and $f0 + or $01 + out ($aa),a + in a,($a9) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + in a,($aa) + and $f0 + or $07 + out ($aa),a + in a,($a9) + bit 5,a ; BS + ld c,$0a + jr z,.key2 + bit 7,a ; RET + ld c,$0b + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + in a,($aa) + and $f0 + or $08 + out ($aa),a + in a,($a9) + bit 5,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 6,a + jr nz,$+4 + res 2,b + bit 4,a + jr nz,$+4 + res 3,b + bit 0,a + jr nz,$+4 + res 6,b + in a,($aa) + and $f0 + or $04 + out ($aa),a + in a,($a9) + bit 2,a + jr nz,$+4 + res 7,b + + ld a,15 + call RDPSG + and $b0 + or $0f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + + ld a,b + cpl + ld (joy1_data),a + endif + if SVI + ld a,14 + call RDPSG + ld b,$ff + bit 4,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 5,a + jr nz,$+4 + res 2,b + bit 6,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 5,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy2_data),a + + ld a,$10 + out ($96),a + in a,($99) + cp $ff + ld c,$ff + jr nz,.key1 + ld a,$11 + out ($96),a + in a,($99) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + ld a,$16 + out ($96),a + in a,($99) + bit 6,a + ld c,$0b + jr z,.key2 + ld a,$15 + out ($96),a + in a,($99) + bit 6,a + ld c,$0a + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + ld a,$15 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 0,b + ld a,$18 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 1,b + ld a,$17 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 2,b + ld a,$16 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 3,b + ld a,$18 + out ($96),a + in a,($99) + bit 0,a + jr nz,$+4 + res 6,b + ld a,$13 + out ($96),a + in a,($99) + bit 5,a + jr nz,$+4 + res 7,b + + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 4,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy1_data),a + endif + if SORD + ld bc,$ffff + in a,($37) ; Read joystick + rra + jr nc,$+4 + res 1,b + rra + jr nc,$+4 + res 0,b + rra + jr nc,$+4 + res 3,b + rra + jr nc,$+4 + res 2,b + rra + jr nc,$+4 + res 1,c + rra + jr nc,$+4 + res 0,c + rra + jr nc,$+4 + res 3,c + rra + jr nc,$+4 + res 2,c + in a,($31) + rra + jr nc,$+4 + res 6,b + rra + jr nc,$+4 + res 7,b + rra + rra + rra + jr nc,$+4 + res 6,c + rra + jr nc,$+4 + res 7,c + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + in a,($31) ; Keyboard 1-8 + or a + ld c,$00 + jr nz,.key3 + in a,($35) + bit 0,a ; 9 + ld c,$09 + jr nz,.key5 + bit 1,a ; 0 + ld c,$00 + jr nz,.key5 + bit 7,a ; Backspace + ld c,$0a + jr nz,.key5 + in a,($30) + bit 7,a ; Enter + ld c,$0b + jr nz,.key5 + ld c,$0f + jr .key5 + +.key3: rra + inc c + jr nc,.key3 +.key5: + ld a,c + ld (key1_data),a + + endif + if MEMOTECH + ld bc,$ffff + + ld a,$fb + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 0,b ; Up direction. + bit 3,a ; Y + jr nz,$+4 + res 0,c ; Up direction. + + ld a,$ef + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 1,b ; Right key. + ld a,$bf + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 2,b ; Down key. + ld a,$f7 + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 3,b ; Left key. + ld a,$df + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a ; Home key. + jr nz,$+4 + res 6,b ; Button 1 + + ld a,$7F + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 2,a ; B + jr nz,$+4 + res 0,c ; Up key. + bit 1,a ; C + jr nz,$+4 + res 1,c ; Right key. + bit 3,a ; M + jr nz,$+4 + res 2,c ; Down key. + bit 0,a ; Z + jr nz,$+4 + res 3,c ; Left key. + bit 5,a ; - + jr nz,$+4 + res 7,c ; Button 2 for player 2. + bit 7,a ; - + jr nz,$+4 + res 7,b ; Button 2 for player 1. + in a,($06) ; Read keyboard data. + bit 0,a ; Space + jr nz,$+4 + res 6,c ; Button 1. + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$fe + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + ld b,1 + jr nc,.mt1 + rra + ld b,3 + jr nc,.mt1 + rra + ld b,5 + jr nc,.mt1 + rra + ld b,7 + jr nc,.mt1 + rra + ld b,9 + jr nc,.mt1 + ld a,$df + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + bit 6,a + ld b,11 + jr z,.mt1 + ld a,$fd + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + rra + ld b,2 + jr nc,.mt1 + rra + ld b,4 + jr nc,.mt1 + rra + ld b,6 + jr nc,.mt1 + rra + ld b,8 + jr nc,.mt1 + rra + ld b,0 + jr nc,.mt1 + in a,($06) + rra + ld b,10 + jr nc,.mt1 + ld b,15 +.mt1: + ld a,b + ld (key1_data),a + endif + if EINSTEIN + ld bc,$ffff + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 0,b ; Up + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 4,a + jr nz,$+4 + res 1,b ; Right + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + jr nz,$+4 + res 2,b ; Down + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + jr nz,$+4 + res 3,b ; Left + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 6,b ; Fire + ld a,$0e + out ($02),a + ld a,$7f + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 0,a + jr nz,$+4 + res 7,b ; 2nd fire + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$0e + out ($02),a + ld a,$ef + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + rra + ld b,7 + jr nc,.te1 + rra + ld b,6 + jr nc,.te1 + rra + ld b,5 + jr nc,.te1 + rra + ld b,4 + jr nc,.te1 + rra + ld b,3 + jr nc,.te1 + rra + ld b,2 + jr nc,.te1 + rra + ld b,1 + jr nc,.te1 + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + ld b,8 + jr z,.te1 + bit 4,a + ld b,10 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + ld b,9 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + ld b,11 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 7,a + ld b,0 + jr z,.te1 + ld b,15 +.te1: + ld a,b + ld (key1_data),a + endif + if PV2000 + ld bc,$ffff + ld a,7 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 0,b + bit 0,a + jr z,$+4 + res 3,b + ld a,6 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 1,b + bit 0,a + jr z,$+4 + res 2,b + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 0,a + jr z,$+4 + res 6,b + bit 1,a + jr z,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + ld a,0 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + and $0f + ld b,$04 + jr nz,.pv1 + in a,($10) + and $0f + ld b,$08 + jr nz,.pv1 + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($10) + ld b,11 + bit 0,a + jr nz,.pv2 + ld a,4 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + ld b,10 + bit 3,a + jr nz,.pv2 + in a,($10) + ld b,9 + bit 0,a + jr nz,.pv2 + ld b,0 + bit 3,a + jr nz,.pv2 + ld b,15 + jr .pv2 + +.pv1: rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b +.pv2: ld a,b + ld (key1_data),a + endif + if NABU + ld a,(nabu_data0) + and $cf + ld (joy1_data),a + ld a,(nabu_data1) + and $cf + ld (joy2_data),a + ld a,(nabu_data2) + ld (key1_data),a + ld a,$0f + ld (nabu_data2),a + endif + + if CVBASIC_MUSIC_PLAYER + ld a,(music_mode) + or a + call nz,music_hardware + endif + + ld hl,(frame) + inc hl + ld (frame),hl + + ld hl,lfsr ; Make LFSR more random + inc (hl) + inc (hl) + inc (hl) + + if CVBASIC_MUSIC_PLAYER + ; + ; Music is played with a 50hz clock. + ; + ld a,(ntsc) + or a + jr z,.2 + ld a,(music_tick) + inc a + cp 6 + jr nz,$+3 + xor a + ld (music_tick),a + jr z,.3 +.2: + ld a,(music_mode) + or a + call nz,music_generate +.3: + endif + + if CVBASIC_BANK_SWITCHING + pop af + if COLECO + ld l,a + ld h,$ff + ld a,(hl) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + pop de + pop bc + pop hl + if COLECO + in a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + if SG1000+SMS+SVI+NABU + pop af + ei + reti + endif + if MSX + pop af + ret + endif + if SORD+MEMOTECH + pop af + ei + ret + +ctc_reti: + reti + endif + if EINSTEIN + pop af + ret + endif + if PV2000 + ld a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + + if NABU +keyboard_handler: + push af + push bc + push hl + in a,($90) + ld c,a + cp $0d ; Enter + ld a,11 + jr z,.8 + ld a,c + cp $7f ; Del + ld a,10 + jr z,.8 + ld a,c + cp $30 + jr c,.7 + cp $3a + jr nc,.7 + sub $30 +.8: ld (nabu_data2),a + jr .1 +.7: + cp $a0 + jr c,.2 + cp $c0 + jr c,.joystick +.2: + ld hl,nabu_data0 + cp $80 + jr nz,.3 + res 4,(hl) + jr .1 +.3: + cp $81 + jr nz,.4 + set 4,(hl) + jr .1 +.4: + cp $e0 + jr c,.1 + and $0f + ld b,2 + jr z,.5 + dec a + ld b,8 + jr z,.5 + dec a + ld b,1 + jr z,.5 + dec a + ld b,4 + jr z,.5 + dec a + ld b,$80 + jr z,.5 + dec a + ld b,$40 + jr nz,.1 +.5: bit 4,c + jr nz,.6 + ld a,(hl) + or b + ld (hl),a + jr .1 + +.6: + ld a,b + cpl + and (hl) + ld (hl),a + jr .1 + +.joystick: + ld hl,nabu_data0 + bit 4,(hl) + jr z,$+5 + ld hl,nabu_data1 + ld b,$00 + bit 3,c + jr z,$+4 + set 0,b + bit 2,c + jr z,$+4 + set 1,b + bit 1,c + jr z,$+4 + set 2,b + bit 0,c + jr z,$+4 + set 3,b + bit 4,c + jr z,$+4 + set 6,b + ld (hl),b +.1: + pop hl + pop bc + pop af + ei + reti + endif + if SORD +wait: + ld de,(frame) +.1: + ld hl,(frame) + or a + sbc hl,de + jr z,.1 + ret + endif + if EINSTEIN +wait: + in a,(VDP+1) + nop + in a,(VDP+1) + bit 7,a + jr z,$-4 + ld (vdp_status),a + jp nmi_handler + endif + + ; + ; The music player code comes from my + ; game Princess Quest for Colecovision (2012) + ; + + ; + ; Init music player. + ; +music_init: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$9f + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$bf + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$df + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ff + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ec + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 +MIX_BASE: equ $b8 + endif + if EINSTEIN+NABU +MIX_BASE: equ $78 + endif + if MSX+SVI+EINSTEIN+NABU + ld a,$08 + ld e,$00 + call WRTPSG + ld a,$09 + ld e,$00 + call WRTPSG + ld a,$0a + ld e,$00 + call WRTPSG + ld a,$07 + ld e,MIX_BASE + call WRTPSG + endif + if SGM + ld b,$08 + xor a + call ay3_reg + ld b,$09 + call ay3_reg + ld b,$0a + call ay3_reg + ld b,$07 + ld a,$b8 + call ay3_reg + endif + if CVBASIC_MUSIC_PLAYER + else + ret + endif + + if CVBASIC_MUSIC_PLAYER + ld a,$ff + ld (audio_vol4hw),a + ld a,$ec + ld (audio_control),a + ld a,MIX_BASE + ld (audio_mix),a + ld hl,music_silence + ; + ; Play a music. + ; HL = Pointer to music. + ; +music_play: + call nmi_off + ld a,(hl) + ld (music_timing),a + inc hl + ld (music_start),hl + ld (music_pointer),hl + xor a + ld (music_note_counter),a + inc a + ld (music_playing),a + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fff) + endif + if MSX + ld a,($bfff) + endif + ld (music_bank),a + endif + jp nmi_on + + ; + ; Generates music. + ; +music_generate: + ld a,(audio_mix) + and $c0 + or $38 + ld (audio_mix),a + xor a ; Turn off all the sound channels. + ld l,a + ld h,a + ld (audio_vol1),hl ; audio_vol1/audio_vol2 + ld (audio_vol3),a + ld a,$ff + ld (audio_vol4hw),a + + ld a,(music_note_counter) + or a + jp nz,.6 + ld hl,(music_pointer) +.15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if COLECO + ld e,a + ld d,$ff + ld a,(de) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.16 + ld e,d + ld d,0 + jr .17 + +.16: rlca + jr nc,.17 + ld e,0 +.17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.19: cp -3 ; Repeat music? + jp nz,.0 + ld hl,(music_start) + jr .15 + +.0: ld a,(music_timing) + and $3f ; Restart note time. + ld (music_note_counter),a + ld a,b + cp $3f ; Sustain? + jr z,.1 + rlca + rlca + and 3 + ld (music_instrument_1),a + ld a,b + and $3f + ld (music_note_1),a + xor a + ld (music_counter_1),a +.1: ld a,c + cp $3f + jr z,.2 + rlca + rlca + and 3 + ld (music_instrument_2),a + ld a,c + and $3f + ld (music_note_2),a + xor a + ld (music_counter_2),a +.2: ld a,d + cp $3f + jr z,.3 + rlca + rlca + and 3 + ld (music_instrument_3),a + ld a,d + and $3f + ld (music_note_3),a + xor a + ld (music_counter_3),a +.3: ld a,e + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + +.6: ld a,(music_note_1) + or a + jr z,.7 + ld bc,(music_instrument_1) + call music_note2freq + ld (audio_freq1),hl + ld (audio_vol1),a + +.7: ld a,(music_note_2) + or a + jr z,.8 + ld bc,(music_instrument_2) + call music_note2freq + ld (audio_freq2),hl + ld (audio_vol2),a + +.8: ld a,(music_note_3) + or a + jr z,.9 + ld bc,(music_instrument_3) + call music_note2freq + ld (audio_freq3),hl + ld (audio_vol3),a + +.9: ld a,(music_drum) + or a + jr z,.4 + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + cp 3 + jp nc,.4 +.10: ld a,5 + ld (audio_noise),a + call enable_drum + jr .4 + +.5: dec a ; 2 - Short durm. + jr nz,.11 + ld a,(music_counter_4) + or a + jp nz,.4 + ld a,8 + ld (audio_noise),a + call enable_drum + jr .4 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + cp 2 + jp c,.10 + cp b + jp c,.4 + dec a + dec a + cp b + jp c,.10 +.4: + ld a,(music_counter_1) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_1),a + + ld a,(music_counter_2) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_2),a + + ld a,(music_counter_3) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_3),a + + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + + ; + ; Converts note to frequency. + ; Input: + ; A = Note (1-62). + ; B = Instrument counter. + ; C = Instrument. + ; Output: + ; HL = Frequency. + ; A = Volume. + ; +music_note2freq: + add a,a + ld e,a + ld d,0 + ld hl,music_notes_table + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ld a,c + or a + jp z,music_piano + dec a + jp z,music_clarinet + dec a + jp z,music_flute + ; + ; Bass instrument. + ; +music_bass: + add hl,hl + + ; + ; Piano instrument. + ; +music_piano: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ret + +.1: + db 12,11,11,10,10,9,9,8 + db 8,7,7,6,6,5,5,4 + db 4,4,5,5,4,4,3,3 + + ; + ; Clarinet instrument. + ; +music_clarinet: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + srl h + rr l + jp nc,.2 + inc hl +.2: ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + + db 13,14,14,13,13,12,12,12 + db 11,11,11,11,12,12,12,12 + db 11,11,11,11,12,12,12,12 + + ; + ; Flute instrument. + ; +music_flute: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + + db 10,12,13,13,12,12,12,12 + db 11,11,11,11,10,10,10,10 + db 11,11,11,11,10,10,10,10 + + ; + ; Emit sound. + ; +music_hardware: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.7 ; Yes, jump. + ld a,(audio_vol2) + or a + jp nz,.7 + ld a,(audio_vol3) + or a + jp z,.7 + ld (audio_vol2),a + xor a + ld (audio_vol3),a + ld hl,(audio_freq3) + ld (audio_freq2),hl +.7: + ld hl,(audio_freq1) + ld a,h + cp 4 + ld a,$9f + jp nc,.1 + ld a,l + and $0f + or $80 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol1) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $90 +.1: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld hl,(audio_freq2) + ld a,h + cp 4 + ld a,$bf + jp nc,.2 + ld a,l + and $0f + or $a0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol2) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $b0 +.2: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.6 ; Yes, jump. + + ld hl,(audio_freq3) + ld a,h + cp 4 + ld a,$df + jp nc,.3 + ld a,l + and $0f + or $c0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol3) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $d0 +.3: out (PSG),a + if MEMOTECH + in a,($03) + endif + +.6: + ld a,(music_mode) + and 1 ; NO DRUMS? + ret z ; Yes, return. + + ld a,(audio_vol4hw) + inc a + jr z,.4 + ld a,(audio_noise) + cp 16 + ld b,$ec + jp c,.5 + ld b,$ed +; ld b,$ee +.5: ld a,(audio_control) + cp b + jr z,.4 + ld a,b + ld (audio_control),a + out (PSG),a + if MEMOTECH + in a,($03) + endif +.4: ld a,(audio_vol4hw) + out (PSG),a + if MEMOTECH + in a,($03) + endif + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.8 ; Yes, jump. + ld hl,audio_freq1 + ld bc,$0b00 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret +.8: + ld hl,audio_freq1 + ld bc,$0400 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + inc hl + inc hl + inc c + inc c + ld a,(music_mode) + and 1 + jr z,.9 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + jr .10 +.9: inc hl + inc c + inc hl + inc c +.10: ld b,$02 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret + endif + + ; + ; Enable drum. + ; +enable_drum: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$f5 + ld (audio_vol4hw),a + else + ld hl,audio_mix + ld a,(audio_vol2) + or a + jr nz,.1 + ld a,10 + ld (audio_vol2),a + set 1,(hl) +.1: res 4,(hl) + endif + ret + + ; + ; Musical notes table. + ; +music_notes_table: + ; Silence - 0 + dw 0 + if MEMOTECH+EINSTEIN + ; Values for 4.00 mhz. + ; 2nd octave - Index 1 + dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 + ; 3rd octave - Index 13 + dw 956,902,851,804,758,716,676,638,602,568,536,506 + ; 4th octave - Index 25 + dw 478,451,426,402,379,358,338,319,301,284,268,253 + ; 5th octave - Index 37 + dw 239,225,213,201,190,179,169,159,150,142,134,127 + ; 6th octave - Index 49 + dw 119,113,106,100,95,89,84,80,75,71,67,63 + ; 7th octave - Index 61 + dw 60,56,53 + else + ; Values for 3.58 mhz. + ; 2nd octave - Index 1 + dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 + ; 3rd octave - Index 13 + dw 855,807,762,719,679,641,605,571,539,508,480,453 + ; 4th octave - Index 25 + dw 428,404,381,360,339,320,302,285,269,254,240,226 + ; 5th octave - Index 37 + dw 214,202,190,180,170,160,151,143,135,127,120,113 + ; 6th octave - Index 49 + dw 107,101,95,90,85,80,76,71,67,64,60,57 + ; 7th octave - Index 61 + dw 53,50,48 + endif + + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ; + ; Converts AY-3-8910 volume to SN76489 + ; +ay2sn: + db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 + endif + +music_silence: + db 8 + db 0,0,0,0 + db -2 + endif + + if CVBASIC_COMPRESSION +define_char_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + else + ld a,(mode) + and 8 + jp z,unpack3 + endif + jp unpack + + if SMS + else +define_color_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d +unpack3: + call .1 + call .1 +.1: + push de + push hl + call unpack + pop hl + pop de + ld a,d + add a,8 + ld d,a + ret + endif + + ; + ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) + ; +unpack: +; Initialization + ld a,(hl) + inc hl + exx + ld de,0 + add a,a + inc a + rl e + add a,a + rl e + add a,a + rl e + rl e + ld hl,.modes + add hl,de + ld c,(hl) + inc hl + ld b,(hl) + push bc + pop ix + ld e,1 + exx + ld iy,.loop + +; Main depack loop +.literal: + ex af,af' + call nmi_off + ld a,(hl) + ex de,hl + call WRTVRM + ex de,hl + inc hl + inc de + call nmi_on + ex af,af' +.loop: add a,a + call z,.getbit + jr nc,.literal + +; Compressed data + exx + ld h,d + ld l,e +.getlen: add a,a + call z,.getbitexx + jr nc,.lenok +.lus: add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr nc,.lenok + add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr c,.lus +.lenok: inc hl + exx + ld c,(hl) + inc hl + ld b,0 + bit 7,c + jr z,.offsok + jp (ix) + +.mode6: add a,a + call z,.getbit + rl b +.mode5: add a,a + call z,.getbit + rl b +.mode4: add a,a + call z,.getbit + rl b +.mode3: add a,a + call z,.getbit + rl b +.mode2: add a,a + call z,.getbit + rl b + add a,a + call z,.getbit + jr nc,.offsok + or a + inc b + res 7,c +.offsok: inc bc + push hl + exx + push hl + exx + ld l,e + ld h,d + sbc hl,bc + pop bc + ex af,af' +.loop2: + call nmi_off + call RDVRM ; unpack + ex de,hl + call WRTVRM + ex de,hl ; 4 + call nmi_on + inc hl ; 6 + inc de ; 6 + dec bc ; 6 + ld a,b ; 4 + or c ; 4 + jr nz,.loop2 ; 10 + ex af,af' + pop hl + jp (iy) + +.getbit: ld a,(hl) + inc hl + rla + ret + +.getbitexx: + exx + ld a,(hl) + inc hl + exx + rla + ret + +.modes: + dw .offsok + dw .mode2 + dw .mode3 + dw .mode4 + dw .mode5 + dw .mode6 + + endif + +START: + if SVI+SG1000+SMS + im 1 + endif + if MEMOTECH +Z80_CTC: equ $08 + endif + if EINSTEIN +Z80_CTC: equ $28 + endif + + if EINSTEIN+MEMOTECH + di + im 2 + ld a,rom_start>>8 + ld i,a + ld a,$03 ; Reset Z80 CTC + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + ld a,$08 ; Interrupt vector offset + out (Z80_CTC+0),a + endif + if MEMOTECH + ld a,$25 ; Disable channel 2 interrupt. + out (Z80_CTC+2),a + ld a,$9c + out (Z80_CTC+2),a + ld a,$25 ; Disable channel 1 interrupt. + out (Z80_CTC+1),a + ld a,$9c + out (Z80_CTC+1),a + ld a,$c5 ; Enable channel 0 interrupt (VDP). + out (Z80_CTC+0),a + ld a,$01 + out (Z80_CTC+0),a + endif + if SORD + ld hl,$186c ; Disable handling of CTC Channel 1 interruption. + ld ($7002),hl + ld hl,$7040 + set 0,(hl) ; Avoid BIOS VDP handling. + endif + if SVI + ld e,$00 + ld a,$08 + call WRTPSG + ld a,$09 + call WRTPSG + ld a,$0A + call WRTPSG + ld a,$07 + ld e,$b8 + call WRTPSG + ld a,$92 ; Setup 8255 for keyboard/joystick reading. + out ($97),a + endif + if SG1000+SMS + ; Contributed by SiRioKD + ld a,$9F ; Turn off PSG + out (PSG),a + ld a,$BF + out (PSG),a + ld a,$DF + out (PSG),a + ld a,$FF + out (PSG),a + ld a,$92 ; Setup 8255 for SC3000. + out ($df),a + endif + if SG1000+SMS+SVI + ; Wait for VDP ready (around 1000 ms) + ld b,11 + ld de,$FFFF +.delay1: + ld hl,$39DE +.delay2: + add hl,de + jr c,.delay2 + djnz .delay1 + else + di + ld sp,STACK + endif + if NABU + im 2 + ld a,nabu_int>>8 + ld i,a + ld a,$03 ; Disable ROM + out ($00),a + ld a,$07 + out ($41),a + ld a,$78 ; Setup output ports and mixer. + out ($40),a + ld a,$0e + out ($41),a + ld a,$30 ; Enable video and keyboard. + out ($40),a + endif + if PV2000 + ld hl,nmi_handler + ld ($7499),hl + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + else + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + endif + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffc0) ; Megacart + endif + if SG1000+SMS + ld a,1 ; Sega mapper + ld ($fffe),a + endif + if MSX + ld a,1 ; ASCII 16K + ld ($7000),a + endif + endif + if MEMOTECH+EINSTEIN+NABU + ld ix,(lfsr) + ld hl,ram_start + ld de,ram_start+1 + ld bc,ram_end-ram_start-1 + ld (hl),0 + ldir + ld (lfsr),ix + else + ld hl,(lfsr) ; Save RAM trash for random generator. + ld de,BASE_RAM + xor a + ld (de),a + inc de + if PV2000 + bit 7,d + else + bit 2,d + endif + jp z,$-4 + ld (lfsr),hl + endif + + if SGM +WRITE_REGISTER: equ $1fd9 +FILL_VRAM: equ $1f82 +WRITE_VRAM: equ $1fdf + + ld b,$00 ; First step. +.0: ld hl,$2000 ; RAM at $2000. +.1: ld (hl),h ; Try to write a byte. + inc h + jp p,.1 ; Repeat until reaching $8000. + ld h,$20 ; Go back at $2000. +.2: ld a,(hl) ; Read back byte. + cp h ; Is it correct? + jr nz,.3 ; No, jump. + inc h + jp p,.2 ; Repeat until reaching $8000. + jp .4 ; Memory valid! + +.3: ld a,$01 ; Enable SGM + out ($53),a + inc b + bit 1,b ; Already enabled? + jr z,.0 ; No, test RAM again. + + ld bc,$0000 + call WRITE_REGISTER + ld bc,$0180 + call WRITE_REGISTER + ld bc,$0206 + call WRITE_REGISTER + ld bc,$0380 + call WRITE_REGISTER + ld bc,$0400 + call WRITE_REGISTER + ld bc,$0536 + call WRITE_REGISTER + ld bc,$0607 + call WRITE_REGISTER + ld bc,$070D + call WRITE_REGISTER + ld bc,$03F0 + ld de,$00E8 + ld hl,$158B ; Note! direct access to Colecovision ROM + call WRITE_VRAM + ld hl,$2000 + ld de,32 + ld a,$FD + call FILL_VRAM + ld hl,$1B00 + ld de,128 + ld a,$D1 + call FILL_VRAM + ld hl,$1800 + ld de,769 + ld a,$20 + call FILL_VRAM + ld bc,$0020 + ld de,$1980 + ld hl,.5 + call WRITE_VRAM + ld bc,$01C0 + call WRITE_REGISTER + jr $ + +.5: db " SUPER GAME MODULE NOT DETECTED " + +.4: + ld ix,(lfsr) + ld hl,$2000 + ld de,$2001 + ld bc,$5FFF + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO + ld a,($0069) + cp 50 + ld a,1 + jr nz,$+3 + dec a + endif + if SG1000+SMS+SVI+SORD+PV2000+NABU + ld a,1 ; Always NTSC. + endif + if MEMOTECH+EINSTEIN + ld a,0 ; Always PAL. + endif + if MSX + call RSLREG + ld b,1 ; $4000-$7fff + call get_slot_mapping + ld h,$80 + call ENASLT ; Map into $8000-$BFFF + + ld a,($002b) + cpl + rlca + and $01 + endif + ld (ntsc),a + + call music_init + + xor a + ld (mode),a + if SMS + call mode_4 + else + call mode_0 + endif + + xor a + ld (joy1_data),a + ld (joy2_data),a + if NABU + ld (nabu_data0),a + ld (nabu_data1),a + endif + ld a,$0f + ld (key1_data),a + ld (key2_data),a + if NABU + ld (nabu_data2),a + endif + + if MSX + ld hl,nmi_handler + ld ($fd9b),hl + ld a,$c3 + ld ($fd9a),a + endif + if SORD + ld hl,nmi_handler + ld ($7006),hl + endif + + ; CVBasic program start. + ; ' + ; ' Bouncing happy face (demo for CVBasic) + ; ' + ; ' by Oscar Toledo G. + ; ' https://nanochess.org/ + ; ' + ; ' Creation date: Feb/28/2024. + ; ' + ; + ; DEFINE SPRITE 0,2,happy_face + LD HL,0 + PUSH HL + LD A,2 + LD HL,cvb_HAPPY_FACE + CALL define_sprite + ; + ; PRINT AT 36,"Happy face!" + LD HL,72 + LD (cursor),HL + LD HL,cv1 + LD A,11 + CALL print_string + JP cv2 +cv1: + DB $48,$61,$70,$70,$79,$20,$66,$61 + DB $63,$65,$21 +cv2: + ; + ; x = 50 + LD A,50 + LD (cvb_X),A + ; y = 100 + LD A,100 + LD (cvb_Y),A + ; dx = 1 + LD A,1 + LD (cvb_DX),A + ; dy = 1 + LD A,1 + LD (cvb_DY),A + ; + ; game_loop: +cvb_GAME_LOOP: + ; WAIT + HALT + ; WAIT + HALT + ; SPRITE 0,y-1,x,0 + SUB A + PUSH AF + LD A,(cvb_Y) + DEC A + PUSH AF + LD A,(cvb_X) + PUSH AF + SUB A + CALL update_sprite + ; SPRITE 1,y-1,x+8,1 + LD A,1 + PUSH AF + LD A,(cvb_Y) + DEC A + PUSH AF + LD A,(cvb_X) + ADD A,8 + PUSH AF + LD A,1 + CALL update_sprite + ; + ; x = x + dx + LD HL,cvb_X + LD A,(cvb_DX) + ADD A,(HL) + LD (HL),A + ; IF x = 0 THEN dx = -dx + LD A,(HL) + AND A + JP NZ,cv3 + LD A,(cvb_DX) + NEG + LD (cvb_DX),A +cv3: + ; IF x = 240 THEN dx = -dx + LD A,(cvb_X) + CP 240 + JP NZ,cv4 + LD A,(cvb_DX) + NEG + LD (cvb_DX),A +cv4: + ; y = y + dy + LD HL,cvb_Y + LD A,(cvb_DY) + ADD A,(HL) + LD (HL),A + ; IF y = 0 THEN dy = -dy + LD A,(HL) + AND A + JP NZ,cv5 + LD A,(cvb_DY) + NEG + LD (cvb_DY),A +cv5: + ; IF y = 176 THEN dy = -dy + LD A,(cvb_Y) + CP 176 + JP NZ,cv6 + LD A,(cvb_DY) + NEG + LD (cvb_DY),A +cv6: + ; GOTO game_loop + JP cvb_GAME_LOOP + ; + ; ' The face includes the color for the sprite + ; ' A = Yellow in the default palette. + ; happy_face: +cvb_HAPPY_FACE: + ; BITMAP "......AA" + ; BITMAP "....AAAA" + DB $00,$03,$00,$03,$00,$0f,$00,$0f + ; BITMAP "...AAAAA" + ; BITMAP "..AAAAAA" + DB $00,$1f,$00,$1f,$00,$3f,$00,$3f + ; BITMAP ".AAAAAAA" + ; BITMAP ".AAFFFAA" + DB $00,$7f,$00,$7f,$1c,$7f,$1c,$7f + ; BITMAP "AAAFFFAA" + ; BITMAP "AAAFF4AA" + DB $1c,$ff,$1c,$ff,$18,$fb,$1c,$fb + ; BITMAP "AAAAAAAA" + ; BITMAP "AAAAAAAA" + DB $00,$ff,$00,$ff,$00,$ff,$00,$ff + ; BITMAP ".AAAAAAA" + ; BITMAP ".AAA66AA" + DB $00,$7f,$00,$7f,$00,$7f,$0c,$73 + ; BITMAP "..AAA666" + ; BITMAP "...AAA66" + DB $00,$3f,$07,$38,$00,$1f,$03,$1c + ; BITMAP "....AAAA" + ; BITMAP "......AA" + DB $00,$0f,$00,$0f,$00,$03,$00,$03 + ; + ; BITMAP "AA......" + ; BITMAP "AAAA...." + DB $00,$c0,$00,$c0,$00,$f0,$00,$f0 + ; BITMAP "AAAAA..." + ; BITMAP "AAAAAA.." + DB $00,$f8,$00,$f8,$00,$fc,$00,$fc + ; BITMAP "AAAAAAA." + ; BITMAP "AAFFFAA." + DB $00,$fe,$00,$fe,$38,$fe,$38,$fe + ; BITMAP "AAFFFAAA" + ; BITMAP "AA4FFAAA" + DB $38,$ff,$38,$ff,$18,$df,$38,$df + ; BITMAP "AAAAAAAA" + ; BITMAP "AAAAAAAA" + DB $00,$ff,$00,$ff,$00,$ff,$00,$ff + ; BITMAP "AAAAAAA." + ; BITMAP "AA66AAA." + DB $00,$fe,$00,$fe,$00,$fe,$30,$ce + ; BITMAP "666AAA.." + ; BITMAP "66AAA..." + DB $00,$fc,$e0,$1c,$00,$f8,$c0,$38 + ; BITMAP "AAAA...." + ; BITMAP "AA......" + DB $00,$f0,$00,$f0,$00,$c0,$00,$c0 + ; + ; CVBasic epilogue (BASIC compiler for Colecovision) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and + ; read_pointer variables. + ; Revision date: Mar/04/2024. Added music player. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/13/2024. Added Pletter decompressor. + ; Revision date: Mar/19/2024. Added support for sprite flicker. + ; Revision date: Apr/11/2024. Added support for Super Game Module. + ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. + ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it + ; can remain accessible in bank 0 (bank switching). + ; Revision date: Aug/02/2024. Added rom_end label for Memotech. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. + ; Revision date: Nov/12/2024. Added vdp_status. + ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. + ; + +rom_end: + + ; ROM final size rounding + if MSX+COLECO+SG1000+SMS+SVI+SORD + TIMES (($+$1FFF)&$1e000)-$ DB $ff + endif + if MEMOTECH+EINSTEIN+NABU + ; Align following data to a 256-byte page. + TIMES $100-($&$ff) DB $4f + endif + if PV2000 + TIMES $10000-$ DB $ff + endif + if SG1000+SMS + forg $7FF0 + org $7FF0 + db "TMR SEGA" + db 0,0 + db 0,0 ; Checksum + db $11,$78 ; Product code + db $00 ; Version + db $4c ; SMS Export + 32KB for checksum + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 + org BASE_RAM + endif +ram_start: + +sprites: + if SMS + rb 256 + else + rb 128 + endif +sprite_data: + rb 4 +frame: + rb 2 +read_pointer: + rb 2 +cursor: + rb 2 +lfsr: + rb 2 +mode: + rb 1 +flicker: + rb 1 +joy1_data: + rb 1 +joy2_data: + rb 1 +key1_data: + rb 1 +key2_data: + rb 1 +ntsc: + rb 1 +vdp_status: + rb 1 + if NABU +nabu_data0: rb 1 +nabu_data1: rb 1 +nabu_data2: rb 1 + endif + + if CVBASIC_MUSIC_PLAYER +music_tick: rb 1 +music_mode: rb 1 + + if CVBASIC_BANK_SWITCHING +music_bank: rb 1 + endif +music_start: rb 2 +music_pointer: rb 2 +music_playing: rb 1 +music_timing: rb 1 +music_note_counter: rb 1 +music_instrument_1: rb 1 +music_counter_1: rb 1 +music_note_1: rb 1 +music_instrument_2: rb 1 +music_counter_2: rb 1 +music_note_2: rb 1 +music_instrument_3: rb 1 +music_counter_3: rb 1 +music_note_3: rb 1 +music_counter_4: rb 1 +music_drum: rb 1 + +audio_freq1: rb 2 +audio_freq2: rb 2 +audio_freq3: rb 2 +audio_noise: rb 1 +audio_mix: rb 1 +audio_vol1: rb 1 +audio_vol2: rb 1 +audio_vol3: rb 1 + +audio_control: rb 1 +audio_vol4hw: rb 1 + endif + + if SGM + org $2000 ; Start for variables. + endif +cvb_X: rb 1 +cvb_Y: rb 1 +cvb_DX: rb 1 +cvb_DY: rb 1 +ram_end: diff --git a/happy_face_sms.rom b/happy_face_sms.rom new file mode 100644 index 0000000000000000000000000000000000000000..f7efce55a586478a67653fa7c6b0e3f1567aabbc GIT binary patch literal 32768 zcmeI1U2Gd!701swjy+CNf23b2WXVj8N;VHow$&0`_QOXyA&Zlnq68_P^DN} zv~`fXu@ItuSRg_xH4jJ|QKYpHQi4R)J~JB4XFiN`E{M3VHY;+JT?O!oXQ&U{s_ovEFF?=fr(YfBy~zCo*!Lca2< zeBMJo*$6(tjt#S6sx)v^HZ~AmS4z2XSf^4hwXGNaK@AhGm2b$#57)h017BNOK(O*B zikE1Acm^^oD(jYtWinQMKEyDQ<|7IPKU2Icg`Ttsd4+^*v!z5|fr6}h|Gg8H3-7-y z9og2D_T;_Alf5nDU2a|TNNatvA*V#TQCXz0^C0x9Sspt^&x>b&ks{pR1zFF0l^wV3K3z1cq&Mm$8*gI352 zR=$t(e%*Cs@MK}wB@83q``B{QUcT-!Q+F4wl-g|O!(p?p%}Cu$#(Ch6z0|Tbd9DPvLc&F#B!YTn}umKr>C+X^Lp1P&^*DE%A6A zJx)q;I?-EID8Cp~VpCldn~qIqC$G_n60`kajm4B8;R#|+luam!ES40dj(|>coS*J! z7)FR>c&CXHnW^kzCPB)GD4-5q4vwVlQIlcU;**p0V36wRsw~S@(qidq2KGAkqrpET zK4MH_Ct@SGJ%~|>i7cW%qB=U#x?PgXE!%m-c}4!IH1fwYnR+He)l5cwU{9yhhzkX+ ziu~zn8g)5iTCCp}d9jFX8A^z1lmwwj*|twk=cgw#geYir%6yQ`3ct+aVs>f@{!oOU zNCpQ-2UwwteTbisu?~o$i9EKykny;!XR{w5UM4O|7we(~n@bG&k|UxeiNxt;qN*lZ zRh$zPc3WM1Z#&Ahsm#MDJ$NFwQO_0mcLdVYl<8?RW@CbU%;8uqOck^@`UB=OS@J)Mt-4 zKSqR$i%|fu?Nire1gzsLuTz(z#1y3q`|U<~MZpV`hhHokgiIt5I1#6{4VCh^UBT%eLGAm%MiA>CdfTPK9{*cLB|xok_HkSg{Lk-Fsak9g$QO1ZsH zI9S_P&^(P|g^+Skijlrjd6~vdOwZmq6ErIxfqW0dykslGo)cy@N|9I z@rmv;POJ|`_8DWxgmVb@`kf=z-NIjYwqX6%R(edzr9&NbEMK{Ux`fBGLeryrOAkHG zV;26c(R$PIoz$7VVU5xAlIu$M4pj*WHdwtM)0q)n2>dZ}08w@q4s=y2n}bYA%0ZJQ6eAMqP{ z)A|9FTUHA4wsjivO=}qP=hjyt-?F|1Iny5r7=3OdeAI2IZN~BA$KNwnYmLgV{$^=H zpTqMAPZQ7IaQ{{=ea!re(j!lMsM%B>e(}h_vtWIBPLh6v7i)LK-5;X-Oy_>_-|JW(LG%~XhaV?PUn4?!RfGp$lJ4p%X|8KO{Ny~0D2Gl zAo>JNbc^2XZgw@g8`RwCu+v1xD>UdGpq`d)dym+gN3WubyZ$NqHf;}x-W+IlJsNnl zw;y)e*509~E8SGj57>LKclU2F9+?0WU;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOyK{C0RH*GjR`OTCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB czyz286Zjtqyf}P8xp?}_DWcrpLrFUKPYdq&?f?J) literal 0 HcmV?d00001 diff --git a/manual.txt b/manual.txt index 1bc47d5..841b260 100644 --- a/manual.txt +++ b/manual.txt @@ -77,7 +77,9 @@ v0.5.1 Jun/25/2024 o Added SIGNED and UNSIGNED keywords to tag variables >>>>>>>>>>>>>>. Description -CVBasic is an integer BASIC compiler for Colecovision, MSX, Sega SG1000, Spectravideo SVI-318/328, Sord M5, Memotech MTX, and Creativision. It works as a cross-compiler over a PC and generates assembler code that can be processed by Gasm80. +CVBasic is an integer BASIC compiler for Colecovision, MSX, Sega SG1000, Spectravideo SVI-318/328, Sord M5, Memotech MTX, Creativision, Soundic Pencil II, Tatung Einstein, Casio PV-2000, TI-99/4A, NABU PC, and Sega Master System. + +It works as a cross-compiler over a PC and generates assembler code that can be processed by Gasm80. Platforms requirements: o PC with Windows XP or better. @@ -102,8 +104,10 @@ Usage: cvbasic --creativision in.bas output.asm cvbasic --pencil in.bas output.asm cvbasic --einstein in.bas output.asm + cvbasic --pv2000 in.bas output.asm cvbasic --ti994a in.bas output.a99 cvbasic --nabu in.bas output.asm + cvbasic --sms in.bas output.asm The following modules are automatically included as the prologue and epilogue of your generated code and they set important variables and helper code: @@ -481,7 +485,9 @@ The following statements are available: BITMAP statements or DATA BYTE statements. Each character is an 8x8 pixel bitmap (represented as 8 BITMAP statements or - 8 constants in a DATA BYTE statement). + 8 constants in a DATA BYTE statement). For Sega Master System, this is 32 + constants in a DATA BYTE statement because the character definition includes + color. Internally, CVBasic will replicate the data along the 3 display areas so the defined characters will appear on the whole screen when required. @@ -497,7 +503,7 @@ The following statements are available: DEFINE COLOR char_num,total,VARPTR array(expr) DEFINE COLOR PLETTER char_num,total,label - Loads color into VRAM. + Loads color into VRAM. This sentence isn't used on Sega Master System. "char_num" valid values are between 0 and 255. @@ -527,15 +533,15 @@ The following statements are available: Loads sprites into VRAM - "sprite_num" valid values are between 0 and 63. + "sprite_num" valid values are between 0 and 63 (127 for Sega Master System) - "total" valid values are between 1 and 64. + "total" valid values are between 1 and 64 (128 for Sega Master System) It replaces the definitions for "sprite_num", "total" means the total number of sprites to load, and "label" should point to a label containing BITMAP or DATA BYTE statements with the sprite or sprites representation. - Each sprite is 16x16 pixels. + Each sprite is 16x16 pixels (8x16 pixels for Sega Master System) The VARPTR expression allows sprite definition from an offset inside an array so you can do animation easily. @@ -614,6 +620,7 @@ The following statements are available: CAN BURN YOUR MSX HARDWARE. SPRITE index,y,x,f,c + SPRITE index,y,x,f The first parameter indicates the number of the sprite (0-31). @@ -630,6 +637,9 @@ The following statements are available: add the flag $80 (128 decimal) to displace the sprite by 32 pixels to the left. Allowing it to blend inside the screen from the left. + The fourth argument (color) isn't used on Sega Master System, and + it will generate an error from CVBasic if present. + Sprites are updated on the vertical retrace. The Y-coordinate visible range for sprites is 240 to 255, and 0 @@ -640,7 +650,8 @@ The following statements are available: Additionally, the value 208 for the Y-coordinate disables sprite processing starting on that very sprite. For example, - SPRITE 0,$d0,0,0,0 forces sprites 1-31 to disappear even if active. + SPRITE 0,$d0,0,0,0 forces sprites 1-31 to disappear even if active. + SPRITE FLICKER ON SPRITE FLICKER OFF @@ -706,9 +717,33 @@ The following statements are available: PRINT CHR$(65) BORDER color + BORDER color,flags Select the border color. It can be a number from 0 to 15. + The flags argument is available on Sega Master System. + bit 0 = Set column 0 to border color. + bit 1 = Horizontal scrolling disabled on rows 0-1. + bit 2 = Vertical scrolling disabled on columns 24-31. + + SCROLL x, y + + Sets the pixel scrolling for Sega Master System background. + + PALETTE register, color + PALETTE LOAD array_data_byte + PALETTE LOAD VARPTR array_data_byte(0) + + Sets a single palette register (0-31) to the color (0-63). Color bits are + specified in a single byte as 00BBGGRR (two bits each for red, green, and + blue). + + The registers 0-15 are for background tiles, and the registers 16-31 are + for sprites. The tiles can request to use the sprite colors. + + Alternatively, you can load a full 32 entries palette using PALETTE LOAD. + The array should be specified with DATA BYTE. + MODE 0 Select the video mode 0. In this mode, the 32x24 screen grid can have one @@ -744,6 +779,13 @@ The following statements are available: VRAM addresses $2000-$201f contain the color for the characters group. + MODE 4 + + It is only available on Sega Master System, and it is the only mode supported + in this console. VRAM $0000-$1fff are setup as background bitmaps, $2000-$37ff + for sprites bitmaps, $3800-$3dff for the background patterns, and $3f00-$3fff + for the sprites attributes. The unused portion $3e00-$3eff and $3f40-$3f7f + can be used for extra sprites (sprite numbers 120-123 and 125) SCREEN DISABLE @@ -785,6 +827,17 @@ The following statements are available: SCREEN tile,0,0,2,2 + For the Sega Master System the source offset, target offset, and width are + automatically multiplied by 2, because each character in the screen uses + two bytes in VRAM. The first byte referring to the tile number (0-255), and + the second byte specifies how it is used: + + bit 0 - Indicates to use tiles in the range 256-511 + bit 1 - Horizontal flip if set. + bit 2 - Vertical flip if set. + bit 3 - Uses sprite palette if set. + bit 4 - The tile will be drawn on top of sprites. + BITMAP "00000000" BITMAP "00001111" @@ -805,6 +858,10 @@ The following statements are available: Every other character will be interpreted as one. + For the Sega Master System, the colors are specified by using 1 to 9, + and A to F. + + PLAY SIMPLE PLAY SIMPLE NO DRUMS PLAY FULL diff --git a/music.asm b/music.asm new file mode 100644 index 0000000..7c5232d --- /dev/null +++ b/music.asm @@ -0,0 +1,4792 @@ + ; CVBasic compiler v0.8.0 Apr/26/2025 + ; Command: ./cvbasic --sms examples/music.bas music.asm + ; Created: Sat Apr 26 18:00:28 2025 + +COLECO: equ 0 +SG1000: equ 0 +MSX: equ 0 +SGM: equ 0 +SVI: equ 0 +SORD: equ 0 +MEMOTECH: equ 0 +EINSTEIN: equ 0 +CPM: equ 0 +PENCIL: equ 0 +PV2000: equ 0 +TI99: equ 0 +NABU: equ 0 +SMS: equ 1 + +CVBASIC_MUSIC_PLAYER: equ 1 +CVBASIC_COMPRESSION: equ 0 +CVBASIC_BANK_SWITCHING: equ 0 + +BASE_RAM: equ $c000 ; Base of RAM +STACK: equ $e000 ; Base stack pointer +VDP: equ $be ; VDP port (write) +VDPR: equ $be ; VDP port (read) +PSG: equ $7f ; PSG port (write) + + ; + ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. + ; Added 16-bit multiply, division, modulo, and abs. + ; Added random generator. Added sound routines. + ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. + ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/14/2024. Added _sgn16. + ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. + ; Revision date: Apr/11/2024. Added support for formatting numbers. Added + ; support for Super Game Module. + ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. + ; Shorter mode setting subroutines. + ; Revision date: Apr/26/2024. Interruption handler saves current bank. + ; Revision date: Apr/27/2024. Music player now supports bank switching. + ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller + ; support with keyboard (code by SiRioKD) + ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. + ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. + ; Revision date: Jun/17/2024. Added SVI-328 support. + ; Revision date: Aug/01/2024. Added Sord M5 support. + ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech + ; support. + ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support + ; for Casio PV-2000. + ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, + ; and Casio PV-2000. + ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision + ; with flicker flag). + ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number + ; keys values were inverted. + ; Revision date: Nov/12/2024. Saves the VDP status. + ; + +JOYSEL: equ $c0 +KEYSEL: equ $80 + +JOY1: equ $fc-$20*(SG1000+SMS) +JOY2: equ $ff-$22*(SG1000+SMS) + + if COLECO + org $8000 + if PENCIL + db "COPYRIGHT SOUNDIC" + jp START + jp nmi_handler + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + db "CVBASIC!POWERED BY!2024!" + else + db $55,$aa + dw 0 + dw 0 + dw 0 + dw 0 + dw START + + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + + jp nmi_handler + endif + endif + if SG1000+SMS+SVI + org $0000 + di + ld sp,STACK + jp START + db $ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp nmi_handler ; It should be called int_handler. + endif + if MSX + ORG $4000 + db "AB" + dw START + dw $0000 + dw $0000 + dw $0000 + dw $0000 + +WRTPSG: equ $0093 +RDPSG: equ $0096 + + endif + if SORD + ORG $2000 + db $02 ; Avoid checking $4000 + dw START ; Start address. + dw $002e ; Prestart address (just point to RET in BIOS). + endif + if PV2000 + ORG $C000 + jp START + endif + + if MEMOTECH + if CPM + org $0100 + else + org $40fc + dw rom_start + dw rom_end-rom_start + endif +rom_start: + jp START + db 0,0,0,0,0 + dw nmi_handler + dw null_vector + dw null_vector + dw rom_start + +null_vector: + ei + reti + endif + if EINSTEIN + org $0100 +rom_start: + jp START + db 0,0,0,0,0 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + endif + if NABU + if CPM + org $0100 + else + org $140d + endif + nop + nop + nop + jp START + times $100-($&255) db $ff +nabu_int: + dw null_vector + dw null_vector + dw keyboard_handler + dw nmi_handler + dw null_vector + dw null_vector + dw null_vector + dw null_vector + +null_vector: + ei + reti + endif + + if SVI +WRTPSG: + out ($88),a + push af + ld a,e + out ($8c),a + pop af + ret + +RDPSG: + out ($88),a + push af + pop af + in a,($90) + ret + endif + + if EINSTEIN +WRTPSG: + out ($02),a + push af + ld a,e + out ($03),a + pop af + ret + +RDPSG: + out ($02),a + push af + pop af + in a,($02) + ret + endif + + if NABU +WRTPSG: + out ($41),a + push af + ld a,e + out ($40),a + pop af + ret + +RDPSG: + out ($41),a + push af + pop af + in a,($40) + ret + endif + + if PV2000 + ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) +WRTVDP: + ld a,b + ld (VDP+1),a + ld a,c + or $80 + ld (VDP+1),a + ret + +SETWRT: + ld a,l + ld (VDP+1),a + ld a,h + or $40 + ld (VDP+1),a + ret + +SETRD: + ld a,l + ld (VDP+1),a + ld a,h + and $3f + ld (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + ld (VDP),a + ret + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + ld a,(VDP) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: ld (VDP),a ; 13 14 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 37 42 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + ld a,(VDP) + ld (de),a + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + EX DE,HL + CALL SETWRT + EX DE,HL + DEC BC + INC C + LD A,B + LD B,C + INC A + LD C,A +.1: + LD A,(HL) ; 7 8 + LD (VDP),A ; 13 14 + INC HL ; 6 7 + DJNZ .1 ; 13 14 + DEC C ; 4 5 + JP NZ,.1 ; 10 11 + RET + else + ; Normal platforms with VDP connected via ports (IORQ) +WRTVDP: + ld a,b + out (VDP+1),a + ld a,c + or $80 + out (VDP+1),a + ret + +SETWRT: + ld a,l + out (VDP+1),a + ld a,h + or $40 + out (VDP+1),a + ret + +SETRD: + ld a,l + out (VDP+1),a + ld a,h + and $3f + out (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + out (VDP),a + ret + + if SG1000+SMS + db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Located at $0066 + ei ; NMI handler (pause button) + retn + endif + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + in a,(VDPR) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: out (VDP),a ; 11 12 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 35 40 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + in a,(VDP) + ld (de),a + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + ex de,hl + call SETWRT + ex de,hl + dec bc + inc c + ld a,b + ld b,c + inc a + ld c,VDP +.1: + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + outi + jp nz,.1 + dec a + jp nz,.1 + ret + endif + + if SMS + else +LDIRVM3: + call .1 + call .1 +.1: push hl + push de + push bc + call LDIRVM + pop bc + pop de + ld a,d + add a,8 + ld d,a + pop hl + ret + endif + +DISSCR: + call nmi_off + ld bc,$a201 + call WRTVDP + jp nmi_on + +ENASCR: + call nmi_off + ld bc,$e201 + call WRTVDP + jp nmi_on + +CPYBLK: + pop hl + ex af,af' + pop af + ld b,a + pop af + ld c,a + pop de + ex (sp),hl + call nmi_off +.1: push bc + push hl + push de + ld b,0 + call LDIRVM + pop hl + ld bc,$0020 + add hl,bc + ex de,hl + pop hl + ex af,af' + ld c,a + ld b,0 + add hl,bc + ex af,af' + pop bc + djnz .1 + jp nmi_on + +nmi_off: + if COLECO+PV2000 + push hl + ld hl,mode + set 0,(hl) + pop hl + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + di + endif + ret + +nmi_on: + if COLECO+PV2000 + push af + push hl + ld hl,mode + res 0,(hl) + nop + bit 1,(hl) + jp nz,nmi_handler.0 + pop hl + pop af + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + ei + endif + ret + + if COLECO +keypad_table: + db $0f,$08,$04,$05,$0c,$07,$0b,$02 + db $0d,$0a,$00,$09,$03,$01,$06,$0f + endif + +cls: + if SMS + ld hl,$3800 + ld (cursor),hl + di + call SETWRT +.1: ld a,$20 ; 7 + out (VDP),a ; 11 + inc hl ; 6 + inc hl ; 6 + ld a,$00 ; 7 + out (VDP),a ; 11 + ld a,h ; 4 + cp $3e ; 7 + jp nz,.1 ; 10 + ei + ret + else + ld hl,$1800 + ld (cursor),hl + ld bc,$0300 + ld a,$20 + call nmi_off + call FILVRM + jp nmi_on + endif + +print_string: + ld c,a + ld b,0 + ld de,(cursor) + if SMS + ld a,d + and $07 + or $38 + ld d,a + else + ld a,d + and $07 + or $18 + ld d,a + endif + push de + push bc + call nmi_off + if SMS + ex de,hl +.1: ld a,(de) + call WRTVRM + inc de + inc hl + xor a + call WRTVRM + inc hl + dec bc + ld a,b + or c + jp nz,.1 + else + call LDIRVM + endif + call nmi_on + pop bc + pop hl + add hl,bc + if SMS + add hl,bc + endif + ld (cursor),hl + ret + +print_number: + ld b,0 + call nmi_off +print_number5: + ld de,10000 + call print_digit +print_number4: + ld de,1000 + call print_digit +print_number3: + ld de,100 + call print_digit +print_number2: + ld de,10 + call print_digit +print_number1: + ld de,1 + ld b,e + call print_digit + jp nmi_on + +print_digit: + ld a,$2f + or a +.2: inc a + sbc hl,de + jp nc,.2 + add hl,de + cp $30 + jr nz,.3 + ld a,b + or a + ret z + dec a + jr z,.4 + ld a,c + jr print_char +.4: + ld a,$30 +.3: ld b,1 + +print_char: + push hl + ld hl,(cursor) + ex af,af' + ld a,h + and $07 + if SMS + or $38 + else + or $18 + endif + ld h,a + ex af,af' + call WRTVRM + inc hl + if SMS + xor a + call WRTVRM + inc hl + endif + ld (cursor),hl + pop hl + ret + +define_char: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + di + call LDIRVM + ei + ret + else + call nmi_off + ld a,(mode) + and 8 + jr nz,.1 + call LDIRVM3 + jp nmi_on + +.1: call LDIRVM + jp nmi_on + endif + +define_color: + if SMS + ret + else + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d + call nmi_off + call LDIRVM3 + jp nmi_on + endif + +define_sprite: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + if SMS + set 1,h + else + ld h,$07 + endif + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ex de,hl + call nmi_off + call LDIRVM + jp nmi_on + endif + +update_sprite: + if SMS + pop bc + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + and $3f + ld e,a + ld d,sprites>>8 + ld a,(sprite_data) + ld (de),a + sla e + set 7,e + ld a,(sprite_data+1) + ld (de),a + inc e + ld a,(sprite_data+2) + ld (de),a + else + pop bc + ld (sprite_data+3),a + pop af + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + ld de,sprites + add a,a + add a,a + if SORD + or $80 + endif + ld e,a + ld hl,sprite_data + ld bc,4 + ldir + endif + ret + + ; Fast 16-bit multiplication. +_mul16: + ld b,h + ld c,l + ld a,16 + ld hl,0 +.1: + srl d + rr e + jr nc,.2 + add hl,bc +.2: sla c + rl b + dec a + jp nz,.1 + ret + + ; 16-bit signed modulo. + ; hl = hl % de +_mod16s: + ld a,h + or a + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _mod16 + pop af + ret p + jp _neg16 + + ; 16-bit signed division. + ; hl = hl / de +_div16s: + ld a,h + xor d + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _div16 + pop af + ret p + jp _neg16 + +_abs16: + bit 7,h + ret z +_neg16: + ld a,h + cpl + ld h,a + ld a,l + cpl + ld l,a + inc hl + ret + + ; Fast 16-bit division. + ; hl = hl / de +_div16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + rl c + rl b + ld h,b + ld l,c + ret + + ; Fast 16-bit modulo. +_mod16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + ret + +_sgn16: + ld a,h + or l + ret z + bit 7,h + ld hl,$ffff + ret nz + inc hl + inc hl + ret + + ; Random number generator. + ; From my game Mecha Eight. +random: + ld hl,(lfsr) + ld a,h + or l + jr nz,.0 + ld hl,$7811 +.0: ld a,h + and $80 + ld b,a + ld a,h + and $02 + rrca + rrca + xor b + ld b,a + ld a,h + and $01 + rrca + xor b + ld b,a + ld a,l + and $20 + rlca + rlca + xor b + rlca + rr h + rr l + ld (lfsr),hl + ret + +sn76489_freq: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld b,a + ld a,l + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + and $3f + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_vol: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + cpl + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_control: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + and $0f + or $e0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +ay3_reg: + if COLECO + push af + ld a,b + out ($50),a + pop af + out ($51),a + ret + endif + if SG1000+SORD+SMS+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,a + ld a,b + jp WRTPSG + endif + +ay3_freq: + if COLECO + out ($50),a + push af + ld a,l + out ($51),a + pop af + inc a + out ($50),a + push af + ld a,h + and $0f + out ($51),a + pop af + ret + endif + if SG1000+SMS+SORD+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,l + call WRTPSG + ld e,h + inc a + jp WRTPSG + endif + + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ; Required for SG1000 and Sega Master System as both don't have a BIOS + ; Required for SVI because we don't have access to BIOS in cartridge. + ; Required for Sord M5 because it doesn't provide an ASCII charset. + ; Required for Memotech/Einstein because CP/M uses the memory. + ; My personal font for TMS9928. + ; + ; Patterned after the TMS9928 programming manual 6x8 letters + ; with better lowercase letters, also I made a proper + ; AT sign. + ; +font_bitmaps: + db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space + db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! + db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " + db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # + db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ + db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % + db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & + db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' + db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( + db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) + db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * + db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + + db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , + db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - + db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . + db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / + db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 + db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 + db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 + db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 + db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 + db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 + db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 + db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 + db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 + db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 + db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : + db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; + db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < + db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = + db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > + db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? + db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ + db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A + db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B + db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C + db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D + db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E + db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F + db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G + db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H + db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I + db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J + db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K + db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L + db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M + db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N + db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O + db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P + db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q + db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R + db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S + db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T + db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U + db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V + db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W + db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X + db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y + db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z + db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ + db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ + db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] + db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E + db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ + db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 + db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a + db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b + db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c + db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d + db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e + db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f + db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g + db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h + db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i + db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j + db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k + db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l + db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m + db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n + db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o + db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p + db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q + db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r + db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s + db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t + db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u + db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v + db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w + db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x + db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y + db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z + db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { + db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | + db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } + db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e + db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f + endif + + if SMS +set_palette: + push hl + di + ld hl,$c000 + call SETWRT + pop hl + ld bc,16*256+VDP + outi + jp nz,$-2 + ei + ret + +mode_4: + di + ld bc,$0400 + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0e02 ; $3800 for pattern table. + call WRTVDP + ld bc,$ff03 ; Not used. + call WRTVDP + ld bc,$0304 ; Not used. + call WRTVDP + ld bc,$7e05 ; $3f00 for sprite attribute table. + call WRTVDP + ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) + call WRTVDP + ld bc,$0007 + call WRTVDP + ld bc,$0008 ; Background X scroll + call WRTVDP + ld bc,$0009 ; Background Y scroll + call WRTVDP + ld hl,$20*32 ; Point to space character bitmap + call SETWRT + ld hl,font_bitmaps + ld c,96 +.1: ld b,8 +.2: ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + inc hl + djnz .2 + dec c + jp nz,.1 + ei + call cls + di + ld hl,$3f00 + ld bc,$0040 + ld a,$e0 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,63 + ld (hl),$e0 + ldir + ei + ld hl,.3 + call set_palette + jp ENASCR + + ; TMS9118-alike palette. From https://www.smspower.org/Development/Palette +.3: db $00,$00,$08,$0c,$10,$30,$01,$3c,$02,$03,$05,$0f,$04,$33,$15,$3f + + else +vdp_generic_mode: + call nmi_off + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0602 ; $1800 for pattern table. + call WRTVDP + ld b,d + ld c,$03 ; for color table. + call WRTVDP + ld b,e + ld c,$04 ; for bitmap table. + call WRTVDP + ld bc,$3605 ; $1b00 for sprite attribute table. + call WRTVDP + ld bc,$0706 ; $3800 for sprites bitmaps. + call WRTVDP + ld bc,$0107 + jp WRTVDP + +mode_0: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls +vdp_generic_sprites: + call nmi_off + ld hl,$1b00 + ld bc,$0080 + ld a,$d1 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,127 + ld (hl),$d1 + ldir + call nmi_on + jp ENASCR + +mode_1: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld hl,$0000 + ld bc,$1800 + xor a + call FILVRM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + ld hl,$1800 +.1: call nmi_off + ld b,32 +.2: ld a,l + call WRTVRM + inc hl + djnz .2 + call nmi_on + ld a,h + cp $1b + jp nz,.1 + jp vdp_generic_sprites + +mode_2: + ld hl,mode + set 3,(hl) + ld bc,$0000 + ld de,$8000 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$0020 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites + endif + + if MSX +ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) +RSLREG: EQU $0138 ; Read slot status in A + + ; + ; Get slot mapping + ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) + ; A = Current slot selection status (CALL RSLREG) + ; +get_slot_mapping: + call rotate_slot + ld c,a + add a,$C1 ; EXPTBL + ld l,a + ld h,$FC + ld a,(hl) + and $80 ; Get expanded flag + or c + ld c,a + inc hl + inc hl + inc hl + inc hl + ld a,(hl) ; SLTTBL + call rotate_slot + rlca + rlca + or c ; A contains bit 7 = Marks expanded + ; bit 6 - 4 = Doesn't care + ; bit 3 - 2 = Secondary mapper + ; bit 1 - 0 = Primary mapper + ret + +rotate_slot: + push bc + dec b + inc b + jr z,.1 +.0: rrca + rrca + djnz .0 +.1: and 3 + pop bc + ret + + endif + +nmi_handler: + push af + push hl + ld hl,mode + bit 0,(hl) + jr z,.1 + set 1,(hl) + pop hl + pop af + retn + +.0: res 1,(hl) + +.1: push bc + push de + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fff) + endif + if MSX + ld a,($bfff) + endif + push af + endif + if SORD+MEMOTECH + call ctc_reti + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + in a,(VDPR+1) + ld (vdp_status),a + endif + + ; + ; Update of sprite attribute table + ; + if SMS + bit 2,(hl) + jr z,.4 + ld hl,$3f00 + call SETWRT + ld hl,sprites + ld bc,$4000+VDP + outi + jp nz,$-2 + ld hl,$3f80 + call SETWRT + ld hl,sprites + ld bc,$8000+VDP + outi + jp nz,$-2 + jr .5 + +.4: ld hl,$3f00 + call SETWRT + ld a,(flicker) + inc a + and $3f + ld (flicker),a + ld l,a + ld h,sprites>>8 + ld bc,$4000+VDP + ld de,6 + outi + add hl,de + res 7,l + jp nz,$-5 + ld hl,$3f80 + call SETWRT + ld a,(flicker) + add a,a + or $80 + ld l,a + ld h,sprites>>8 + ld bc,$8000+VDP + ld de,12 + outi + nop + nop + nop + outi + add hl,de + res 7,l + jp nz,$-10 +.5: + else + ld bc,$8000+VDP + bit 2,(hl) + jr z,.4 + + ld hl,$1b00 + call SETWRT + ld hl,sprites +.7: + if PV2000 + ld a,(hl) + ld (VDP),a + inc hl + djnz .7 + else + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp nz,.7 + endif + jr .5 + +.4: + ld hl,$1b00 + call SETWRT + ld a,(flicker) + add a,$04 + ld (flicker),a + ld de,24 + ld b,128 + ld l,a + if SORD + else + ld h,sprites>>8 + endif +.6: + if SORD + set 7,l + ld h,sprites>>8 + else + res 7,l + endif + if PV2000 + ld a,(hl) ; 7 8 + ld (VDP),a ; 13 14 + inc hl ; 6 7 + dec b ; 4 5 + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + else + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + endif + add hl,de + jp nz,.6 +.5: + endif + + if COLECO + out (JOYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + or $b0 + ld b,a + in a,(JOY2) + or $b0 + ld c,a + + out (KEYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + ld d,a + in a,(JOY2) + ld e,a + + ld a,d + rlca + or $7f + and b + cpl + ld (joy1_data),a + + ld a,e + rlca + or $7f + and c + cpl + ld (joy2_data),a + + ld a,d + and $0f + ld c,a + ld b,0 + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key1_data),a + + ld a,e + and $0f + ld c,a + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key2_data),a + endif + if SG1000+SMS + ld a,$07 + out ($de),a + ld b,$ff + in a,(JOY1) + ld h,a + in a,(JOY2) + ld l,a + in a,($de) + cp 7 + jp nz,.sg1000 + + ld a,$00 + out ($de),a + in a,($dc) + rra + ld c,1 + jr nc,.sg1 + in a,($dd) + rra + ld c,8 + jr nc,.sg1 + ld a,$01 + out ($de),a + in a,($dc) + rra + ld c,2 + jr nc,.sg1 + in a,($dd) + rra + ld c,9 + jr nc,.sg1 + ld a,$02 + out ($de),a + in a,($dc) + rra + ld c,3 + jr nc,.sg1 + in a,($dd) + rra + ld c,0 + jr nc,.sg1 + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a + ld c,10 + jr z,.sg1 + rra + ld c,4 + jr nc,.sg1 + ld a,$04 + out ($de),a + in a,($dc) + rra + ld c,5 + jr nc,.sg1 + ld a,$05 + out ($de),a + in a,($dc) + bit 6,a + ld c,11 + jr z,.sg1 + rra + ld c,6 + jr nc,.sg1 + ld a,$06 + out ($de),a + in a,($dc) + rra + ld c,7 + jr nc,.sg1 + ld c,15 +.sg1: ld a,c + ld (key1_data),a + + ld a,$04 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard down. + jr nz,$+4 + res 1,h + ld a,$05 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard left. + jr nz,$+4 + res 2,h + ld a,$06 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard right. + jr nz,$+4 + res 3,h + bit 6,a ; Keyboard up. + jr nz,$+4 + res 0,h + ld a,$02 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Ins + jr nz,$+4 + res 4,h + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Del + jr nz,$+4 + res 5,h +.sg1000: + bit 0,h + jr nz,$+4 + res 0,b + bit 1,h + jr nz,$+4 + res 2,b + bit 2,h + jr nz,$+4 + res 3,b + bit 3,h + jr nz,$+4 + res 1,b + bit 4,h + jr nz,$+4 + res 6,b + bit 5,h + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + + ld a,$ff + bit 6,h + jr nz,$+4 + res 0,a + bit 7,h + jr nz,$+4 + res 2,a + + bit 0,l + jr nz,$+4 + res 3,a + bit 1,l + jr nz,$+4 + res 1,a + bit 2,l + jr nz,$+4 + res 4,a + bit 3,l + jr nz,$+4 + res 5,a + cpl + ld (joy2_data),a + + endif + if MSX + ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php + ld a,15 + call RDPSG + and $b0 + or $4f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + ld b,$ff + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy2_data),a + + in a,($aa) + and $f0 + or $00 + out ($aa),a + in a,($a9) + cp $ff + ld c,$ff + jr nz,.key1 + in a,($aa) + and $f0 + or $01 + out ($aa),a + in a,($a9) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + in a,($aa) + and $f0 + or $07 + out ($aa),a + in a,($a9) + bit 5,a ; BS + ld c,$0a + jr z,.key2 + bit 7,a ; RET + ld c,$0b + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + in a,($aa) + and $f0 + or $08 + out ($aa),a + in a,($a9) + bit 5,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 6,a + jr nz,$+4 + res 2,b + bit 4,a + jr nz,$+4 + res 3,b + bit 0,a + jr nz,$+4 + res 6,b + in a,($aa) + and $f0 + or $04 + out ($aa),a + in a,($a9) + bit 2,a + jr nz,$+4 + res 7,b + + ld a,15 + call RDPSG + and $b0 + or $0f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + + ld a,b + cpl + ld (joy1_data),a + endif + if SVI + ld a,14 + call RDPSG + ld b,$ff + bit 4,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 5,a + jr nz,$+4 + res 2,b + bit 6,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 5,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy2_data),a + + ld a,$10 + out ($96),a + in a,($99) + cp $ff + ld c,$ff + jr nz,.key1 + ld a,$11 + out ($96),a + in a,($99) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + ld a,$16 + out ($96),a + in a,($99) + bit 6,a + ld c,$0b + jr z,.key2 + ld a,$15 + out ($96),a + in a,($99) + bit 6,a + ld c,$0a + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + ld a,$15 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 0,b + ld a,$18 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 1,b + ld a,$17 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 2,b + ld a,$16 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 3,b + ld a,$18 + out ($96),a + in a,($99) + bit 0,a + jr nz,$+4 + res 6,b + ld a,$13 + out ($96),a + in a,($99) + bit 5,a + jr nz,$+4 + res 7,b + + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 4,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy1_data),a + endif + if SORD + ld bc,$ffff + in a,($37) ; Read joystick + rra + jr nc,$+4 + res 1,b + rra + jr nc,$+4 + res 0,b + rra + jr nc,$+4 + res 3,b + rra + jr nc,$+4 + res 2,b + rra + jr nc,$+4 + res 1,c + rra + jr nc,$+4 + res 0,c + rra + jr nc,$+4 + res 3,c + rra + jr nc,$+4 + res 2,c + in a,($31) + rra + jr nc,$+4 + res 6,b + rra + jr nc,$+4 + res 7,b + rra + rra + rra + jr nc,$+4 + res 6,c + rra + jr nc,$+4 + res 7,c + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + in a,($31) ; Keyboard 1-8 + or a + ld c,$00 + jr nz,.key3 + in a,($35) + bit 0,a ; 9 + ld c,$09 + jr nz,.key5 + bit 1,a ; 0 + ld c,$00 + jr nz,.key5 + bit 7,a ; Backspace + ld c,$0a + jr nz,.key5 + in a,($30) + bit 7,a ; Enter + ld c,$0b + jr nz,.key5 + ld c,$0f + jr .key5 + +.key3: rra + inc c + jr nc,.key3 +.key5: + ld a,c + ld (key1_data),a + + endif + if MEMOTECH + ld bc,$ffff + + ld a,$fb + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 0,b ; Up direction. + bit 3,a ; Y + jr nz,$+4 + res 0,c ; Up direction. + + ld a,$ef + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 1,b ; Right key. + ld a,$bf + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 2,b ; Down key. + ld a,$f7 + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 3,b ; Left key. + ld a,$df + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a ; Home key. + jr nz,$+4 + res 6,b ; Button 1 + + ld a,$7F + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 2,a ; B + jr nz,$+4 + res 0,c ; Up key. + bit 1,a ; C + jr nz,$+4 + res 1,c ; Right key. + bit 3,a ; M + jr nz,$+4 + res 2,c ; Down key. + bit 0,a ; Z + jr nz,$+4 + res 3,c ; Left key. + bit 5,a ; - + jr nz,$+4 + res 7,c ; Button 2 for player 2. + bit 7,a ; - + jr nz,$+4 + res 7,b ; Button 2 for player 1. + in a,($06) ; Read keyboard data. + bit 0,a ; Space + jr nz,$+4 + res 6,c ; Button 1. + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$fe + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + ld b,1 + jr nc,.mt1 + rra + ld b,3 + jr nc,.mt1 + rra + ld b,5 + jr nc,.mt1 + rra + ld b,7 + jr nc,.mt1 + rra + ld b,9 + jr nc,.mt1 + ld a,$df + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + bit 6,a + ld b,11 + jr z,.mt1 + ld a,$fd + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + rra + ld b,2 + jr nc,.mt1 + rra + ld b,4 + jr nc,.mt1 + rra + ld b,6 + jr nc,.mt1 + rra + ld b,8 + jr nc,.mt1 + rra + ld b,0 + jr nc,.mt1 + in a,($06) + rra + ld b,10 + jr nc,.mt1 + ld b,15 +.mt1: + ld a,b + ld (key1_data),a + endif + if EINSTEIN + ld bc,$ffff + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 0,b ; Up + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 4,a + jr nz,$+4 + res 1,b ; Right + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + jr nz,$+4 + res 2,b ; Down + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + jr nz,$+4 + res 3,b ; Left + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 6,b ; Fire + ld a,$0e + out ($02),a + ld a,$7f + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 0,a + jr nz,$+4 + res 7,b ; 2nd fire + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$0e + out ($02),a + ld a,$ef + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + rra + ld b,7 + jr nc,.te1 + rra + ld b,6 + jr nc,.te1 + rra + ld b,5 + jr nc,.te1 + rra + ld b,4 + jr nc,.te1 + rra + ld b,3 + jr nc,.te1 + rra + ld b,2 + jr nc,.te1 + rra + ld b,1 + jr nc,.te1 + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + ld b,8 + jr z,.te1 + bit 4,a + ld b,10 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + ld b,9 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + ld b,11 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 7,a + ld b,0 + jr z,.te1 + ld b,15 +.te1: + ld a,b + ld (key1_data),a + endif + if PV2000 + ld bc,$ffff + ld a,7 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 0,b + bit 0,a + jr z,$+4 + res 3,b + ld a,6 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 1,b + bit 0,a + jr z,$+4 + res 2,b + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 0,a + jr z,$+4 + res 6,b + bit 1,a + jr z,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + ld a,0 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + and $0f + ld b,$04 + jr nz,.pv1 + in a,($10) + and $0f + ld b,$08 + jr nz,.pv1 + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($10) + ld b,11 + bit 0,a + jr nz,.pv2 + ld a,4 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + ld b,10 + bit 3,a + jr nz,.pv2 + in a,($10) + ld b,9 + bit 0,a + jr nz,.pv2 + ld b,0 + bit 3,a + jr nz,.pv2 + ld b,15 + jr .pv2 + +.pv1: rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b +.pv2: ld a,b + ld (key1_data),a + endif + if NABU + ld a,(nabu_data0) + and $cf + ld (joy1_data),a + ld a,(nabu_data1) + and $cf + ld (joy2_data),a + ld a,(nabu_data2) + ld (key1_data),a + ld a,$0f + ld (nabu_data2),a + endif + + if CVBASIC_MUSIC_PLAYER + ld a,(music_mode) + or a + call nz,music_hardware + endif + + ld hl,(frame) + inc hl + ld (frame),hl + + ld hl,lfsr ; Make LFSR more random + inc (hl) + inc (hl) + inc (hl) + + if CVBASIC_MUSIC_PLAYER + ; + ; Music is played with a 50hz clock. + ; + ld a,(ntsc) + or a + jr z,.2 + ld a,(music_tick) + inc a + cp 6 + jr nz,$+3 + xor a + ld (music_tick),a + jr z,.3 +.2: + ld a,(music_mode) + or a + call nz,music_generate +.3: + endif + + if CVBASIC_BANK_SWITCHING + pop af + if COLECO + ld l,a + ld h,$ff + ld a,(hl) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + pop de + pop bc + pop hl + if COLECO + in a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + if SG1000+SMS+SVI+NABU + pop af + ei + reti + endif + if MSX + pop af + ret + endif + if SORD+MEMOTECH + pop af + ei + ret + +ctc_reti: + reti + endif + if EINSTEIN + pop af + ret + endif + if PV2000 + ld a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + + if NABU +keyboard_handler: + push af + push bc + push hl + in a,($90) + ld c,a + cp $0d ; Enter + ld a,11 + jr z,.8 + ld a,c + cp $7f ; Del + ld a,10 + jr z,.8 + ld a,c + cp $30 + jr c,.7 + cp $3a + jr nc,.7 + sub $30 +.8: ld (nabu_data2),a + jr .1 +.7: + cp $a0 + jr c,.2 + cp $c0 + jr c,.joystick +.2: + ld hl,nabu_data0 + cp $80 + jr nz,.3 + res 4,(hl) + jr .1 +.3: + cp $81 + jr nz,.4 + set 4,(hl) + jr .1 +.4: + cp $e0 + jr c,.1 + and $0f + ld b,2 + jr z,.5 + dec a + ld b,8 + jr z,.5 + dec a + ld b,1 + jr z,.5 + dec a + ld b,4 + jr z,.5 + dec a + ld b,$80 + jr z,.5 + dec a + ld b,$40 + jr nz,.1 +.5: bit 4,c + jr nz,.6 + ld a,(hl) + or b + ld (hl),a + jr .1 + +.6: + ld a,b + cpl + and (hl) + ld (hl),a + jr .1 + +.joystick: + ld hl,nabu_data0 + bit 4,(hl) + jr z,$+5 + ld hl,nabu_data1 + ld b,$00 + bit 3,c + jr z,$+4 + set 0,b + bit 2,c + jr z,$+4 + set 1,b + bit 1,c + jr z,$+4 + set 2,b + bit 0,c + jr z,$+4 + set 3,b + bit 4,c + jr z,$+4 + set 6,b + ld (hl),b +.1: + pop hl + pop bc + pop af + ei + reti + endif + if SORD +wait: + ld de,(frame) +.1: + ld hl,(frame) + or a + sbc hl,de + jr z,.1 + ret + endif + if EINSTEIN +wait: + in a,(VDP+1) + nop + in a,(VDP+1) + bit 7,a + jr z,$-4 + ld (vdp_status),a + jp nmi_handler + endif + + ; + ; The music player code comes from my + ; game Princess Quest for Colecovision (2012) + ; + + ; + ; Init music player. + ; +music_init: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$9f + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$bf + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$df + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ff + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ec + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 +MIX_BASE: equ $b8 + endif + if EINSTEIN+NABU +MIX_BASE: equ $78 + endif + if MSX+SVI+EINSTEIN+NABU + ld a,$08 + ld e,$00 + call WRTPSG + ld a,$09 + ld e,$00 + call WRTPSG + ld a,$0a + ld e,$00 + call WRTPSG + ld a,$07 + ld e,MIX_BASE + call WRTPSG + endif + if SGM + ld b,$08 + xor a + call ay3_reg + ld b,$09 + call ay3_reg + ld b,$0a + call ay3_reg + ld b,$07 + ld a,$b8 + call ay3_reg + endif + if CVBASIC_MUSIC_PLAYER + else + ret + endif + + if CVBASIC_MUSIC_PLAYER + ld a,$ff + ld (audio_vol4hw),a + ld a,$ec + ld (audio_control),a + ld a,MIX_BASE + ld (audio_mix),a + ld hl,music_silence + ; + ; Play a music. + ; HL = Pointer to music. + ; +music_play: + call nmi_off + ld a,(hl) + ld (music_timing),a + inc hl + ld (music_start),hl + ld (music_pointer),hl + xor a + ld (music_note_counter),a + inc a + ld (music_playing),a + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fff) + endif + if MSX + ld a,($bfff) + endif + ld (music_bank),a + endif + jp nmi_on + + ; + ; Generates music. + ; +music_generate: + ld a,(audio_mix) + and $c0 + or $38 + ld (audio_mix),a + xor a ; Turn off all the sound channels. + ld l,a + ld h,a + ld (audio_vol1),hl ; audio_vol1/audio_vol2 + ld (audio_vol3),a + ld a,$ff + ld (audio_vol4hw),a + + ld a,(music_note_counter) + or a + jp nz,.6 + ld hl,(music_pointer) +.15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if COLECO + ld e,a + ld d,$ff + ld a,(de) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.16 + ld e,d + ld d,0 + jr .17 + +.16: rlca + jr nc,.17 + ld e,0 +.17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.19: cp -3 ; Repeat music? + jp nz,.0 + ld hl,(music_start) + jr .15 + +.0: ld a,(music_timing) + and $3f ; Restart note time. + ld (music_note_counter),a + ld a,b + cp $3f ; Sustain? + jr z,.1 + rlca + rlca + and 3 + ld (music_instrument_1),a + ld a,b + and $3f + ld (music_note_1),a + xor a + ld (music_counter_1),a +.1: ld a,c + cp $3f + jr z,.2 + rlca + rlca + and 3 + ld (music_instrument_2),a + ld a,c + and $3f + ld (music_note_2),a + xor a + ld (music_counter_2),a +.2: ld a,d + cp $3f + jr z,.3 + rlca + rlca + and 3 + ld (music_instrument_3),a + ld a,d + and $3f + ld (music_note_3),a + xor a + ld (music_counter_3),a +.3: ld a,e + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + +.6: ld a,(music_note_1) + or a + jr z,.7 + ld bc,(music_instrument_1) + call music_note2freq + ld (audio_freq1),hl + ld (audio_vol1),a + +.7: ld a,(music_note_2) + or a + jr z,.8 + ld bc,(music_instrument_2) + call music_note2freq + ld (audio_freq2),hl + ld (audio_vol2),a + +.8: ld a,(music_note_3) + or a + jr z,.9 + ld bc,(music_instrument_3) + call music_note2freq + ld (audio_freq3),hl + ld (audio_vol3),a + +.9: ld a,(music_drum) + or a + jr z,.4 + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + cp 3 + jp nc,.4 +.10: ld a,5 + ld (audio_noise),a + call enable_drum + jr .4 + +.5: dec a ; 2 - Short durm. + jr nz,.11 + ld a,(music_counter_4) + or a + jp nz,.4 + ld a,8 + ld (audio_noise),a + call enable_drum + jr .4 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + cp 2 + jp c,.10 + cp b + jp c,.4 + dec a + dec a + cp b + jp c,.10 +.4: + ld a,(music_counter_1) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_1),a + + ld a,(music_counter_2) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_2),a + + ld a,(music_counter_3) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_3),a + + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + + ; + ; Converts note to frequency. + ; Input: + ; A = Note (1-62). + ; B = Instrument counter. + ; C = Instrument. + ; Output: + ; HL = Frequency. + ; A = Volume. + ; +music_note2freq: + add a,a + ld e,a + ld d,0 + ld hl,music_notes_table + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ld a,c + or a + jp z,music_piano + dec a + jp z,music_clarinet + dec a + jp z,music_flute + ; + ; Bass instrument. + ; +music_bass: + add hl,hl + + ; + ; Piano instrument. + ; +music_piano: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ret + +.1: + db 12,11,11,10,10,9,9,8 + db 8,7,7,6,6,5,5,4 + db 4,4,5,5,4,4,3,3 + + ; + ; Clarinet instrument. + ; +music_clarinet: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + srl h + rr l + jp nc,.2 + inc hl +.2: ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + + db 13,14,14,13,13,12,12,12 + db 11,11,11,11,12,12,12,12 + db 11,11,11,11,12,12,12,12 + + ; + ; Flute instrument. + ; +music_flute: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + + db 10,12,13,13,12,12,12,12 + db 11,11,11,11,10,10,10,10 + db 11,11,11,11,10,10,10,10 + + ; + ; Emit sound. + ; +music_hardware: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.7 ; Yes, jump. + ld a,(audio_vol2) + or a + jp nz,.7 + ld a,(audio_vol3) + or a + jp z,.7 + ld (audio_vol2),a + xor a + ld (audio_vol3),a + ld hl,(audio_freq3) + ld (audio_freq2),hl +.7: + ld hl,(audio_freq1) + ld a,h + cp 4 + ld a,$9f + jp nc,.1 + ld a,l + and $0f + or $80 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol1) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $90 +.1: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld hl,(audio_freq2) + ld a,h + cp 4 + ld a,$bf + jp nc,.2 + ld a,l + and $0f + or $a0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol2) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $b0 +.2: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.6 ; Yes, jump. + + ld hl,(audio_freq3) + ld a,h + cp 4 + ld a,$df + jp nc,.3 + ld a,l + and $0f + or $c0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol3) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $d0 +.3: out (PSG),a + if MEMOTECH + in a,($03) + endif + +.6: + ld a,(music_mode) + and 1 ; NO DRUMS? + ret z ; Yes, return. + + ld a,(audio_vol4hw) + inc a + jr z,.4 + ld a,(audio_noise) + cp 16 + ld b,$ec + jp c,.5 + ld b,$ed +; ld b,$ee +.5: ld a,(audio_control) + cp b + jr z,.4 + ld a,b + ld (audio_control),a + out (PSG),a + if MEMOTECH + in a,($03) + endif +.4: ld a,(audio_vol4hw) + out (PSG),a + if MEMOTECH + in a,($03) + endif + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.8 ; Yes, jump. + ld hl,audio_freq1 + ld bc,$0b00 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret +.8: + ld hl,audio_freq1 + ld bc,$0400 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + inc hl + inc hl + inc c + inc c + ld a,(music_mode) + and 1 + jr z,.9 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + jr .10 +.9: inc hl + inc c + inc hl + inc c +.10: ld b,$02 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret + endif + + ; + ; Enable drum. + ; +enable_drum: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$f5 + ld (audio_vol4hw),a + else + ld hl,audio_mix + ld a,(audio_vol2) + or a + jr nz,.1 + ld a,10 + ld (audio_vol2),a + set 1,(hl) +.1: res 4,(hl) + endif + ret + + ; + ; Musical notes table. + ; +music_notes_table: + ; Silence - 0 + dw 0 + if MEMOTECH+EINSTEIN + ; Values for 4.00 mhz. + ; 2nd octave - Index 1 + dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 + ; 3rd octave - Index 13 + dw 956,902,851,804,758,716,676,638,602,568,536,506 + ; 4th octave - Index 25 + dw 478,451,426,402,379,358,338,319,301,284,268,253 + ; 5th octave - Index 37 + dw 239,225,213,201,190,179,169,159,150,142,134,127 + ; 6th octave - Index 49 + dw 119,113,106,100,95,89,84,80,75,71,67,63 + ; 7th octave - Index 61 + dw 60,56,53 + else + ; Values for 3.58 mhz. + ; 2nd octave - Index 1 + dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 + ; 3rd octave - Index 13 + dw 855,807,762,719,679,641,605,571,539,508,480,453 + ; 4th octave - Index 25 + dw 428,404,381,360,339,320,302,285,269,254,240,226 + ; 5th octave - Index 37 + dw 214,202,190,180,170,160,151,143,135,127,120,113 + ; 6th octave - Index 49 + dw 107,101,95,90,85,80,76,71,67,64,60,57 + ; 7th octave - Index 61 + dw 53,50,48 + endif + + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ; + ; Converts AY-3-8910 volume to SN76489 + ; +ay2sn: + db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 + endif + +music_silence: + db 8 + db 0,0,0,0 + db -2 + endif + + if CVBASIC_COMPRESSION +define_char_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + else + ld a,(mode) + and 8 + jp z,unpack3 + endif + jp unpack + + if SMS + else +define_color_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d +unpack3: + call .1 + call .1 +.1: + push de + push hl + call unpack + pop hl + pop de + ld a,d + add a,8 + ld d,a + ret + endif + + ; + ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) + ; +unpack: +; Initialization + ld a,(hl) + inc hl + exx + ld de,0 + add a,a + inc a + rl e + add a,a + rl e + add a,a + rl e + rl e + ld hl,.modes + add hl,de + ld c,(hl) + inc hl + ld b,(hl) + push bc + pop ix + ld e,1 + exx + ld iy,.loop + +; Main depack loop +.literal: + ex af,af' + call nmi_off + ld a,(hl) + ex de,hl + call WRTVRM + ex de,hl + inc hl + inc de + call nmi_on + ex af,af' +.loop: add a,a + call z,.getbit + jr nc,.literal + +; Compressed data + exx + ld h,d + ld l,e +.getlen: add a,a + call z,.getbitexx + jr nc,.lenok +.lus: add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr nc,.lenok + add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr c,.lus +.lenok: inc hl + exx + ld c,(hl) + inc hl + ld b,0 + bit 7,c + jr z,.offsok + jp (ix) + +.mode6: add a,a + call z,.getbit + rl b +.mode5: add a,a + call z,.getbit + rl b +.mode4: add a,a + call z,.getbit + rl b +.mode3: add a,a + call z,.getbit + rl b +.mode2: add a,a + call z,.getbit + rl b + add a,a + call z,.getbit + jr nc,.offsok + or a + inc b + res 7,c +.offsok: inc bc + push hl + exx + push hl + exx + ld l,e + ld h,d + sbc hl,bc + pop bc + ex af,af' +.loop2: + call nmi_off + call RDVRM ; unpack + ex de,hl + call WRTVRM + ex de,hl ; 4 + call nmi_on + inc hl ; 6 + inc de ; 6 + dec bc ; 6 + ld a,b ; 4 + or c ; 4 + jr nz,.loop2 ; 10 + ex af,af' + pop hl + jp (iy) + +.getbit: ld a,(hl) + inc hl + rla + ret + +.getbitexx: + exx + ld a,(hl) + inc hl + exx + rla + ret + +.modes: + dw .offsok + dw .mode2 + dw .mode3 + dw .mode4 + dw .mode5 + dw .mode6 + + endif + +START: + if SVI+SG1000+SMS + im 1 + endif + if MEMOTECH +Z80_CTC: equ $08 + endif + if EINSTEIN +Z80_CTC: equ $28 + endif + + if EINSTEIN+MEMOTECH + di + im 2 + ld a,rom_start>>8 + ld i,a + ld a,$03 ; Reset Z80 CTC + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + ld a,$08 ; Interrupt vector offset + out (Z80_CTC+0),a + endif + if MEMOTECH + ld a,$25 ; Disable channel 2 interrupt. + out (Z80_CTC+2),a + ld a,$9c + out (Z80_CTC+2),a + ld a,$25 ; Disable channel 1 interrupt. + out (Z80_CTC+1),a + ld a,$9c + out (Z80_CTC+1),a + ld a,$c5 ; Enable channel 0 interrupt (VDP). + out (Z80_CTC+0),a + ld a,$01 + out (Z80_CTC+0),a + endif + if SORD + ld hl,$186c ; Disable handling of CTC Channel 1 interruption. + ld ($7002),hl + ld hl,$7040 + set 0,(hl) ; Avoid BIOS VDP handling. + endif + if SVI + ld e,$00 + ld a,$08 + call WRTPSG + ld a,$09 + call WRTPSG + ld a,$0A + call WRTPSG + ld a,$07 + ld e,$b8 + call WRTPSG + ld a,$92 ; Setup 8255 for keyboard/joystick reading. + out ($97),a + endif + if SG1000+SMS + ; Contributed by SiRioKD + ld a,$9F ; Turn off PSG + out (PSG),a + ld a,$BF + out (PSG),a + ld a,$DF + out (PSG),a + ld a,$FF + out (PSG),a + ld a,$92 ; Setup 8255 for SC3000. + out ($df),a + endif + if SG1000+SMS+SVI + ; Wait for VDP ready (around 1000 ms) + ld b,11 + ld de,$FFFF +.delay1: + ld hl,$39DE +.delay2: + add hl,de + jr c,.delay2 + djnz .delay1 + else + di + ld sp,STACK + endif + if NABU + im 2 + ld a,nabu_int>>8 + ld i,a + ld a,$03 ; Disable ROM + out ($00),a + ld a,$07 + out ($41),a + ld a,$78 ; Setup output ports and mixer. + out ($40),a + ld a,$0e + out ($41),a + ld a,$30 ; Enable video and keyboard. + out ($40),a + endif + if PV2000 + ld hl,nmi_handler + ld ($7499),hl + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + else + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + endif + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffc0) ; Megacart + endif + if SG1000+SMS + ld a,1 ; Sega mapper + ld ($fffe),a + endif + if MSX + ld a,1 ; ASCII 16K + ld ($7000),a + endif + endif + if MEMOTECH+EINSTEIN+NABU + ld ix,(lfsr) + ld hl,ram_start + ld de,ram_start+1 + ld bc,ram_end-ram_start-1 + ld (hl),0 + ldir + ld (lfsr),ix + else + ld hl,(lfsr) ; Save RAM trash for random generator. + ld de,BASE_RAM + xor a + ld (de),a + inc de + if PV2000 + bit 7,d + else + bit 2,d + endif + jp z,$-4 + ld (lfsr),hl + endif + + if SGM +WRITE_REGISTER: equ $1fd9 +FILL_VRAM: equ $1f82 +WRITE_VRAM: equ $1fdf + + ld b,$00 ; First step. +.0: ld hl,$2000 ; RAM at $2000. +.1: ld (hl),h ; Try to write a byte. + inc h + jp p,.1 ; Repeat until reaching $8000. + ld h,$20 ; Go back at $2000. +.2: ld a,(hl) ; Read back byte. + cp h ; Is it correct? + jr nz,.3 ; No, jump. + inc h + jp p,.2 ; Repeat until reaching $8000. + jp .4 ; Memory valid! + +.3: ld a,$01 ; Enable SGM + out ($53),a + inc b + bit 1,b ; Already enabled? + jr z,.0 ; No, test RAM again. + + ld bc,$0000 + call WRITE_REGISTER + ld bc,$0180 + call WRITE_REGISTER + ld bc,$0206 + call WRITE_REGISTER + ld bc,$0380 + call WRITE_REGISTER + ld bc,$0400 + call WRITE_REGISTER + ld bc,$0536 + call WRITE_REGISTER + ld bc,$0607 + call WRITE_REGISTER + ld bc,$070D + call WRITE_REGISTER + ld bc,$03F0 + ld de,$00E8 + ld hl,$158B ; Note! direct access to Colecovision ROM + call WRITE_VRAM + ld hl,$2000 + ld de,32 + ld a,$FD + call FILL_VRAM + ld hl,$1B00 + ld de,128 + ld a,$D1 + call FILL_VRAM + ld hl,$1800 + ld de,769 + ld a,$20 + call FILL_VRAM + ld bc,$0020 + ld de,$1980 + ld hl,.5 + call WRITE_VRAM + ld bc,$01C0 + call WRITE_REGISTER + jr $ + +.5: db " SUPER GAME MODULE NOT DETECTED " + +.4: + ld ix,(lfsr) + ld hl,$2000 + ld de,$2001 + ld bc,$5FFF + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO + ld a,($0069) + cp 50 + ld a,1 + jr nz,$+3 + dec a + endif + if SG1000+SMS+SVI+SORD+PV2000+NABU + ld a,1 ; Always NTSC. + endif + if MEMOTECH+EINSTEIN + ld a,0 ; Always PAL. + endif + if MSX + call RSLREG + ld b,1 ; $4000-$7fff + call get_slot_mapping + ld h,$80 + call ENASLT ; Map into $8000-$BFFF + + ld a,($002b) + cpl + rlca + and $01 + endif + ld (ntsc),a + + call music_init + + xor a + ld (mode),a + if SMS + call mode_4 + else + call mode_0 + endif + + xor a + ld (joy1_data),a + ld (joy2_data),a + if NABU + ld (nabu_data0),a + ld (nabu_data1),a + endif + ld a,$0f + ld (key1_data),a + ld (key2_data),a + if NABU + ld (nabu_data2),a + endif + + if MSX + ld hl,nmi_handler + ld ($fd9b),hl + ld a,$c3 + ld ($fd9a),a + endif + if SORD + ld hl,nmi_handler + ld ($7006),hl + endif + + ; CVBasic program start. + ; rem + ; rem Test of IntyBASIC music player + ; rem by Oscar Toledo G. http://nanochess.org + ; rem Aug/26/2014 + ; rem + ; + ; REM Include useful predefined constants + ; + ; main: +cvb_MAIN: + ; V=0 + SUB A + LD (cvb_V),A + ; + ; wait_key: +cvb_WAIT_KEY: + ; CLS + CALL cls + ; PRINT AT 66,"Press button" + LD HL,132 + LD (cursor),HL + LD HL,cv1 + LD A,12 + CALL print_string + JP cv2 +cv1: + DB $50,$72,$65,$73,$73,$20,$62,$75 + DB $74,$74,$6f,$6e +cv2: + ; FOR c = 0 TO 60 + SUB A + LD (cvb_C),A +cv3: + ; WAIT + HALT + ; NEXT c + LD HL,cvb_C + INC (HL) + LD A,(HL) + CP 61 + JP C,cv3 + ; wait_loop: +cvb_WAIT_LOOP: + ; IF CONT1.BUTTON THEN GOTO play_1 + LD A,(joy1_data) + AND 64 + JP Z,cv4 + JP cvb_PLAY_1 +cv4: + ; IF CONT1.BUTTON2 THEN GOTO play_2 + LD A,(joy1_data) + AND 128 + JP Z,cv5 + JP cvb_PLAY_2 +cv5: + ; + ; GOTO wait_loop + JP cvb_WAIT_LOOP + ; + ; play_1: +cvb_PLAY_1: + ; PRINT AT 66,"Bach Invention 8" + LD HL,132 + LD (cursor),HL + LD HL,cv6 + LD A,16 + CALL print_string + JP cv7 +cv6: + DB $42,$61,$63,$68,$20,$49,$6e,$76 + DB $65,$6e,$74,$69,$6f,$6e,$20,$38 +cv7: + ; PRINT AT 130,"(fragment)" + LD HL,260 + LD (cursor),HL + LD HL,cv8 + LD A,10 + CALL print_string + JP cv9 +cv8: + DB $28,$66,$72,$61,$67,$6d,$65,$6e + DB $74,$29 +cv9: + ; WAIT + HALT + ; PLAY SIMPLE + LD A,3 + LD (music_mode),A + ; PLAY tune_1 + LD HL,cvb_TUNE_1 + CALL music_play + ; + ; ' Sound effect if button touch + ; repeat: +cvb_REPEAT: + ; WAIT + HALT + ; IF CONT1.BUTTON2 THEN V=15 + LD A,(joy1_data) + AND 128 + JP Z,cv10 + LD A,15 + LD (cvb_V),A +cv10: + ; SOUND 2,300,V + LD HL,300 + LD A,$c0 + CALL sn76489_freq + LD A,(cvb_V) + LD B,$d0 + CALL sn76489_vol + ; IF V>0 THEN V=V-1 + LD A,(cvb_V) + CP 1 + JP C,cv11 + LD HL,cvb_V + DEC (HL) +cv11: + ; IF MUSIC.PLAYING THEN GOTO repeat + LD A,(music_playing) + OR A + JP Z,cv12 + JP cvb_REPEAT +cv12: + ; GOTO wait_key + JP cvb_WAIT_KEY + ; + ; play_2: +cvb_PLAY_2: + ; PRINT AT 66,"Mecha-8 Level 4 " + LD HL,132 + LD (cursor),HL + LD HL,cv13 + LD A,16 + CALL print_string + JP cv14 +cv13: + DB $4d,$65,$63,$68,$61,$2d,$38,$20 + DB $4c,$65,$76,$65,$6c,$20,$34,$20 +cv14: + ; PRINT AT 130,"(fragment)" + LD HL,260 + LD (cursor),HL + LD HL,cv15 + LD A,10 + CALL print_string + JP cv16 +cv15: + DB $28,$66,$72,$61,$67,$6d,$65,$6e + DB $74,$29 +cv16: + ; WAIT + HALT + ; PLAY FULL + LD A,5 + LD (music_mode),A + ; PLAY tune_2 + LD HL,cvb_TUNE_2 + CALL music_play + ; repeat2: +cvb_REPEAT2: + ; WAIT + HALT + ; IF CONT1.BUTTON THEN PLAY OFF: GOTO wait_key + LD A,(joy1_data) + AND 64 + JP Z,cv17 + LD HL,music_silence + CALL music_play + JP cvb_WAIT_KEY +cv17: + ; GOTO repeat2 + JP cvb_REPEAT2 + ; + ; ' Bach Invention 8 (BWV779) + ; ' Fragment + ; tune_1: DATA BYTE 7 +cvb_TUNE_1: + DB $07 + ; MUSIC F4,- + db $1e,$00,$00,$00 + ; MUSIC S,- + db $3f,$00,$00,$00 + ; MUSIC A4,- + db $22,$00,$00,$00 + ; MUSIC S,- + db $3f,$00,$00,$00 + ; MUSIC F4,- + db $1e,$00,$00,$00 + ; MUSIC S,- + db $3f,$00,$00,$00 + ; MUSIC C5,- + db $25,$00,$00,$00 + ; MUSIC S,- + db $3f,$00,$00,$00 + ; MUSIC F4,- + db $1e,$00,$00,$00 + ; MUSIC S,- + db $3f,$00,$00,$00 + ; + ; MUSIC F5,- + db $2a,$00,$00,$00 + ; MUSIC S,- + db $3f,$00,$00,$00 + ; MUSIC E5,F3 + db $29,$12,$00,$00 + ; MUSIC D5,S + db $27,$3f,$00,$00 + ; MUSIC C5,A3 + db $25,$16,$00,$00 + ; MUSIC D5,S + db $27,$3f,$00,$00 + ; MUSIC C5,F3 + db $25,$12,$00,$00 + ; MUSIC A4#,S + db $23,$3f,$00,$00 + ; MUSIC A4,C4 + db $22,$19,$00,$00 + ; MUSIC A4#,S + db $23,$3f,$00,$00 + ; MUSIC A4,F3 + db $22,$12,$00,$00 + ; MUSIC G4,S + db $20,$3f,$00,$00 + ; + ; MUSIC F4,F4 + db $1e,$1e,$00,$00 + ; MUSIC S,S + db $3f,$3f,$00,$00 + ; MUSIC A4,E4 + db $22,$1d,$00,$00 + ; MUSIC S,D4 + db $3f,$1b,$00,$00 + ; MUSIC C5,C4 + db $25,$19,$00,$00 + ; MUSIC S,D4 + db $3f,$1b,$00,$00 + ; MUSIC A4,C4 + db $22,$19,$00,$00 + ; MUSIC S,A3# + db $3f,$17,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC S,A3# + db $3f,$17,$00,$00 + ; MUSIC C5,A3 + db $25,$16,$00,$00 + ; MUSIC S,G3 + db $3f,$14,$00,$00 + ; + ; MUSIC A5,F3 + db $2e,$12,$00,$00 + ; MUSIC C6,S + db $31,$3f,$00,$00 + ; MUSIC A5#,A3 + db $2f,$16,$00,$00 + ; MUSIC C6,S + db $31,$3f,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; MUSIC C6,S + db $31,$3f,$00,$00 + ; MUSIC A5#,A3 + db $2f,$16,$00,$00 + ; MUSIC C6,S + db $31,$3f,$00,$00 + ; MUSIC A5,F4 + db $2e,$1e,$00,$00 + ; MUSIC C6,S + db $31,$3f,$00,$00 + ; MUSIC A5#,C4 + db $2f,$19,$00,$00 + ; MUSIC C6,S + db $31,$3f,$00,$00 + ; + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; MUSIC G5,A3# + db $2c,$17,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; MUSIC G5,A3# + db $2c,$17,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; MUSIC G5,A3# + db $2c,$17,$00,$00 + ; MUSIC A5,C4 + db $2e,$19,$00,$00 + ; + ; MUSIC D5,F3 + db $27,$12,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC E5,G3 + db $29,$14,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC D5,F3 + db $27,$12,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC E5,G3 + db $29,$14,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC D5,F3 + db $27,$12,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; MUSIC E5,G3 + db $29,$14,$00,$00 + ; MUSIC F5,A3 + db $2a,$16,$00,$00 + ; + ; MUSIC B4,D3 + db $24,$0f,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC G4,E3 + db $20,$11,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC D5,D3 + db $27,$0f,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC B4,E3 + db $24,$11,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC F5,D3 + db $2a,$0f,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC D5,E3 + db $27,$11,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; + ; MUSIC G5,B3 + db $2c,$18,$00,$00 + ; MUSIC A5,S + db $2e,$3f,$00,$00 + ; MUSIC G5,G3 + db $2c,$14,$00,$00 + ; MUSIC F5,S + db $2a,$3f,$00,$00 + ; MUSIC E5,C4 + db $29,$19,$00,$00 + ; MUSIC F5,S + db $2a,$3f,$00,$00 + ; MUSIC E5,G3 + db $29,$14,$00,$00 + ; MUSIC D5,S + db $27,$3f,$00,$00 + ; MUSIC C5,E4 + db $25,$1d,$00,$00 + ; MUSIC D5,S + db $27,$3f,$00,$00 + ; MUSIC C5,C4 + db $25,$19,$00,$00 + ; MUSIC A4#,S + db $23,$3f,$00,$00 + ; + ; MUSIC A4,F4 + db $22,$1e,$00,$00 + ; MUSIC S,G4 + db $3f,$20,$00,$00 + ; MUSIC D5,F4 + db $27,$1e,$00,$00 + ; MUSIC C5,E4 + db $25,$1d,$00,$00 + ; MUSIC B4,D4 + db $24,$1b,$00,$00 + ; MUSIC C5,E4 + db $25,$1d,$00,$00 + ; MUSIC B4,D4 + db $24,$1b,$00,$00 + ; MUSIC A4,C4 + db $22,$19,$00,$00 + ; MUSIC G4,B3 + db $20,$18,$00,$00 + ; MUSIC A4,C4 + db $22,$19,$00,$00 + ; MUSIC G4,B3 + db $20,$18,$00,$00 + ; MUSIC F4,A3 + db $1e,$16,$00,$00 + ; + ; MUSIC E4,G3 + db $1d,$14,$00,$00 + ; MUSIC F4,S + db $1e,$3f,$00,$00 + ; MUSIC E4,C4 + db $1d,$19,$00,$00 + ; MUSIC D4,B3 + db $1b,$18,$00,$00 + ; MUSIC C4,A3 + db $19,$16,$00,$00 + ; MUSIC S,B3 + db $3f,$18,$00,$00 + ; MUSIC C5,A3 + db $25,$16,$00,$00 + ; MUSIC B4,G3 + db $24,$14,$00,$00 + ; MUSIC C5,F3 + db $25,$12,$00,$00 + ; MUSIC S,G3 + db $3f,$14,$00,$00 + ; MUSIC E4,F3 + db $1d,$12,$00,$00 + ; MUSIC S,E3 + db $3f,$11,$00,$00 + ; + ; MUSIC F4,D3 + db $1e,$0f,$00,$00 + ; MUSIC S,E3 + db $3f,$11,$00,$00 + ; MUSIC C5,D3 + db $25,$0f,$00,$00 + ; MUSIC S,C3 + db $3f,$0d,$00,$00 + ; MUSIC E4,G3 + db $1d,$14,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC C5,E3 + db $25,$11,$00,$00 + ; MUSIC S,F3 + db $3f,$12,$00,$00 + ; MUSIC D4,G3 + db $1b,$14,$00,$00 + ; MUSIC S,S + db $3f,$3f,$00,$00 + ; MUSIC B4,G2 + db $24,$08,$00,$00 + ; MUSIC S,S + db $3f,$3f,$00,$00 + ; + ; MUSIC C5,C4 + db $25,$19,$00,$00 + ; MUSIC S,S + db $3f,$3f,$00,$00 + ; MUSIC S,S + db $3f,$3f,$00,$00 + ; MUSIC S,S + db $3f,$3f,$00,$00 + ; MUSIC STOP + db $fe,$00,$00,$00 + ; + ; ' Mecha-8 level 5: alone + ; ' Fragment + ; tune_2: DATA BYTE 5 +cvb_TUNE_2: + DB $05 + ; MUSIC G5#Y,C3#,-,M1 + db $ad,$0e,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC F5#,G3#,-,M2 + db $ab,$15,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC E5,C3#,-,M1 + db $a9,$0e,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC D5#,G3#,-,M2 + db $a8,$15,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC E5,C3#,-,M1 + db $a9,$0e,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC F5#,G3#,-,M2 + db $ab,$15,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC G5#,C3#,-,M1 + db $ad,$0e,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,G3#,-,M2 + db $3f,$15,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,C3#,-,M1 + db $3f,$0e,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC C5#,G3#,-,M2 + db $a6,$15,$00,$02 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC G5#,C3#,-,M1 + db $ad,$0e,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC E5,G3#,-,M2 + db $a9,$15,$00,$02 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC F5#,B2,-,M1 + db $ab,$0c,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,F3#,-,M2 + db $3f,$13,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,B2,-,M1 + db $3f,$0c,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC -,F3#,-,M2 + db $00,$13,$00,$02 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,B2,-,M1 + db $00,$0c,$00,$01 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,F3#,-,M2 + db $00,$13,$00,$02 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,B2,-,M1 + db $00,$0c,$00,$01 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,F3#,-,M1 + db $00,$13,$00,$01 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC C5#,B2,-,M1 + db $a6,$0c,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC F5#,F3#,-,M1 + db $ab,$13,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC C5#,B2,-,M1 + db $a6,$0c,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC E5,A2,-,M1 + db $a9,$0a,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,E3,-,M1 + db $3f,$11,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,A2,-,M1 + db $3f,$0a,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,E3,-,M1 + db $3f,$11,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,A2,-,M1 + db $3f,$0a,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,E3,-,M1 + db $3f,$11,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,A2,-,M1 + db $3f,$0a,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC F5#,E3,-,M1 + db $ab,$11,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC E5,A2,-,M2 + db $a9,$0a,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC D5#,E3,-,M1 + db $a8,$11,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,A2,-,M2 + db $3f,$0a,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC C5,G2#,-,M1 + db $a5,$09,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,D3#,-,M2 + db $3f,$10,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,G2#,-,M1 + db $3f,$09,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,D3#,-,M2 + db $3f,$10,$00,$02 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC S,G2#,-,M1 + db $3f,$09,$00,$01 + ; MUSIC S,S,-,M2 + db $3f,$3f,$00,$02 + ; MUSIC -,D3#,-,M2 + db $00,$10,$00,$02 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,G2#,-,M1 + db $00,$09,$00,$01 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,D3#,-,M2 + db $00,$10,$00,$02 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,G2#,-,M1 + db $00,$09,$00,$01 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,D3#,-,M1 + db $00,$10,$00,$01 + ; MUSIC -,S,-,M3 + db $00,$3f,$00,$03 + ; MUSIC -,G2#,-,M1 + db $00,$09,$00,$01 + ; MUSIC -,S,-,M2 + db $00,$3f,$00,$02 + ; MUSIC -,D3#,-,M1 + db $00,$10,$00,$01 + ; MUSIC -,S,-,M3 + db $00,$3f,$00,$03 + ; MUSIC -,G2#,-,M1 + db $00,$09,$00,$01 + ; MUSIC -,S,-,M1 + db $00,$3f,$00,$01 + ; MUSIC -,D3#,-,M1 + db $00,$10,$00,$01 + ; MUSIC -,S,-,M1 + db $00,$3f,$00,$01 + ; MUSIC REPEAT + db $fd,$00,$00,$00 + ; + ; CVBasic epilogue (BASIC compiler for Colecovision) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and + ; read_pointer variables. + ; Revision date: Mar/04/2024. Added music player. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/13/2024. Added Pletter decompressor. + ; Revision date: Mar/19/2024. Added support for sprite flicker. + ; Revision date: Apr/11/2024. Added support for Super Game Module. + ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. + ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it + ; can remain accessible in bank 0 (bank switching). + ; Revision date: Aug/02/2024. Added rom_end label for Memotech. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. + ; Revision date: Nov/12/2024. Added vdp_status. + ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. + ; + +rom_end: + + ; ROM final size rounding + if MSX+COLECO+SG1000+SMS+SVI+SORD + TIMES (($+$1FFF)&$1e000)-$ DB $ff + endif + if MEMOTECH+EINSTEIN+NABU + ; Align following data to a 256-byte page. + TIMES $100-($&$ff) DB $4f + endif + if PV2000 + TIMES $10000-$ DB $ff + endif + if SG1000+SMS + forg $7FF0 + org $7FF0 + db "TMR SEGA" + db 0,0 + db 0,0 ; Checksum + db $11,$78 ; Product code + db $00 ; Version + db $4c ; SMS Export + 32KB for checksum + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 + org BASE_RAM + endif +ram_start: + +sprites: + if SMS + rb 256 + else + rb 128 + endif +sprite_data: + rb 4 +frame: + rb 2 +read_pointer: + rb 2 +cursor: + rb 2 +lfsr: + rb 2 +mode: + rb 1 +flicker: + rb 1 +joy1_data: + rb 1 +joy2_data: + rb 1 +key1_data: + rb 1 +key2_data: + rb 1 +ntsc: + rb 1 +vdp_status: + rb 1 + if NABU +nabu_data0: rb 1 +nabu_data1: rb 1 +nabu_data2: rb 1 + endif + + if CVBASIC_MUSIC_PLAYER +music_tick: rb 1 +music_mode: rb 1 + + if CVBASIC_BANK_SWITCHING +music_bank: rb 1 + endif +music_start: rb 2 +music_pointer: rb 2 +music_playing: rb 1 +music_timing: rb 1 +music_note_counter: rb 1 +music_instrument_1: rb 1 +music_counter_1: rb 1 +music_note_1: rb 1 +music_instrument_2: rb 1 +music_counter_2: rb 1 +music_note_2: rb 1 +music_instrument_3: rb 1 +music_counter_3: rb 1 +music_note_3: rb 1 +music_counter_4: rb 1 +music_drum: rb 1 + +audio_freq1: rb 2 +audio_freq2: rb 2 +audio_freq3: rb 2 +audio_noise: rb 1 +audio_mix: rb 1 +audio_vol1: rb 1 +audio_vol2: rb 1 +audio_vol3: rb 1 + +audio_control: rb 1 +audio_vol4hw: rb 1 + endif + + if SGM + org $2000 ; Start for variables. + endif +cvb_C: rb 1 +cvb_V: rb 1 +ram_end: diff --git a/music.rom b/music.rom new file mode 100644 index 0000000000000000000000000000000000000000..6a5d562dc9a725e318643e85b8840843d7672aca GIT binary patch literal 32768 zcmeI0e{fXQ701te`|It`Y{HKwhJ?4-goF%|WeE(f$?mEk{Xrz-59rt`QNhG&NveR0 zF0k!5!?x4Ww9+9n?UYQl8pSp^#R>hR$=*bmY+lzYE7l>3iB3|Tn3-fKG&Z>D_rBeL z$aJ*-^^beA@1A#l+;h(Tyti*3oL@yF1J#bX0iroRzP5bQ97*@>y%pfu=wDXt+1)w5NORT4ZQ1B`4tE_5xa9kG$F+=a%&} zVRuAss&n`h+Cucc~j`V1o4X53}c^%JjzR&2N1K+sUyrW=b8RQAs81 z#Hg~_Ojd=tKgNpl$=Rfb)|DyjJkkf%bg$PNq;zjI6YT#N%_b2#`8|a_F>blIZtIzo zNH%d@Y6~s!c4PMP&X!2231XvGD{>@J<`c?ySEjZ}`5znjyq)-L(`Sipfr6^Rnx4AJ z+fUyw6=i&?J<>B+UuD=^Xbk$y(pa^^lqfIPtnd0T=PEduiQU@W)Oga%rCQPzl4L>^vUtiw#A76u>#Gj%?2b^up}U}g5>&!pxZ;F z1+-$HWYs*HyT1RDl#KRV(4w!`%M;l-wOyW`8mO0}FJEomkTq-3!DvnMzM57q@*!K$ zt>tU($sb_5-<69(_5GV_)<=TXd+S&9V2RscXSQL+emHV4a`7S+)XiE`V`oGjqU9-Za2-urW8e)B40Q* z6^DHW>oE`?=N~R3Sc%+7t_v>JFt5VY#uVzuref$TD`VV$g4cx;%i`3=yHVQ+O)9#*y))6-9w%hMn4$Q)U0pmb zJ~-Ib(SdjuJd)s-=@G1hs{oFH}clGpSPfM38P-5 ziH`^o-@QUK<>O?dm{bTk7_zHf#{aK*Ww z6K~7L$3e0Q<*|P%RQSFCuYCmj;8t!Ydb0}y^4K5>K(;|}yIwD*=R-oG6A2WCJpuse zm)}O%7x5jUKV4$~kVx0aB?q9}J6aSZoWUiZp+Z#+t7;+E>w^-iiW??@xNw&nb6Xn{ zw>8q(c@HJF|0xT863z|3x6~#1b_~D2)TQ|D4N6&y?7M?otiDY_IcqWa zZsHd51%d`{(VAVhs+CJ!M&I(FF&kp?l?F|^?{SyCs$i+h>~jXqS)auxyYlw>-7Fid zwW_lA^ISAPKa>sB?Z43;hvlhkWvv%@MUQ)0d5eus&rUW3kE9O-`*3`KV-ClsT>5KS@KgV4 z7ChmvVV-gaey#TVi;;LSD=TE({w1u=e;vcGSD=QCCoZl-RCjB0nUDGX=oqU5OIS~T zy|ucKjos?K&AY{W?`WWyS$w9u7gM1LAWJEd$*87oq)BEz?|)yZUd#&9h{3I~gheu; zs(g!O+~6-^5m=U@W+~fy*{ZU=u$IBjrG&YtvFLM~%oua_rHsFD|* z2bO||bMiYSEH!N{t73j13zTI|s&1-g{#7hcku`aB(+a++KqX8!*Q*7AWh`Sj-D?e+ z{3}`NX?x-I^=dwhJ^ipLIa?7g8O+th$OtGsfVN({?-F9q`VYeR)V92>95kg{^Nme$~AHVte{P zb+sPXcY3uR*Lfvw)s;BBdSokBAvsU`!Rh<;@WhpH|CR7J_3&|NFi^|tstN-uS;lSt z^la2_o(!yJC#uX5d@&GHizykrfSVm0|7gC={7=(wO${c=^k?I4;~L{RwX1dK zVgDMo$Fqjj?$6YpJ?;p&*m!to$T9G)ei|D(;~3cL9O!f8l6>L_x_Oe%95>(hK#TgV zoqKld-1SiFPIaBfDDf&bXVAt27CNgQeDuENAHuzSPtf3B#5~8HsolyRULiKL(upS5 zGS3Prm`MFe4yZTogc08iis=4w%&6R)ls`4gY{;jxu15$*Sx(OD6<^Y; zbNccEqDm~NSe%p4z0k{wauT`I5LIJ6mpo5sA<;^#TZQ-< z=v=Nu+*LaA>3Yu2*YlVa$id}T>6OUOW0s>9mtUoq=bW2=ZtcaGs3%>&Wg)Y^jm^FrN~zTUomV& zu!SHwzjF90&@1Oy!XFs}j=M~r_rH|Wk22h1Ox#=KoAfF1OY)n5D)|e0YN|z5Cr}|2;d*9Vh93)fFK|U z2m*qDARq_`0)l`bAP5Kof`A|(2nYg#fFK|U2m*qDARq_`0)l`bAP5Kof`A|(2nYg# zfFK|U2m*qDARq_`0)l`bAP5Kof`A|(2nYg#fFK|U2m*qDARq_`0)l`bAP5Kof`A|( z2nYg#fFK|U2m*qDARq_`0)l`bAP5Kof`A|(2nYg#fFK|U2m*qDARq_`0)l`bAP5Ko Zg24Ys;Le8I)jKw9you=7OY Date: Sat, 26 Apr 2025 19:34:17 -0600 Subject: [PATCH 020/155] Updated changes in manual --- happy_face_sms.asm | 4304 --------------------------------------- happy_face_sms.rom | Bin 32768 -> 0 bytes manual.txt | 7 +- music.asm | 4792 -------------------------------------------- music.rom | Bin 32768 -> 0 bytes 5 files changed, 6 insertions(+), 9097 deletions(-) delete mode 100644 happy_face_sms.asm delete mode 100644 happy_face_sms.rom delete mode 100644 music.asm delete mode 100644 music.rom diff --git a/happy_face_sms.asm b/happy_face_sms.asm deleted file mode 100644 index c1c4dcb..0000000 --- a/happy_face_sms.asm +++ /dev/null @@ -1,4304 +0,0 @@ - ; CVBasic compiler v0.8.0 Apr/26/2025 - ; Command: ./cvbasic --sms examples/happy_face_sms.bas happy_face_sms.asm - ; Created: Sat Apr 26 19:18:25 2025 - -COLECO: equ 0 -SG1000: equ 0 -MSX: equ 0 -SGM: equ 0 -SVI: equ 0 -SORD: equ 0 -MEMOTECH: equ 0 -EINSTEIN: equ 0 -CPM: equ 0 -PENCIL: equ 0 -PV2000: equ 0 -TI99: equ 0 -NABU: equ 0 -SMS: equ 1 - -CVBASIC_MUSIC_PLAYER: equ 0 -CVBASIC_COMPRESSION: equ 0 -CVBASIC_BANK_SWITCHING: equ 0 - -BASE_RAM: equ $c000 ; Base of RAM -STACK: equ $e000 ; Base stack pointer -VDP: equ $be ; VDP port (write) -VDPR: equ $be ; VDP port (read) -PSG: equ $7f ; PSG port (write) - - ; - ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. - ; Added 16-bit multiply, division, modulo, and abs. - ; Added random generator. Added sound routines. - ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. - ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/14/2024. Added _sgn16. - ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. - ; Revision date: Apr/11/2024. Added support for formatting numbers. Added - ; support for Super Game Module. - ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. - ; Shorter mode setting subroutines. - ; Revision date: Apr/26/2024. Interruption handler saves current bank. - ; Revision date: Apr/27/2024. Music player now supports bank switching. - ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller - ; support with keyboard (code by SiRioKD) - ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. - ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. - ; Revision date: Jun/17/2024. Added SVI-328 support. - ; Revision date: Aug/01/2024. Added Sord M5 support. - ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech - ; support. - ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support - ; for Casio PV-2000. - ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, - ; and Casio PV-2000. - ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision - ; with flicker flag). - ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number - ; keys values were inverted. - ; Revision date: Nov/12/2024. Saves the VDP status. - ; - -JOYSEL: equ $c0 -KEYSEL: equ $80 - -JOY1: equ $fc-$20*(SG1000+SMS) -JOY2: equ $ff-$22*(SG1000+SMS) - - if COLECO - org $8000 - if PENCIL - db "COPYRIGHT SOUNDIC" - jp START - jp nmi_handler - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - db "CVBASIC!POWERED BY!2024!" - else - db $55,$aa - dw 0 - dw 0 - dw 0 - dw 0 - dw START - - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - - jp nmi_handler - endif - endif - if SG1000+SMS+SVI - org $0000 - di - ld sp,STACK - jp START - db $ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp nmi_handler ; It should be called int_handler. - endif - if MSX - ORG $4000 - db "AB" - dw START - dw $0000 - dw $0000 - dw $0000 - dw $0000 - -WRTPSG: equ $0093 -RDPSG: equ $0096 - - endif - if SORD - ORG $2000 - db $02 ; Avoid checking $4000 - dw START ; Start address. - dw $002e ; Prestart address (just point to RET in BIOS). - endif - if PV2000 - ORG $C000 - jp START - endif - - if MEMOTECH - if CPM - org $0100 - else - org $40fc - dw rom_start - dw rom_end-rom_start - endif -rom_start: - jp START - db 0,0,0,0,0 - dw nmi_handler - dw null_vector - dw null_vector - dw rom_start - -null_vector: - ei - reti - endif - if EINSTEIN - org $0100 -rom_start: - jp START - db 0,0,0,0,0 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - endif - if NABU - if CPM - org $0100 - else - org $140d - endif - nop - nop - nop - jp START - times $100-($&255) db $ff -nabu_int: - dw null_vector - dw null_vector - dw keyboard_handler - dw nmi_handler - dw null_vector - dw null_vector - dw null_vector - dw null_vector - -null_vector: - ei - reti - endif - - if SVI -WRTPSG: - out ($88),a - push af - ld a,e - out ($8c),a - pop af - ret - -RDPSG: - out ($88),a - push af - pop af - in a,($90) - ret - endif - - if EINSTEIN -WRTPSG: - out ($02),a - push af - ld a,e - out ($03),a - pop af - ret - -RDPSG: - out ($02),a - push af - pop af - in a,($02) - ret - endif - - if NABU -WRTPSG: - out ($41),a - push af - ld a,e - out ($40),a - pop af - ret - -RDPSG: - out ($41),a - push af - pop af - in a,($40) - ret - endif - - if PV2000 - ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) -WRTVDP: - ld a,b - ld (VDP+1),a - ld a,c - or $80 - ld (VDP+1),a - ret - -SETWRT: - ld a,l - ld (VDP+1),a - ld a,h - or $40 - ld (VDP+1),a - ret - -SETRD: - ld a,l - ld (VDP+1),a - ld a,h - and $3f - ld (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - ld (VDP),a - ret - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - ld a,(VDP) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: ld (VDP),a ; 13 14 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 37 42 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - ld a,(VDP) - ld (de),a - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - EX DE,HL - CALL SETWRT - EX DE,HL - DEC BC - INC C - LD A,B - LD B,C - INC A - LD C,A -.1: - LD A,(HL) ; 7 8 - LD (VDP),A ; 13 14 - INC HL ; 6 7 - DJNZ .1 ; 13 14 - DEC C ; 4 5 - JP NZ,.1 ; 10 11 - RET - else - ; Normal platforms with VDP connected via ports (IORQ) -WRTVDP: - ld a,b - out (VDP+1),a - ld a,c - or $80 - out (VDP+1),a - ret - -SETWRT: - ld a,l - out (VDP+1),a - ld a,h - or $40 - out (VDP+1),a - ret - -SETRD: - ld a,l - out (VDP+1),a - ld a,h - and $3f - out (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - out (VDP),a - ret - - if SG1000+SMS - db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff - - ; Located at $0066 - ei ; NMI handler (pause button) - retn - endif - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - in a,(VDPR) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: out (VDP),a ; 11 12 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 35 40 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - in a,(VDP) - ld (de),a - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - ex de,hl - call SETWRT - ex de,hl - dec bc - inc c - ld a,b - ld b,c - inc a - ld c,VDP -.1: - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - outi - jp nz,.1 - dec a - jp nz,.1 - ret - endif - - if SMS - else -LDIRVM3: - call .1 - call .1 -.1: push hl - push de - push bc - call LDIRVM - pop bc - pop de - ld a,d - add a,8 - ld d,a - pop hl - ret - endif - -DISSCR: - call nmi_off - ld bc,$a201 - call WRTVDP - jp nmi_on - -ENASCR: - call nmi_off - ld bc,$e201 - call WRTVDP - jp nmi_on - -CPYBLK: - pop hl - ex af,af' - pop af - ld b,a - pop af - ld c,a - pop de - ex (sp),hl - call nmi_off -.1: push bc - push hl - push de - ld b,0 - call LDIRVM - pop hl - ld bc,$0020 - add hl,bc - ex de,hl - pop hl - ex af,af' - ld c,a - ld b,0 - add hl,bc - ex af,af' - pop bc - djnz .1 - jp nmi_on - -nmi_off: - if COLECO+PV2000 - push hl - ld hl,mode - set 0,(hl) - pop hl - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - di - endif - ret - -nmi_on: - if COLECO+PV2000 - push af - push hl - ld hl,mode - res 0,(hl) - nop - bit 1,(hl) - jp nz,nmi_handler.0 - pop hl - pop af - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - ei - endif - ret - - if COLECO -keypad_table: - db $0f,$08,$04,$05,$0c,$07,$0b,$02 - db $0d,$0a,$00,$09,$03,$01,$06,$0f - endif - -cls: - if SMS - ld hl,$3800 - ld (cursor),hl - di - call SETWRT -.1: ld a,$20 ; 7 - out (VDP),a ; 11 - inc hl ; 6 - inc hl ; 6 - ld a,$00 ; 7 - out (VDP),a ; 11 - ld a,h ; 4 - cp $3e ; 7 - jp nz,.1 ; 10 - ei - ret - else - ld hl,$1800 - ld (cursor),hl - ld bc,$0300 - ld a,$20 - call nmi_off - call FILVRM - jp nmi_on - endif - -print_string: - ld c,a - ld b,0 - ld de,(cursor) - if SMS - ld a,d - and $07 - or $38 - ld d,a - else - ld a,d - and $07 - or $18 - ld d,a - endif - push de - push bc - call nmi_off - if SMS - ex de,hl -.1: ld a,(de) - call WRTVRM - inc de - inc hl - xor a - call WRTVRM - inc hl - dec bc - ld a,b - or c - jp nz,.1 - else - call LDIRVM - endif - call nmi_on - pop bc - pop hl - add hl,bc - if SMS - add hl,bc - endif - ld (cursor),hl - ret - -print_number: - ld b,0 - call nmi_off -print_number5: - ld de,10000 - call print_digit -print_number4: - ld de,1000 - call print_digit -print_number3: - ld de,100 - call print_digit -print_number2: - ld de,10 - call print_digit -print_number1: - ld de,1 - ld b,e - call print_digit - jp nmi_on - -print_digit: - ld a,$2f - or a -.2: inc a - sbc hl,de - jp nc,.2 - add hl,de - cp $30 - jr nz,.3 - ld a,b - or a - ret z - dec a - jr z,.4 - ld a,c - jr print_char -.4: - ld a,$30 -.3: ld b,1 - -print_char: - push hl - ld hl,(cursor) - ex af,af' - ld a,h - and $07 - if SMS - or $38 - else - or $18 - endif - ld h,a - ex af,af' - call WRTVRM - inc hl - if SMS - xor a - call WRTVRM - inc hl - endif - ld (cursor),hl - pop hl - ret - -define_char: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - di - call LDIRVM - ei - ret - else - call nmi_off - ld a,(mode) - and 8 - jr nz,.1 - call LDIRVM3 - jp nmi_on - -.1: call LDIRVM - jp nmi_on - endif - -define_color: - if SMS - ret - else - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d - call nmi_off - call LDIRVM3 - jp nmi_on - endif - -define_sprite: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - if SMS - set 1,h - else - ld h,$07 - endif - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ex de,hl - call nmi_off - call LDIRVM - jp nmi_on - endif - -update_sprite: - if SMS - pop bc - add a,a - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - and $3f - ld e,a - ld d,sprites>>8 - ld a,(sprite_data) - ld (de),a - sla e - set 7,e - ld a,(sprite_data+1) - ld (de),a - inc e - ld a,(sprite_data+2) - ld (de),a - else - pop bc - ld (sprite_data+3),a - pop af - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - ld de,sprites - add a,a - add a,a - if SORD - or $80 - endif - ld e,a - ld hl,sprite_data - ld bc,4 - ldir - endif - ret - - ; Fast 16-bit multiplication. -_mul16: - ld b,h - ld c,l - ld a,16 - ld hl,0 -.1: - srl d - rr e - jr nc,.2 - add hl,bc -.2: sla c - rl b - dec a - jp nz,.1 - ret - - ; 16-bit signed modulo. - ; hl = hl % de -_mod16s: - ld a,h - or a - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _mod16 - pop af - ret p - jp _neg16 - - ; 16-bit signed division. - ; hl = hl / de -_div16s: - ld a,h - xor d - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _div16 - pop af - ret p - jp _neg16 - -_abs16: - bit 7,h - ret z -_neg16: - ld a,h - cpl - ld h,a - ld a,l - cpl - ld l,a - inc hl - ret - - ; Fast 16-bit division. - ; hl = hl / de -_div16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - rl c - rl b - ld h,b - ld l,c - ret - - ; Fast 16-bit modulo. -_mod16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - ret - -_sgn16: - ld a,h - or l - ret z - bit 7,h - ld hl,$ffff - ret nz - inc hl - inc hl - ret - - ; Random number generator. - ; From my game Mecha Eight. -random: - ld hl,(lfsr) - ld a,h - or l - jr nz,.0 - ld hl,$7811 -.0: ld a,h - and $80 - ld b,a - ld a,h - and $02 - rrca - rrca - xor b - ld b,a - ld a,h - and $01 - rrca - xor b - ld b,a - ld a,l - and $20 - rlca - rlca - xor b - rlca - rr h - rr l - ld (lfsr),hl - ret - -sn76489_freq: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld b,a - ld a,l - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - and $3f - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_vol: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - cpl - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_control: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - and $0f - or $e0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -ay3_reg: - if COLECO - push af - ld a,b - out ($50),a - pop af - out ($51),a - ret - endif - if SG1000+SORD+SMS+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,a - ld a,b - jp WRTPSG - endif - -ay3_freq: - if COLECO - out ($50),a - push af - ld a,l - out ($51),a - pop af - inc a - out ($50),a - push af - ld a,h - and $0f - out ($51),a - pop af - ret - endif - if SG1000+SMS+SORD+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,l - call WRTPSG - ld e,h - inc a - jp WRTPSG - endif - - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ; Required for SG1000 and Sega Master System as both don't have a BIOS - ; Required for SVI because we don't have access to BIOS in cartridge. - ; Required for Sord M5 because it doesn't provide an ASCII charset. - ; Required for Memotech/Einstein because CP/M uses the memory. - ; My personal font for TMS9928. - ; - ; Patterned after the TMS9928 programming manual 6x8 letters - ; with better lowercase letters, also I made a proper - ; AT sign. - ; -font_bitmaps: - db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space - db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! - db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " - db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # - db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ - db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % - db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & - db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' - db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( - db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) - db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * - db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + - db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , - db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - - db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . - db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / - db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 - db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 - db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 - db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 - db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 - db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 - db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 - db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 - db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 - db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 - db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : - db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; - db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < - db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = - db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > - db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? - db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ - db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A - db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B - db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C - db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D - db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E - db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F - db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G - db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H - db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I - db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J - db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K - db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L - db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M - db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N - db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O - db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P - db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q - db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R - db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S - db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T - db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U - db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V - db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W - db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X - db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y - db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z - db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ - db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ - db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] - db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E - db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ - db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 - db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a - db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b - db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c - db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d - db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e - db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f - db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g - db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h - db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i - db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j - db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k - db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l - db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m - db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n - db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o - db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p - db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q - db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r - db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s - db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t - db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u - db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v - db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w - db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x - db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y - db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z - db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { - db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | - db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } - db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e - db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f - endif - - if SMS -palette_load: - push hl - di - ld hl,$c000 - call SETWRT - pop hl - ld bc,32*256+VDP - outi - jp nz,$-2 - ei - ret - -mode_4: - di - ld bc,$0400 - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) - call WRTVDP - ld bc,$ff03 ; Not used (required value for SMS1) - call WRTVDP - ld bc,$0704 ; Not used (required value for SMS1) - call WRTVDP - ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) - call WRTVDP - ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) - call WRTVDP - ld bc,$0007 - call WRTVDP - ld bc,$0008 ; Background X scroll - call WRTVDP - ld bc,$0009 ; Background Y scroll - call WRTVDP - ld hl,$20*32 ; Point to space character bitmap - call SETWRT - ld hl,font_bitmaps - ld c,96 -.1: ld b,8 -.2: ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - inc hl - djnz .2 - dec c - jp nz,.1 - ei - call cls - di - ld hl,$3f00 - ld bc,$0040 - ld a,$e0 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,63 - ld (hl),$e0 - ldir - ei - ld hl,.3 - call palette_load - jp ENASCR - - ; TMS9118-alike palette -.3: - db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f - db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f - - else -vdp_generic_mode: - call nmi_off - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0602 ; $1800 for pattern table. - call WRTVDP - ld b,d - ld c,$03 ; for color table. - call WRTVDP - ld b,e - ld c,$04 ; for bitmap table. - call WRTVDP - ld bc,$3605 ; $1b00 for sprite attribute table. - call WRTVDP - ld bc,$0706 ; $3800 for sprites bitmaps. - call WRTVDP - ld bc,$0107 - jp WRTVDP - -mode_0: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM3 - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - call cls -vdp_generic_sprites: - call nmi_off - ld hl,$1b00 - ld bc,$0080 - ld a,$d1 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,127 - ld (hl),$d1 - ldir - call nmi_on - jp ENASCR - -mode_1: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - ld hl,$0000 - ld bc,$1800 - xor a - call FILVRM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - ld hl,$1800 -.1: call nmi_off - ld b,32 -.2: ld a,l - call WRTVRM - inc hl - djnz .2 - call nmi_on - ld a,h - cp $1b - jp nz,.1 - jp vdp_generic_sprites - -mode_2: - ld hl,mode - set 3,(hl) - ld bc,$0000 - ld de,$8000 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$0020 - ld a,$f0 - call FILVRM - call nmi_on - call cls - jp vdp_generic_sprites - endif - - if MSX -ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) -RSLREG: EQU $0138 ; Read slot status in A - - ; - ; Get slot mapping - ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) - ; A = Current slot selection status (CALL RSLREG) - ; -get_slot_mapping: - call rotate_slot - ld c,a - add a,$C1 ; EXPTBL - ld l,a - ld h,$FC - ld a,(hl) - and $80 ; Get expanded flag - or c - ld c,a - inc hl - inc hl - inc hl - inc hl - ld a,(hl) ; SLTTBL - call rotate_slot - rlca - rlca - or c ; A contains bit 7 = Marks expanded - ; bit 6 - 4 = Doesn't care - ; bit 3 - 2 = Secondary mapper - ; bit 1 - 0 = Primary mapper - ret - -rotate_slot: - push bc - dec b - inc b - jr z,.1 -.0: rrca - rrca - djnz .0 -.1: and 3 - pop bc - ret - - endif - -nmi_handler: - push af - push hl - ld hl,mode - bit 0,(hl) - jr z,.1 - set 1,(hl) - pop hl - pop af - retn - -.0: res 1,(hl) - -.1: push bc - push de - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fff) - endif - if MSX - ld a,($bfff) - endif - push af - endif - if SORD+MEMOTECH - call ctc_reti - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - in a,(VDPR+1) - ld (vdp_status),a - endif - - ; - ; Update of sprite attribute table - ; - if SMS - bit 2,(hl) - jr z,.4 - ld hl,$3f00 - call SETWRT - ld hl,sprites - ld bc,$4000+VDP - outi - jp nz,$-2 - ld hl,$3f80 - call SETWRT - ld hl,sprites - ld bc,$8000+VDP - outi - jp nz,$-2 - jr .5 - -.4: ld hl,$3f00 - call SETWRT - ld a,(flicker) - inc a - and $3f - ld (flicker),a - ld l,a - ld h,sprites>>8 - ld bc,$4000+VDP - ld de,6 - outi - add hl,de - res 6,l - jp nz,$-5 - ld hl,$3f80 - call SETWRT - ld a,(flicker) - add a,a - or $80 - ld l,a - ld bc,$8000+VDP - ld de,12 - ld h,sprites>>8 - outi - nop - nop - nop - outi - add hl,de - set 7,l - jp nz,$-12 -.5: - else - ld bc,$8000+VDP - bit 2,(hl) - jr z,.4 - - ld hl,$1b00 - call SETWRT - ld hl,sprites -.7: - if PV2000 - ld a,(hl) - ld (VDP),a - inc hl - djnz .7 - else - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp nz,.7 - endif - jr .5 - -.4: - ld hl,$1b00 - call SETWRT - ld a,(flicker) - add a,$04 - ld (flicker),a - ld de,24 - ld b,128 - ld l,a - if SORD - else - ld h,sprites>>8 - endif -.6: - if SORD - set 7,l - ld h,sprites>>8 - else - res 7,l - endif - if PV2000 - ld a,(hl) ; 7 8 - ld (VDP),a ; 13 14 - inc hl ; 6 7 - dec b ; 4 5 - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - else - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - endif - add hl,de - jp nz,.6 -.5: - endif - - if COLECO - out (JOYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - or $b0 - ld b,a - in a,(JOY2) - or $b0 - ld c,a - - out (KEYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - ld d,a - in a,(JOY2) - ld e,a - - ld a,d - rlca - or $7f - and b - cpl - ld (joy1_data),a - - ld a,e - rlca - or $7f - and c - cpl - ld (joy2_data),a - - ld a,d - and $0f - ld c,a - ld b,0 - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key1_data),a - - ld a,e - and $0f - ld c,a - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key2_data),a - endif - if SG1000+SMS - ld a,$07 - out ($de),a - ld b,$ff - in a,(JOY1) - ld h,a - in a,(JOY2) - ld l,a - in a,($de) - cp 7 - jp nz,.sg1000 - - ld a,$00 - out ($de),a - in a,($dc) - rra - ld c,1 - jr nc,.sg1 - in a,($dd) - rra - ld c,8 - jr nc,.sg1 - ld a,$01 - out ($de),a - in a,($dc) - rra - ld c,2 - jr nc,.sg1 - in a,($dd) - rra - ld c,9 - jr nc,.sg1 - ld a,$02 - out ($de),a - in a,($dc) - rra - ld c,3 - jr nc,.sg1 - in a,($dd) - rra - ld c,0 - jr nc,.sg1 - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a - ld c,10 - jr z,.sg1 - rra - ld c,4 - jr nc,.sg1 - ld a,$04 - out ($de),a - in a,($dc) - rra - ld c,5 - jr nc,.sg1 - ld a,$05 - out ($de),a - in a,($dc) - bit 6,a - ld c,11 - jr z,.sg1 - rra - ld c,6 - jr nc,.sg1 - ld a,$06 - out ($de),a - in a,($dc) - rra - ld c,7 - jr nc,.sg1 - ld c,15 -.sg1: ld a,c - ld (key1_data),a - - ld a,$04 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard down. - jr nz,$+4 - res 1,h - ld a,$05 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard left. - jr nz,$+4 - res 2,h - ld a,$06 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard right. - jr nz,$+4 - res 3,h - bit 6,a ; Keyboard up. - jr nz,$+4 - res 0,h - ld a,$02 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Ins - jr nz,$+4 - res 4,h - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Del - jr nz,$+4 - res 5,h -.sg1000: - bit 0,h - jr nz,$+4 - res 0,b - bit 1,h - jr nz,$+4 - res 2,b - bit 2,h - jr nz,$+4 - res 3,b - bit 3,h - jr nz,$+4 - res 1,b - bit 4,h - jr nz,$+4 - res 6,b - bit 5,h - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - - ld a,$ff - bit 6,h - jr nz,$+4 - res 0,a - bit 7,h - jr nz,$+4 - res 2,a - - bit 0,l - jr nz,$+4 - res 3,a - bit 1,l - jr nz,$+4 - res 1,a - bit 2,l - jr nz,$+4 - res 4,a - bit 3,l - jr nz,$+4 - res 5,a - cpl - ld (joy2_data),a - - endif - if MSX - ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php - ld a,15 - call RDPSG - and $b0 - or $4f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - ld b,$ff - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy2_data),a - - in a,($aa) - and $f0 - or $00 - out ($aa),a - in a,($a9) - cp $ff - ld c,$ff - jr nz,.key1 - in a,($aa) - and $f0 - or $01 - out ($aa),a - in a,($a9) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - in a,($aa) - and $f0 - or $07 - out ($aa),a - in a,($a9) - bit 5,a ; BS - ld c,$0a - jr z,.key2 - bit 7,a ; RET - ld c,$0b - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - in a,($aa) - and $f0 - or $08 - out ($aa),a - in a,($a9) - bit 5,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 6,a - jr nz,$+4 - res 2,b - bit 4,a - jr nz,$+4 - res 3,b - bit 0,a - jr nz,$+4 - res 6,b - in a,($aa) - and $f0 - or $04 - out ($aa),a - in a,($a9) - bit 2,a - jr nz,$+4 - res 7,b - - ld a,15 - call RDPSG - and $b0 - or $0f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - - ld a,b - cpl - ld (joy1_data),a - endif - if SVI - ld a,14 - call RDPSG - ld b,$ff - bit 4,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 5,a - jr nz,$+4 - res 2,b - bit 6,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 5,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy2_data),a - - ld a,$10 - out ($96),a - in a,($99) - cp $ff - ld c,$ff - jr nz,.key1 - ld a,$11 - out ($96),a - in a,($99) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - ld a,$16 - out ($96),a - in a,($99) - bit 6,a - ld c,$0b - jr z,.key2 - ld a,$15 - out ($96),a - in a,($99) - bit 6,a - ld c,$0a - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - ld a,$15 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 0,b - ld a,$18 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 1,b - ld a,$17 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 2,b - ld a,$16 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 3,b - ld a,$18 - out ($96),a - in a,($99) - bit 0,a - jr nz,$+4 - res 6,b - ld a,$13 - out ($96),a - in a,($99) - bit 5,a - jr nz,$+4 - res 7,b - - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 4,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy1_data),a - endif - if SORD - ld bc,$ffff - in a,($37) ; Read joystick - rra - jr nc,$+4 - res 1,b - rra - jr nc,$+4 - res 0,b - rra - jr nc,$+4 - res 3,b - rra - jr nc,$+4 - res 2,b - rra - jr nc,$+4 - res 1,c - rra - jr nc,$+4 - res 0,c - rra - jr nc,$+4 - res 3,c - rra - jr nc,$+4 - res 2,c - in a,($31) - rra - jr nc,$+4 - res 6,b - rra - jr nc,$+4 - res 7,b - rra - rra - rra - jr nc,$+4 - res 6,c - rra - jr nc,$+4 - res 7,c - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - in a,($31) ; Keyboard 1-8 - or a - ld c,$00 - jr nz,.key3 - in a,($35) - bit 0,a ; 9 - ld c,$09 - jr nz,.key5 - bit 1,a ; 0 - ld c,$00 - jr nz,.key5 - bit 7,a ; Backspace - ld c,$0a - jr nz,.key5 - in a,($30) - bit 7,a ; Enter - ld c,$0b - jr nz,.key5 - ld c,$0f - jr .key5 - -.key3: rra - inc c - jr nc,.key3 -.key5: - ld a,c - ld (key1_data),a - - endif - if MEMOTECH - ld bc,$ffff - - ld a,$fb - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 0,b ; Up direction. - bit 3,a ; Y - jr nz,$+4 - res 0,c ; Up direction. - - ld a,$ef - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 1,b ; Right key. - ld a,$bf - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 2,b ; Down key. - ld a,$f7 - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 3,b ; Left key. - ld a,$df - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a ; Home key. - jr nz,$+4 - res 6,b ; Button 1 - - ld a,$7F - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 2,a ; B - jr nz,$+4 - res 0,c ; Up key. - bit 1,a ; C - jr nz,$+4 - res 1,c ; Right key. - bit 3,a ; M - jr nz,$+4 - res 2,c ; Down key. - bit 0,a ; Z - jr nz,$+4 - res 3,c ; Left key. - bit 5,a ; - - jr nz,$+4 - res 7,c ; Button 2 for player 2. - bit 7,a ; - - jr nz,$+4 - res 7,b ; Button 2 for player 1. - in a,($06) ; Read keyboard data. - bit 0,a ; Space - jr nz,$+4 - res 6,c ; Button 1. - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$fe - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - ld b,1 - jr nc,.mt1 - rra - ld b,3 - jr nc,.mt1 - rra - ld b,5 - jr nc,.mt1 - rra - ld b,7 - jr nc,.mt1 - rra - ld b,9 - jr nc,.mt1 - ld a,$df - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - bit 6,a - ld b,11 - jr z,.mt1 - ld a,$fd - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - rra - ld b,2 - jr nc,.mt1 - rra - ld b,4 - jr nc,.mt1 - rra - ld b,6 - jr nc,.mt1 - rra - ld b,8 - jr nc,.mt1 - rra - ld b,0 - jr nc,.mt1 - in a,($06) - rra - ld b,10 - jr nc,.mt1 - ld b,15 -.mt1: - ld a,b - ld (key1_data),a - endif - if EINSTEIN - ld bc,$ffff - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 0,b ; Up - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 4,a - jr nz,$+4 - res 1,b ; Right - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - jr nz,$+4 - res 2,b ; Down - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - jr nz,$+4 - res 3,b ; Left - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 6,b ; Fire - ld a,$0e - out ($02),a - ld a,$7f - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 0,a - jr nz,$+4 - res 7,b ; 2nd fire - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$0e - out ($02),a - ld a,$ef - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - rra - ld b,7 - jr nc,.te1 - rra - ld b,6 - jr nc,.te1 - rra - ld b,5 - jr nc,.te1 - rra - ld b,4 - jr nc,.te1 - rra - ld b,3 - jr nc,.te1 - rra - ld b,2 - jr nc,.te1 - rra - ld b,1 - jr nc,.te1 - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - ld b,8 - jr z,.te1 - bit 4,a - ld b,10 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - ld b,9 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - ld b,11 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 7,a - ld b,0 - jr z,.te1 - ld b,15 -.te1: - ld a,b - ld (key1_data),a - endif - if PV2000 - ld bc,$ffff - ld a,7 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 0,b - bit 0,a - jr z,$+4 - res 3,b - ld a,6 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 1,b - bit 0,a - jr z,$+4 - res 2,b - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 0,a - jr z,$+4 - res 6,b - bit 1,a - jr z,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - ld a,0 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - and $0f - ld b,$04 - jr nz,.pv1 - in a,($10) - and $0f - ld b,$08 - jr nz,.pv1 - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($10) - ld b,11 - bit 0,a - jr nz,.pv2 - ld a,4 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - ld b,10 - bit 3,a - jr nz,.pv2 - in a,($10) - ld b,9 - bit 0,a - jr nz,.pv2 - ld b,0 - bit 3,a - jr nz,.pv2 - ld b,15 - jr .pv2 - -.pv1: rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b -.pv2: ld a,b - ld (key1_data),a - endif - if NABU - ld a,(nabu_data0) - and $cf - ld (joy1_data),a - ld a,(nabu_data1) - and $cf - ld (joy2_data),a - ld a,(nabu_data2) - ld (key1_data),a - ld a,$0f - ld (nabu_data2),a - endif - - if CVBASIC_MUSIC_PLAYER - ld a,(music_mode) - or a - call nz,music_hardware - endif - - ld hl,(frame) - inc hl - ld (frame),hl - - ld hl,lfsr ; Make LFSR more random - inc (hl) - inc (hl) - inc (hl) - - if CVBASIC_MUSIC_PLAYER - ; - ; Music is played with a 50hz clock. - ; - ld a,(ntsc) - or a - jr z,.2 - ld a,(music_tick) - inc a - cp 6 - jr nz,$+3 - xor a - ld (music_tick),a - jr z,.3 -.2: - ld a,(music_mode) - or a - call nz,music_generate -.3: - endif - - if CVBASIC_BANK_SWITCHING - pop af - if COLECO - ld l,a - ld h,$ff - ld a,(hl) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - pop de - pop bc - pop hl - if COLECO - in a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - if SG1000+SMS+SVI+NABU - pop af - ei - reti - endif - if MSX - pop af - ret - endif - if SORD+MEMOTECH - pop af - ei - ret - -ctc_reti: - reti - endif - if EINSTEIN - pop af - ret - endif - if PV2000 - ld a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - - if NABU -keyboard_handler: - push af - push bc - push hl - in a,($90) - ld c,a - cp $0d ; Enter - ld a,11 - jr z,.8 - ld a,c - cp $7f ; Del - ld a,10 - jr z,.8 - ld a,c - cp $30 - jr c,.7 - cp $3a - jr nc,.7 - sub $30 -.8: ld (nabu_data2),a - jr .1 -.7: - cp $a0 - jr c,.2 - cp $c0 - jr c,.joystick -.2: - ld hl,nabu_data0 - cp $80 - jr nz,.3 - res 4,(hl) - jr .1 -.3: - cp $81 - jr nz,.4 - set 4,(hl) - jr .1 -.4: - cp $e0 - jr c,.1 - and $0f - ld b,2 - jr z,.5 - dec a - ld b,8 - jr z,.5 - dec a - ld b,1 - jr z,.5 - dec a - ld b,4 - jr z,.5 - dec a - ld b,$80 - jr z,.5 - dec a - ld b,$40 - jr nz,.1 -.5: bit 4,c - jr nz,.6 - ld a,(hl) - or b - ld (hl),a - jr .1 - -.6: - ld a,b - cpl - and (hl) - ld (hl),a - jr .1 - -.joystick: - ld hl,nabu_data0 - bit 4,(hl) - jr z,$+5 - ld hl,nabu_data1 - ld b,$00 - bit 3,c - jr z,$+4 - set 0,b - bit 2,c - jr z,$+4 - set 1,b - bit 1,c - jr z,$+4 - set 2,b - bit 0,c - jr z,$+4 - set 3,b - bit 4,c - jr z,$+4 - set 6,b - ld (hl),b -.1: - pop hl - pop bc - pop af - ei - reti - endif - if SORD -wait: - ld de,(frame) -.1: - ld hl,(frame) - or a - sbc hl,de - jr z,.1 - ret - endif - if EINSTEIN -wait: - in a,(VDP+1) - nop - in a,(VDP+1) - bit 7,a - jr z,$-4 - ld (vdp_status),a - jp nmi_handler - endif - - ; - ; The music player code comes from my - ; game Princess Quest for Colecovision (2012) - ; - - ; - ; Init music player. - ; -music_init: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$9f - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$bf - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$df - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ff - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ec - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 -MIX_BASE: equ $b8 - endif - if EINSTEIN+NABU -MIX_BASE: equ $78 - endif - if MSX+SVI+EINSTEIN+NABU - ld a,$08 - ld e,$00 - call WRTPSG - ld a,$09 - ld e,$00 - call WRTPSG - ld a,$0a - ld e,$00 - call WRTPSG - ld a,$07 - ld e,MIX_BASE - call WRTPSG - endif - if SGM - ld b,$08 - xor a - call ay3_reg - ld b,$09 - call ay3_reg - ld b,$0a - call ay3_reg - ld b,$07 - ld a,$b8 - call ay3_reg - endif - if CVBASIC_MUSIC_PLAYER - else - ret - endif - - if CVBASIC_MUSIC_PLAYER - ld a,$ff - ld (audio_vol4hw),a - ld a,$ec - ld (audio_control),a - ld a,MIX_BASE - ld (audio_mix),a - ld hl,music_silence - ; - ; Play a music. - ; HL = Pointer to music. - ; -music_play: - call nmi_off - ld a,(hl) - ld (music_timing),a - inc hl - ld (music_start),hl - ld (music_pointer),hl - xor a - ld (music_note_counter),a - inc a - ld (music_playing),a - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fff) - endif - if MSX - ld a,($bfff) - endif - ld (music_bank),a - endif - jp nmi_on - - ; - ; Generates music. - ; -music_generate: - ld a,(audio_mix) - and $c0 - or $38 - ld (audio_mix),a - xor a ; Turn off all the sound channels. - ld l,a - ld h,a - ld (audio_vol1),hl ; audio_vol1/audio_vol2 - ld (audio_vol3),a - ld a,$ff - ld (audio_vol4hw),a - - ld a,(music_note_counter) - or a - jp nz,.6 - ld hl,(music_pointer) -.15: push hl - if CVBASIC_BANK_SWITCHING - ld a,(music_bank) - if COLECO - ld e,a - ld d,$ff - ld a,(de) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - ld b,(hl) - inc hl - ld c,(hl) - inc hl - ld d,(hl) - inc hl - ld e,(hl) - pop hl - ld a,(music_timing) - rlca - jr nc,.16 - ld e,d - ld d,0 - jr .17 - -.16: rlca - jr nc,.17 - ld e,0 -.17: ld a,b ; Read first byte. - cp -2 ; End of music? - jr nz,.19 ; No, jump. - xor a ; Keep at same place. - ld (music_playing),a - ret - -.19: cp -3 ; Repeat music? - jp nz,.0 - ld hl,(music_start) - jr .15 - -.0: ld a,(music_timing) - and $3f ; Restart note time. - ld (music_note_counter),a - ld a,b - cp $3f ; Sustain? - jr z,.1 - rlca - rlca - and 3 - ld (music_instrument_1),a - ld a,b - and $3f - ld (music_note_1),a - xor a - ld (music_counter_1),a -.1: ld a,c - cp $3f - jr z,.2 - rlca - rlca - and 3 - ld (music_instrument_2),a - ld a,c - and $3f - ld (music_note_2),a - xor a - ld (music_counter_2),a -.2: ld a,d - cp $3f - jr z,.3 - rlca - rlca - and 3 - ld (music_instrument_3),a - ld a,d - and $3f - ld (music_note_3),a - xor a - ld (music_counter_3),a -.3: ld a,e - ld (music_drum),a - xor a - ld (music_counter_4),a - inc hl - inc hl - inc hl - ld a,(music_timing) - and $c0 - jr nz,.14 - inc hl -.14: ld (music_pointer),hl - -.6: ld a,(music_note_1) - or a - jr z,.7 - ld bc,(music_instrument_1) - call music_note2freq - ld (audio_freq1),hl - ld (audio_vol1),a - -.7: ld a,(music_note_2) - or a - jr z,.8 - ld bc,(music_instrument_2) - call music_note2freq - ld (audio_freq2),hl - ld (audio_vol2),a - -.8: ld a,(music_note_3) - or a - jr z,.9 - ld bc,(music_instrument_3) - call music_note2freq - ld (audio_freq3),hl - ld (audio_vol3),a - -.9: ld a,(music_drum) - or a - jr z,.4 - dec a ; 1 - Long drum. - jr nz,.5 - ld a,(music_counter_4) - cp 3 - jp nc,.4 -.10: ld a,5 - ld (audio_noise),a - call enable_drum - jr .4 - -.5: dec a ; 2 - Short durm. - jr nz,.11 - ld a,(music_counter_4) - or a - jp nz,.4 - ld a,8 - ld (audio_noise),a - call enable_drum - jr .4 - -.11: ;dec a ; 3 - Roll. - ;jp nz,.4 - ld a,(music_timing) - and $3e - rrca - ld b,a - ld a,(music_counter_4) - cp 2 - jp c,.10 - cp b - jp c,.4 - dec a - dec a - cp b - jp c,.10 -.4: - ld a,(music_counter_1) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_1),a - - ld a,(music_counter_2) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_2),a - - ld a,(music_counter_3) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_3),a - - ld hl,music_counter_4 - inc (hl) - ld hl,music_note_counter - dec (hl) - ret - - ; - ; Converts note to frequency. - ; Input: - ; A = Note (1-62). - ; B = Instrument counter. - ; C = Instrument. - ; Output: - ; HL = Frequency. - ; A = Volume. - ; -music_note2freq: - add a,a - ld e,a - ld d,0 - ld hl,music_notes_table - add hl,de - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - ld a,c - or a - jp z,music_piano - dec a - jp z,music_clarinet - dec a - jp z,music_flute - ; - ; Bass instrument. - ; -music_bass: - add hl,hl - - ; - ; Piano instrument. - ; -music_piano: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ret - -.1: - db 12,11,11,10,10,9,9,8 - db 8,7,7,6,6,5,5,4 - db 4,4,5,5,4,4,3,3 - - ; - ; Clarinet instrument. - ; -music_clarinet: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - srl h - rr l - jp nc,.2 - inc hl -.2: ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - - db 13,14,14,13,13,12,12,12 - db 11,11,11,11,12,12,12,12 - db 11,11,11,11,12,12,12,12 - - ; - ; Flute instrument. - ; -music_flute: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - - db 10,12,13,13,12,12,12,12 - db 11,11,11,11,10,10,10,10 - db 11,11,11,11,10,10,10,10 - - ; - ; Emit sound. - ; -music_hardware: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.7 ; Yes, jump. - ld a,(audio_vol2) - or a - jp nz,.7 - ld a,(audio_vol3) - or a - jp z,.7 - ld (audio_vol2),a - xor a - ld (audio_vol3),a - ld hl,(audio_freq3) - ld (audio_freq2),hl -.7: - ld hl,(audio_freq1) - ld a,h - cp 4 - ld a,$9f - jp nc,.1 - ld a,l - and $0f - or $80 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol1) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $90 -.1: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld hl,(audio_freq2) - ld a,h - cp 4 - ld a,$bf - jp nc,.2 - ld a,l - and $0f - or $a0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol2) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $b0 -.2: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.6 ; Yes, jump. - - ld hl,(audio_freq3) - ld a,h - cp 4 - ld a,$df - jp nc,.3 - ld a,l - and $0f - or $c0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol3) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $d0 -.3: out (PSG),a - if MEMOTECH - in a,($03) - endif - -.6: - ld a,(music_mode) - and 1 ; NO DRUMS? - ret z ; Yes, return. - - ld a,(audio_vol4hw) - inc a - jr z,.4 - ld a,(audio_noise) - cp 16 - ld b,$ec - jp c,.5 - ld b,$ed -; ld b,$ee -.5: ld a,(audio_control) - cp b - jr z,.4 - ld a,b - ld (audio_control),a - out (PSG),a - if MEMOTECH - in a,($03) - endif -.4: ld a,(audio_vol4hw) - out (PSG),a - if MEMOTECH - in a,($03) - endif - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.8 ; Yes, jump. - ld hl,audio_freq1 - ld bc,$0b00 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret -.8: - ld hl,audio_freq1 - ld bc,$0400 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - inc hl - inc hl - inc c - inc c - ld a,(music_mode) - and 1 - jr z,.9 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - jr .10 -.9: inc hl - inc c - inc hl - inc c -.10: ld b,$02 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret - endif - - ; - ; Enable drum. - ; -enable_drum: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$f5 - ld (audio_vol4hw),a - else - ld hl,audio_mix - ld a,(audio_vol2) - or a - jr nz,.1 - ld a,10 - ld (audio_vol2),a - set 1,(hl) -.1: res 4,(hl) - endif - ret - - ; - ; Musical notes table. - ; -music_notes_table: - ; Silence - 0 - dw 0 - if MEMOTECH+EINSTEIN - ; Values for 4.00 mhz. - ; 2nd octave - Index 1 - dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 - ; 3rd octave - Index 13 - dw 956,902,851,804,758,716,676,638,602,568,536,506 - ; 4th octave - Index 25 - dw 478,451,426,402,379,358,338,319,301,284,268,253 - ; 5th octave - Index 37 - dw 239,225,213,201,190,179,169,159,150,142,134,127 - ; 6th octave - Index 49 - dw 119,113,106,100,95,89,84,80,75,71,67,63 - ; 7th octave - Index 61 - dw 60,56,53 - else - ; Values for 3.58 mhz. - ; 2nd octave - Index 1 - dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 - ; 3rd octave - Index 13 - dw 855,807,762,719,679,641,605,571,539,508,480,453 - ; 4th octave - Index 25 - dw 428,404,381,360,339,320,302,285,269,254,240,226 - ; 5th octave - Index 37 - dw 214,202,190,180,170,160,151,143,135,127,120,113 - ; 6th octave - Index 49 - dw 107,101,95,90,85,80,76,71,67,64,60,57 - ; 7th octave - Index 61 - dw 53,50,48 - endif - - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ; - ; Converts AY-3-8910 volume to SN76489 - ; -ay2sn: - db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 - endif - -music_silence: - db 8 - db 0,0,0,0 - db -2 - endif - - if CVBASIC_COMPRESSION -define_char_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - else - ld a,(mode) - and 8 - jp z,unpack3 - endif - jp unpack - - if SMS - else -define_color_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d -unpack3: - call .1 - call .1 -.1: - push de - push hl - call unpack - pop hl - pop de - ld a,d - add a,8 - ld d,a - ret - endif - - ; - ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) - ; -unpack: -; Initialization - ld a,(hl) - inc hl - exx - ld de,0 - add a,a - inc a - rl e - add a,a - rl e - add a,a - rl e - rl e - ld hl,.modes - add hl,de - ld c,(hl) - inc hl - ld b,(hl) - push bc - pop ix - ld e,1 - exx - ld iy,.loop - -; Main depack loop -.literal: - ex af,af' - call nmi_off - ld a,(hl) - ex de,hl - call WRTVRM - ex de,hl - inc hl - inc de - call nmi_on - ex af,af' -.loop: add a,a - call z,.getbit - jr nc,.literal - -; Compressed data - exx - ld h,d - ld l,e -.getlen: add a,a - call z,.getbitexx - jr nc,.lenok -.lus: add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr nc,.lenok - add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr c,.lus -.lenok: inc hl - exx - ld c,(hl) - inc hl - ld b,0 - bit 7,c - jr z,.offsok - jp (ix) - -.mode6: add a,a - call z,.getbit - rl b -.mode5: add a,a - call z,.getbit - rl b -.mode4: add a,a - call z,.getbit - rl b -.mode3: add a,a - call z,.getbit - rl b -.mode2: add a,a - call z,.getbit - rl b - add a,a - call z,.getbit - jr nc,.offsok - or a - inc b - res 7,c -.offsok: inc bc - push hl - exx - push hl - exx - ld l,e - ld h,d - sbc hl,bc - pop bc - ex af,af' -.loop2: - call nmi_off - call RDVRM ; unpack - ex de,hl - call WRTVRM - ex de,hl ; 4 - call nmi_on - inc hl ; 6 - inc de ; 6 - dec bc ; 6 - ld a,b ; 4 - or c ; 4 - jr nz,.loop2 ; 10 - ex af,af' - pop hl - jp (iy) - -.getbit: ld a,(hl) - inc hl - rla - ret - -.getbitexx: - exx - ld a,(hl) - inc hl - exx - rla - ret - -.modes: - dw .offsok - dw .mode2 - dw .mode3 - dw .mode4 - dw .mode5 - dw .mode6 - - endif - -START: - if SVI+SG1000+SMS - im 1 - endif - if MEMOTECH -Z80_CTC: equ $08 - endif - if EINSTEIN -Z80_CTC: equ $28 - endif - - if EINSTEIN+MEMOTECH - di - im 2 - ld a,rom_start>>8 - ld i,a - ld a,$03 ; Reset Z80 CTC - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - ld a,$08 ; Interrupt vector offset - out (Z80_CTC+0),a - endif - if MEMOTECH - ld a,$25 ; Disable channel 2 interrupt. - out (Z80_CTC+2),a - ld a,$9c - out (Z80_CTC+2),a - ld a,$25 ; Disable channel 1 interrupt. - out (Z80_CTC+1),a - ld a,$9c - out (Z80_CTC+1),a - ld a,$c5 ; Enable channel 0 interrupt (VDP). - out (Z80_CTC+0),a - ld a,$01 - out (Z80_CTC+0),a - endif - if SORD - ld hl,$186c ; Disable handling of CTC Channel 1 interruption. - ld ($7002),hl - ld hl,$7040 - set 0,(hl) ; Avoid BIOS VDP handling. - endif - if SVI - ld e,$00 - ld a,$08 - call WRTPSG - ld a,$09 - call WRTPSG - ld a,$0A - call WRTPSG - ld a,$07 - ld e,$b8 - call WRTPSG - ld a,$92 ; Setup 8255 for keyboard/joystick reading. - out ($97),a - endif - if SG1000+SMS - ; Contributed by SiRioKD - ld a,$9F ; Turn off PSG - out (PSG),a - ld a,$BF - out (PSG),a - ld a,$DF - out (PSG),a - ld a,$FF - out (PSG),a - ld a,$92 ; Setup 8255 for SC3000. - out ($df),a - endif - if SG1000+SMS+SVI - ; Wait for VDP ready (around 1000 ms) - ld b,11 - ld de,$FFFF -.delay1: - ld hl,$39DE -.delay2: - add hl,de - jr c,.delay2 - djnz .delay1 - else - di - ld sp,STACK - endif - if NABU - im 2 - ld a,nabu_int>>8 - ld i,a - ld a,$03 ; Disable ROM - out ($00),a - ld a,$07 - out ($41),a - ld a,$78 ; Setup output ports and mixer. - out ($40),a - ld a,$0e - out ($41),a - ld a,$30 ; Enable video and keyboard. - out ($40),a - endif - if PV2000 - ld hl,nmi_handler - ld ($7499),hl - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - else - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - endif - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffc0) ; Megacart - endif - if SG1000+SMS - ld a,1 ; Sega mapper - ld ($fffe),a - endif - if MSX - ld a,1 ; ASCII 16K - ld ($7000),a - endif - endif - if MEMOTECH+EINSTEIN+NABU - ld ix,(lfsr) - ld hl,ram_start - ld de,ram_start+1 - ld bc,ram_end-ram_start-1 - ld (hl),0 - ldir - ld (lfsr),ix - else - ld hl,(lfsr) ; Save RAM trash for random generator. - ld de,BASE_RAM - xor a - ld (de),a - inc de - if PV2000 - bit 7,d - else - bit 2,d - endif - jp z,$-4 - ld (lfsr),hl - endif - - if SGM -WRITE_REGISTER: equ $1fd9 -FILL_VRAM: equ $1f82 -WRITE_VRAM: equ $1fdf - - ld b,$00 ; First step. -.0: ld hl,$2000 ; RAM at $2000. -.1: ld (hl),h ; Try to write a byte. - inc h - jp p,.1 ; Repeat until reaching $8000. - ld h,$20 ; Go back at $2000. -.2: ld a,(hl) ; Read back byte. - cp h ; Is it correct? - jr nz,.3 ; No, jump. - inc h - jp p,.2 ; Repeat until reaching $8000. - jp .4 ; Memory valid! - -.3: ld a,$01 ; Enable SGM - out ($53),a - inc b - bit 1,b ; Already enabled? - jr z,.0 ; No, test RAM again. - - ld bc,$0000 - call WRITE_REGISTER - ld bc,$0180 - call WRITE_REGISTER - ld bc,$0206 - call WRITE_REGISTER - ld bc,$0380 - call WRITE_REGISTER - ld bc,$0400 - call WRITE_REGISTER - ld bc,$0536 - call WRITE_REGISTER - ld bc,$0607 - call WRITE_REGISTER - ld bc,$070D - call WRITE_REGISTER - ld bc,$03F0 - ld de,$00E8 - ld hl,$158B ; Note! direct access to Colecovision ROM - call WRITE_VRAM - ld hl,$2000 - ld de,32 - ld a,$FD - call FILL_VRAM - ld hl,$1B00 - ld de,128 - ld a,$D1 - call FILL_VRAM - ld hl,$1800 - ld de,769 - ld a,$20 - call FILL_VRAM - ld bc,$0020 - ld de,$1980 - ld hl,.5 - call WRITE_VRAM - ld bc,$01C0 - call WRITE_REGISTER - jr $ - -.5: db " SUPER GAME MODULE NOT DETECTED " - -.4: - ld ix,(lfsr) - ld hl,$2000 - ld de,$2001 - ld bc,$5FFF - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO - ld a,($0069) - cp 50 - ld a,1 - jr nz,$+3 - dec a - endif - if SG1000+SMS+SVI+SORD+PV2000+NABU - ld a,1 ; Always NTSC. - endif - if MEMOTECH+EINSTEIN - ld a,0 ; Always PAL. - endif - if MSX - call RSLREG - ld b,1 ; $4000-$7fff - call get_slot_mapping - ld h,$80 - call ENASLT ; Map into $8000-$BFFF - - ld a,($002b) - cpl - rlca - and $01 - endif - ld (ntsc),a - - call music_init - - xor a - ld (mode),a - if SMS - call mode_4 - else - call mode_0 - endif - - xor a - ld (joy1_data),a - ld (joy2_data),a - if NABU - ld (nabu_data0),a - ld (nabu_data1),a - endif - ld a,$0f - ld (key1_data),a - ld (key2_data),a - if NABU - ld (nabu_data2),a - endif - - if MSX - ld hl,nmi_handler - ld ($fd9b),hl - ld a,$c3 - ld ($fd9a),a - endif - if SORD - ld hl,nmi_handler - ld ($7006),hl - endif - - ; CVBasic program start. - ; ' - ; ' Bouncing happy face (demo for CVBasic) - ; ' - ; ' by Oscar Toledo G. - ; ' https://nanochess.org/ - ; ' - ; ' Creation date: Feb/28/2024. - ; ' - ; - ; DEFINE SPRITE 0,2,happy_face - LD HL,0 - PUSH HL - LD A,2 - LD HL,cvb_HAPPY_FACE - CALL define_sprite - ; - ; PRINT AT 36,"Happy face!" - LD HL,72 - LD (cursor),HL - LD HL,cv1 - LD A,11 - CALL print_string - JP cv2 -cv1: - DB $48,$61,$70,$70,$79,$20,$66,$61 - DB $63,$65,$21 -cv2: - ; - ; x = 50 - LD A,50 - LD (cvb_X),A - ; y = 100 - LD A,100 - LD (cvb_Y),A - ; dx = 1 - LD A,1 - LD (cvb_DX),A - ; dy = 1 - LD A,1 - LD (cvb_DY),A - ; - ; game_loop: -cvb_GAME_LOOP: - ; WAIT - HALT - ; WAIT - HALT - ; SPRITE 0,y-1,x,0 - SUB A - PUSH AF - LD A,(cvb_Y) - DEC A - PUSH AF - LD A,(cvb_X) - PUSH AF - SUB A - CALL update_sprite - ; SPRITE 1,y-1,x+8,1 - LD A,1 - PUSH AF - LD A,(cvb_Y) - DEC A - PUSH AF - LD A,(cvb_X) - ADD A,8 - PUSH AF - LD A,1 - CALL update_sprite - ; - ; x = x + dx - LD HL,cvb_X - LD A,(cvb_DX) - ADD A,(HL) - LD (HL),A - ; IF x = 0 THEN dx = -dx - LD A,(HL) - AND A - JP NZ,cv3 - LD A,(cvb_DX) - NEG - LD (cvb_DX),A -cv3: - ; IF x = 240 THEN dx = -dx - LD A,(cvb_X) - CP 240 - JP NZ,cv4 - LD A,(cvb_DX) - NEG - LD (cvb_DX),A -cv4: - ; y = y + dy - LD HL,cvb_Y - LD A,(cvb_DY) - ADD A,(HL) - LD (HL),A - ; IF y = 0 THEN dy = -dy - LD A,(HL) - AND A - JP NZ,cv5 - LD A,(cvb_DY) - NEG - LD (cvb_DY),A -cv5: - ; IF y = 176 THEN dy = -dy - LD A,(cvb_Y) - CP 176 - JP NZ,cv6 - LD A,(cvb_DY) - NEG - LD (cvb_DY),A -cv6: - ; GOTO game_loop - JP cvb_GAME_LOOP - ; - ; ' The face includes the color for the sprite - ; ' A = Yellow in the default palette. - ; happy_face: -cvb_HAPPY_FACE: - ; BITMAP "......AA" - ; BITMAP "....AAAA" - DB $00,$03,$00,$03,$00,$0f,$00,$0f - ; BITMAP "...AAAAA" - ; BITMAP "..AAAAAA" - DB $00,$1f,$00,$1f,$00,$3f,$00,$3f - ; BITMAP ".AAAAAAA" - ; BITMAP ".AAFFFAA" - DB $00,$7f,$00,$7f,$1c,$7f,$1c,$7f - ; BITMAP "AAAFFFAA" - ; BITMAP "AAAFF4AA" - DB $1c,$ff,$1c,$ff,$18,$fb,$1c,$fb - ; BITMAP "AAAAAAAA" - ; BITMAP "AAAAAAAA" - DB $00,$ff,$00,$ff,$00,$ff,$00,$ff - ; BITMAP ".AAAAAAA" - ; BITMAP ".AAA66AA" - DB $00,$7f,$00,$7f,$00,$7f,$0c,$73 - ; BITMAP "..AAA666" - ; BITMAP "...AAA66" - DB $00,$3f,$07,$38,$00,$1f,$03,$1c - ; BITMAP "....AAAA" - ; BITMAP "......AA" - DB $00,$0f,$00,$0f,$00,$03,$00,$03 - ; - ; BITMAP "AA......" - ; BITMAP "AAAA...." - DB $00,$c0,$00,$c0,$00,$f0,$00,$f0 - ; BITMAP "AAAAA..." - ; BITMAP "AAAAAA.." - DB $00,$f8,$00,$f8,$00,$fc,$00,$fc - ; BITMAP "AAAAAAA." - ; BITMAP "AAFFFAA." - DB $00,$fe,$00,$fe,$38,$fe,$38,$fe - ; BITMAP "AAFFFAAA" - ; BITMAP "AA4FFAAA" - DB $38,$ff,$38,$ff,$18,$df,$38,$df - ; BITMAP "AAAAAAAA" - ; BITMAP "AAAAAAAA" - DB $00,$ff,$00,$ff,$00,$ff,$00,$ff - ; BITMAP "AAAAAAA." - ; BITMAP "AA66AAA." - DB $00,$fe,$00,$fe,$00,$fe,$30,$ce - ; BITMAP "666AAA.." - ; BITMAP "66AAA..." - DB $00,$fc,$e0,$1c,$00,$f8,$c0,$38 - ; BITMAP "AAAA...." - ; BITMAP "AA......" - DB $00,$f0,$00,$f0,$00,$c0,$00,$c0 - ; - ; CVBasic epilogue (BASIC compiler for Colecovision) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and - ; read_pointer variables. - ; Revision date: Mar/04/2024. Added music player. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/13/2024. Added Pletter decompressor. - ; Revision date: Mar/19/2024. Added support for sprite flicker. - ; Revision date: Apr/11/2024. Added support for Super Game Module. - ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. - ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it - ; can remain accessible in bank 0 (bank switching). - ; Revision date: Aug/02/2024. Added rom_end label for Memotech. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. - ; Revision date: Nov/12/2024. Added vdp_status. - ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. - ; - -rom_end: - - ; ROM final size rounding - if MSX+COLECO+SG1000+SMS+SVI+SORD - TIMES (($+$1FFF)&$1e000)-$ DB $ff - endif - if MEMOTECH+EINSTEIN+NABU - ; Align following data to a 256-byte page. - TIMES $100-($&$ff) DB $4f - endif - if PV2000 - TIMES $10000-$ DB $ff - endif - if SG1000+SMS - forg $7FF0 - org $7FF0 - db "TMR SEGA" - db 0,0 - db 0,0 ; Checksum - db $11,$78 ; Product code - db $00 ; Version - db $4c ; SMS Export + 32KB for checksum - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 - org BASE_RAM - endif -ram_start: - -sprites: - if SMS - rb 256 - else - rb 128 - endif -sprite_data: - rb 4 -frame: - rb 2 -read_pointer: - rb 2 -cursor: - rb 2 -lfsr: - rb 2 -mode: - rb 1 -flicker: - rb 1 -joy1_data: - rb 1 -joy2_data: - rb 1 -key1_data: - rb 1 -key2_data: - rb 1 -ntsc: - rb 1 -vdp_status: - rb 1 - if NABU -nabu_data0: rb 1 -nabu_data1: rb 1 -nabu_data2: rb 1 - endif - - if CVBASIC_MUSIC_PLAYER -music_tick: rb 1 -music_mode: rb 1 - - if CVBASIC_BANK_SWITCHING -music_bank: rb 1 - endif -music_start: rb 2 -music_pointer: rb 2 -music_playing: rb 1 -music_timing: rb 1 -music_note_counter: rb 1 -music_instrument_1: rb 1 -music_counter_1: rb 1 -music_note_1: rb 1 -music_instrument_2: rb 1 -music_counter_2: rb 1 -music_note_2: rb 1 -music_instrument_3: rb 1 -music_counter_3: rb 1 -music_note_3: rb 1 -music_counter_4: rb 1 -music_drum: rb 1 - -audio_freq1: rb 2 -audio_freq2: rb 2 -audio_freq3: rb 2 -audio_noise: rb 1 -audio_mix: rb 1 -audio_vol1: rb 1 -audio_vol2: rb 1 -audio_vol3: rb 1 - -audio_control: rb 1 -audio_vol4hw: rb 1 - endif - - if SGM - org $2000 ; Start for variables. - endif -cvb_X: rb 1 -cvb_Y: rb 1 -cvb_DX: rb 1 -cvb_DY: rb 1 -ram_end: diff --git a/happy_face_sms.rom b/happy_face_sms.rom deleted file mode 100644 index f7efce55a586478a67653fa7c6b0e3f1567aabbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI1U2Gd!701swjy+CNf23b2WXVj8N;VHow$&0`_QOXyA&Zlnq68_P^DN} zv~`fXu@ItuSRg_xH4jJ|QKYpHQi4R)J~JB4XFiN`E{M3VHY;+JT?O!oXQ&U{s_ovEFF?=fr(YfBy~zCo*!Lca2< zeBMJo*$6(tjt#S6sx)v^HZ~AmS4z2XSf^4hwXGNaK@AhGm2b$#57)h017BNOK(O*B zikE1Acm^^oD(jYtWinQMKEyDQ<|7IPKU2Icg`Ttsd4+^*v!z5|fr6}h|Gg8H3-7-y z9og2D_T;_Alf5nDU2a|TNNatvA*V#TQCXz0^C0x9Sspt^&x>b&ks{pR1zFF0l^wV3K3z1cq&Mm$8*gI352 zR=$t(e%*Cs@MK}wB@83q``B{QUcT-!Q+F4wl-g|O!(p?p%}Cu$#(Ch6z0|Tbd9DPvLc&F#B!YTn}umKr>C+X^Lp1P&^*DE%A6A zJx)q;I?-EID8Cp~VpCldn~qIqC$G_n60`kajm4B8;R#|+luam!ES40dj(|>coS*J! z7)FR>c&CXHnW^kzCPB)GD4-5q4vwVlQIlcU;**p0V36wRsw~S@(qidq2KGAkqrpET zK4MH_Ct@SGJ%~|>i7cW%qB=U#x?PgXE!%m-c}4!IH1fwYnR+He)l5cwU{9yhhzkX+ ziu~zn8g)5iTCCp}d9jFX8A^z1lmwwj*|twk=cgw#geYir%6yQ`3ct+aVs>f@{!oOU zNCpQ-2UwwteTbisu?~o$i9EKykny;!XR{w5UM4O|7we(~n@bG&k|UxeiNxt;qN*lZ zRh$zPc3WM1Z#&Ahsm#MDJ$NFwQO_0mcLdVYl<8?RW@CbU%;8uqOck^@`UB=OS@J)Mt-4 zKSqR$i%|fu?Nire1gzsLuTz(z#1y3q`|U<~MZpV`hhHokgiIt5I1#6{4VCh^UBT%eLGAm%MiA>CdfTPK9{*cLB|xok_HkSg{Lk-Fsak9g$QO1ZsH zI9S_P&^(P|g^+Skijlrjd6~vdOwZmq6ErIxfqW0dykslGo)cy@N|9I z@rmv;POJ|`_8DWxgmVb@`kf=z-NIjYwqX6%R(edzr9&NbEMK{Ux`fBGLeryrOAkHG zV;26c(R$PIoz$7VVU5xAlIu$M4pj*WHdwtM)0q)n2>dZ}08w@q4s=y2n}bYA%0ZJQ6eAMqP{ z)A|9FTUHA4wsjivO=}qP=hjyt-?F|1Iny5r7=3OdeAI2IZN~BA$KNwnYmLgV{$^=H zpTqMAPZQ7IaQ{{=ea!re(j!lMsM%B>e(}h_vtWIBPLh6v7i)LK-5;X-Oy_>_-|JW(LG%~XhaV?PUn4?!RfGp$lJ4p%X|8KO{Ny~0D2Gl zAo>JNbc^2XZgw@g8`RwCu+v1xD>UdGpq`d)dym+gN3WubyZ$NqHf;}x-W+IlJsNnl zw;y)e*509~E8SGj57>LKclU2F9+?0WU;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOyK{C0RH*GjR`OTCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB czyz286Zjtqyf}P8xp?}_DWcrpLrFUKPYdq&?f?J) diff --git a/manual.txt b/manual.txt index 841b260..5ea69fe 100644 --- a/manual.txt +++ b/manual.txt @@ -22,10 +22,15 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.8.0 Apr/26/2025 o Added support for VDP.STATUS (for reading VDP status) +v0.8.0 Apr/26/2025 o Added support for Sega Master System using --sms + o Added support for VDP.STATUS (for reading VDP status) o Added SELECT CASE / END SELECT o Added support for CHR$ in PRINT (for portable printing of arbitrary characters in the current cursor position) + o Added SCROLL statement for Sega Master System. + o Added BORDER flags for Sega Master System. + o Added PALETTE statement for Sega Master System. + o Adapted BITMAP, SCREEN, and SPRITE for Sega Master System. o Optimizes code using directly DI/EI instructions in Z80 platforms if possible. diff --git a/music.asm b/music.asm deleted file mode 100644 index 7c5232d..0000000 --- a/music.asm +++ /dev/null @@ -1,4792 +0,0 @@ - ; CVBasic compiler v0.8.0 Apr/26/2025 - ; Command: ./cvbasic --sms examples/music.bas music.asm - ; Created: Sat Apr 26 18:00:28 2025 - -COLECO: equ 0 -SG1000: equ 0 -MSX: equ 0 -SGM: equ 0 -SVI: equ 0 -SORD: equ 0 -MEMOTECH: equ 0 -EINSTEIN: equ 0 -CPM: equ 0 -PENCIL: equ 0 -PV2000: equ 0 -TI99: equ 0 -NABU: equ 0 -SMS: equ 1 - -CVBASIC_MUSIC_PLAYER: equ 1 -CVBASIC_COMPRESSION: equ 0 -CVBASIC_BANK_SWITCHING: equ 0 - -BASE_RAM: equ $c000 ; Base of RAM -STACK: equ $e000 ; Base stack pointer -VDP: equ $be ; VDP port (write) -VDPR: equ $be ; VDP port (read) -PSG: equ $7f ; PSG port (write) - - ; - ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. - ; Added 16-bit multiply, division, modulo, and abs. - ; Added random generator. Added sound routines. - ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. - ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/14/2024. Added _sgn16. - ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. - ; Revision date: Apr/11/2024. Added support for formatting numbers. Added - ; support for Super Game Module. - ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. - ; Shorter mode setting subroutines. - ; Revision date: Apr/26/2024. Interruption handler saves current bank. - ; Revision date: Apr/27/2024. Music player now supports bank switching. - ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller - ; support with keyboard (code by SiRioKD) - ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. - ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. - ; Revision date: Jun/17/2024. Added SVI-328 support. - ; Revision date: Aug/01/2024. Added Sord M5 support. - ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech - ; support. - ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support - ; for Casio PV-2000. - ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, - ; and Casio PV-2000. - ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision - ; with flicker flag). - ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number - ; keys values were inverted. - ; Revision date: Nov/12/2024. Saves the VDP status. - ; - -JOYSEL: equ $c0 -KEYSEL: equ $80 - -JOY1: equ $fc-$20*(SG1000+SMS) -JOY2: equ $ff-$22*(SG1000+SMS) - - if COLECO - org $8000 - if PENCIL - db "COPYRIGHT SOUNDIC" - jp START - jp nmi_handler - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - db "CVBASIC!POWERED BY!2024!" - else - db $55,$aa - dw 0 - dw 0 - dw 0 - dw 0 - dw START - - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - - jp nmi_handler - endif - endif - if SG1000+SMS+SVI - org $0000 - di - ld sp,STACK - jp START - db $ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp nmi_handler ; It should be called int_handler. - endif - if MSX - ORG $4000 - db "AB" - dw START - dw $0000 - dw $0000 - dw $0000 - dw $0000 - -WRTPSG: equ $0093 -RDPSG: equ $0096 - - endif - if SORD - ORG $2000 - db $02 ; Avoid checking $4000 - dw START ; Start address. - dw $002e ; Prestart address (just point to RET in BIOS). - endif - if PV2000 - ORG $C000 - jp START - endif - - if MEMOTECH - if CPM - org $0100 - else - org $40fc - dw rom_start - dw rom_end-rom_start - endif -rom_start: - jp START - db 0,0,0,0,0 - dw nmi_handler - dw null_vector - dw null_vector - dw rom_start - -null_vector: - ei - reti - endif - if EINSTEIN - org $0100 -rom_start: - jp START - db 0,0,0,0,0 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - endif - if NABU - if CPM - org $0100 - else - org $140d - endif - nop - nop - nop - jp START - times $100-($&255) db $ff -nabu_int: - dw null_vector - dw null_vector - dw keyboard_handler - dw nmi_handler - dw null_vector - dw null_vector - dw null_vector - dw null_vector - -null_vector: - ei - reti - endif - - if SVI -WRTPSG: - out ($88),a - push af - ld a,e - out ($8c),a - pop af - ret - -RDPSG: - out ($88),a - push af - pop af - in a,($90) - ret - endif - - if EINSTEIN -WRTPSG: - out ($02),a - push af - ld a,e - out ($03),a - pop af - ret - -RDPSG: - out ($02),a - push af - pop af - in a,($02) - ret - endif - - if NABU -WRTPSG: - out ($41),a - push af - ld a,e - out ($40),a - pop af - ret - -RDPSG: - out ($41),a - push af - pop af - in a,($40) - ret - endif - - if PV2000 - ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) -WRTVDP: - ld a,b - ld (VDP+1),a - ld a,c - or $80 - ld (VDP+1),a - ret - -SETWRT: - ld a,l - ld (VDP+1),a - ld a,h - or $40 - ld (VDP+1),a - ret - -SETRD: - ld a,l - ld (VDP+1),a - ld a,h - and $3f - ld (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - ld (VDP),a - ret - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - ld a,(VDP) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: ld (VDP),a ; 13 14 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 37 42 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - ld a,(VDP) - ld (de),a - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - EX DE,HL - CALL SETWRT - EX DE,HL - DEC BC - INC C - LD A,B - LD B,C - INC A - LD C,A -.1: - LD A,(HL) ; 7 8 - LD (VDP),A ; 13 14 - INC HL ; 6 7 - DJNZ .1 ; 13 14 - DEC C ; 4 5 - JP NZ,.1 ; 10 11 - RET - else - ; Normal platforms with VDP connected via ports (IORQ) -WRTVDP: - ld a,b - out (VDP+1),a - ld a,c - or $80 - out (VDP+1),a - ret - -SETWRT: - ld a,l - out (VDP+1),a - ld a,h - or $40 - out (VDP+1),a - ret - -SETRD: - ld a,l - out (VDP+1),a - ld a,h - and $3f - out (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - out (VDP),a - ret - - if SG1000+SMS - db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff - - ; Located at $0066 - ei ; NMI handler (pause button) - retn - endif - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - in a,(VDPR) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: out (VDP),a ; 11 12 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 35 40 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - in a,(VDP) - ld (de),a - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - ex de,hl - call SETWRT - ex de,hl - dec bc - inc c - ld a,b - ld b,c - inc a - ld c,VDP -.1: - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - outi - jp nz,.1 - dec a - jp nz,.1 - ret - endif - - if SMS - else -LDIRVM3: - call .1 - call .1 -.1: push hl - push de - push bc - call LDIRVM - pop bc - pop de - ld a,d - add a,8 - ld d,a - pop hl - ret - endif - -DISSCR: - call nmi_off - ld bc,$a201 - call WRTVDP - jp nmi_on - -ENASCR: - call nmi_off - ld bc,$e201 - call WRTVDP - jp nmi_on - -CPYBLK: - pop hl - ex af,af' - pop af - ld b,a - pop af - ld c,a - pop de - ex (sp),hl - call nmi_off -.1: push bc - push hl - push de - ld b,0 - call LDIRVM - pop hl - ld bc,$0020 - add hl,bc - ex de,hl - pop hl - ex af,af' - ld c,a - ld b,0 - add hl,bc - ex af,af' - pop bc - djnz .1 - jp nmi_on - -nmi_off: - if COLECO+PV2000 - push hl - ld hl,mode - set 0,(hl) - pop hl - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - di - endif - ret - -nmi_on: - if COLECO+PV2000 - push af - push hl - ld hl,mode - res 0,(hl) - nop - bit 1,(hl) - jp nz,nmi_handler.0 - pop hl - pop af - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - ei - endif - ret - - if COLECO -keypad_table: - db $0f,$08,$04,$05,$0c,$07,$0b,$02 - db $0d,$0a,$00,$09,$03,$01,$06,$0f - endif - -cls: - if SMS - ld hl,$3800 - ld (cursor),hl - di - call SETWRT -.1: ld a,$20 ; 7 - out (VDP),a ; 11 - inc hl ; 6 - inc hl ; 6 - ld a,$00 ; 7 - out (VDP),a ; 11 - ld a,h ; 4 - cp $3e ; 7 - jp nz,.1 ; 10 - ei - ret - else - ld hl,$1800 - ld (cursor),hl - ld bc,$0300 - ld a,$20 - call nmi_off - call FILVRM - jp nmi_on - endif - -print_string: - ld c,a - ld b,0 - ld de,(cursor) - if SMS - ld a,d - and $07 - or $38 - ld d,a - else - ld a,d - and $07 - or $18 - ld d,a - endif - push de - push bc - call nmi_off - if SMS - ex de,hl -.1: ld a,(de) - call WRTVRM - inc de - inc hl - xor a - call WRTVRM - inc hl - dec bc - ld a,b - or c - jp nz,.1 - else - call LDIRVM - endif - call nmi_on - pop bc - pop hl - add hl,bc - if SMS - add hl,bc - endif - ld (cursor),hl - ret - -print_number: - ld b,0 - call nmi_off -print_number5: - ld de,10000 - call print_digit -print_number4: - ld de,1000 - call print_digit -print_number3: - ld de,100 - call print_digit -print_number2: - ld de,10 - call print_digit -print_number1: - ld de,1 - ld b,e - call print_digit - jp nmi_on - -print_digit: - ld a,$2f - or a -.2: inc a - sbc hl,de - jp nc,.2 - add hl,de - cp $30 - jr nz,.3 - ld a,b - or a - ret z - dec a - jr z,.4 - ld a,c - jr print_char -.4: - ld a,$30 -.3: ld b,1 - -print_char: - push hl - ld hl,(cursor) - ex af,af' - ld a,h - and $07 - if SMS - or $38 - else - or $18 - endif - ld h,a - ex af,af' - call WRTVRM - inc hl - if SMS - xor a - call WRTVRM - inc hl - endif - ld (cursor),hl - pop hl - ret - -define_char: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - di - call LDIRVM - ei - ret - else - call nmi_off - ld a,(mode) - and 8 - jr nz,.1 - call LDIRVM3 - jp nmi_on - -.1: call LDIRVM - jp nmi_on - endif - -define_color: - if SMS - ret - else - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d - call nmi_off - call LDIRVM3 - jp nmi_on - endif - -define_sprite: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - if SMS - set 1,h - else - ld h,$07 - endif - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ex de,hl - call nmi_off - call LDIRVM - jp nmi_on - endif - -update_sprite: - if SMS - pop bc - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - and $3f - ld e,a - ld d,sprites>>8 - ld a,(sprite_data) - ld (de),a - sla e - set 7,e - ld a,(sprite_data+1) - ld (de),a - inc e - ld a,(sprite_data+2) - ld (de),a - else - pop bc - ld (sprite_data+3),a - pop af - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - ld de,sprites - add a,a - add a,a - if SORD - or $80 - endif - ld e,a - ld hl,sprite_data - ld bc,4 - ldir - endif - ret - - ; Fast 16-bit multiplication. -_mul16: - ld b,h - ld c,l - ld a,16 - ld hl,0 -.1: - srl d - rr e - jr nc,.2 - add hl,bc -.2: sla c - rl b - dec a - jp nz,.1 - ret - - ; 16-bit signed modulo. - ; hl = hl % de -_mod16s: - ld a,h - or a - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _mod16 - pop af - ret p - jp _neg16 - - ; 16-bit signed division. - ; hl = hl / de -_div16s: - ld a,h - xor d - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _div16 - pop af - ret p - jp _neg16 - -_abs16: - bit 7,h - ret z -_neg16: - ld a,h - cpl - ld h,a - ld a,l - cpl - ld l,a - inc hl - ret - - ; Fast 16-bit division. - ; hl = hl / de -_div16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - rl c - rl b - ld h,b - ld l,c - ret - - ; Fast 16-bit modulo. -_mod16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - ret - -_sgn16: - ld a,h - or l - ret z - bit 7,h - ld hl,$ffff - ret nz - inc hl - inc hl - ret - - ; Random number generator. - ; From my game Mecha Eight. -random: - ld hl,(lfsr) - ld a,h - or l - jr nz,.0 - ld hl,$7811 -.0: ld a,h - and $80 - ld b,a - ld a,h - and $02 - rrca - rrca - xor b - ld b,a - ld a,h - and $01 - rrca - xor b - ld b,a - ld a,l - and $20 - rlca - rlca - xor b - rlca - rr h - rr l - ld (lfsr),hl - ret - -sn76489_freq: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld b,a - ld a,l - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - and $3f - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_vol: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - cpl - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_control: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - and $0f - or $e0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -ay3_reg: - if COLECO - push af - ld a,b - out ($50),a - pop af - out ($51),a - ret - endif - if SG1000+SORD+SMS+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,a - ld a,b - jp WRTPSG - endif - -ay3_freq: - if COLECO - out ($50),a - push af - ld a,l - out ($51),a - pop af - inc a - out ($50),a - push af - ld a,h - and $0f - out ($51),a - pop af - ret - endif - if SG1000+SMS+SORD+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,l - call WRTPSG - ld e,h - inc a - jp WRTPSG - endif - - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ; Required for SG1000 and Sega Master System as both don't have a BIOS - ; Required for SVI because we don't have access to BIOS in cartridge. - ; Required for Sord M5 because it doesn't provide an ASCII charset. - ; Required for Memotech/Einstein because CP/M uses the memory. - ; My personal font for TMS9928. - ; - ; Patterned after the TMS9928 programming manual 6x8 letters - ; with better lowercase letters, also I made a proper - ; AT sign. - ; -font_bitmaps: - db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space - db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! - db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " - db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # - db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ - db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % - db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & - db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' - db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( - db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) - db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * - db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + - db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , - db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - - db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . - db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / - db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 - db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 - db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 - db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 - db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 - db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 - db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 - db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 - db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 - db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 - db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : - db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; - db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < - db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = - db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > - db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? - db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ - db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A - db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B - db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C - db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D - db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E - db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F - db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G - db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H - db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I - db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J - db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K - db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L - db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M - db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N - db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O - db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P - db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q - db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R - db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S - db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T - db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U - db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V - db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W - db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X - db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y - db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z - db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ - db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ - db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] - db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E - db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ - db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 - db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a - db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b - db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c - db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d - db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e - db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f - db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g - db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h - db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i - db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j - db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k - db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l - db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m - db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n - db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o - db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p - db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q - db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r - db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s - db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t - db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u - db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v - db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w - db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x - db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y - db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z - db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { - db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | - db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } - db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e - db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f - endif - - if SMS -set_palette: - push hl - di - ld hl,$c000 - call SETWRT - pop hl - ld bc,16*256+VDP - outi - jp nz,$-2 - ei - ret - -mode_4: - di - ld bc,$0400 - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0e02 ; $3800 for pattern table. - call WRTVDP - ld bc,$ff03 ; Not used. - call WRTVDP - ld bc,$0304 ; Not used. - call WRTVDP - ld bc,$7e05 ; $3f00 for sprite attribute table. - call WRTVDP - ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) - call WRTVDP - ld bc,$0007 - call WRTVDP - ld bc,$0008 ; Background X scroll - call WRTVDP - ld bc,$0009 ; Background Y scroll - call WRTVDP - ld hl,$20*32 ; Point to space character bitmap - call SETWRT - ld hl,font_bitmaps - ld c,96 -.1: ld b,8 -.2: ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - inc hl - djnz .2 - dec c - jp nz,.1 - ei - call cls - di - ld hl,$3f00 - ld bc,$0040 - ld a,$e0 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,63 - ld (hl),$e0 - ldir - ei - ld hl,.3 - call set_palette - jp ENASCR - - ; TMS9118-alike palette. From https://www.smspower.org/Development/Palette -.3: db $00,$00,$08,$0c,$10,$30,$01,$3c,$02,$03,$05,$0f,$04,$33,$15,$3f - - else -vdp_generic_mode: - call nmi_off - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0602 ; $1800 for pattern table. - call WRTVDP - ld b,d - ld c,$03 ; for color table. - call WRTVDP - ld b,e - ld c,$04 ; for bitmap table. - call WRTVDP - ld bc,$3605 ; $1b00 for sprite attribute table. - call WRTVDP - ld bc,$0706 ; $3800 for sprites bitmaps. - call WRTVDP - ld bc,$0107 - jp WRTVDP - -mode_0: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM3 - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - call cls -vdp_generic_sprites: - call nmi_off - ld hl,$1b00 - ld bc,$0080 - ld a,$d1 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,127 - ld (hl),$d1 - ldir - call nmi_on - jp ENASCR - -mode_1: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - ld hl,$0000 - ld bc,$1800 - xor a - call FILVRM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - ld hl,$1800 -.1: call nmi_off - ld b,32 -.2: ld a,l - call WRTVRM - inc hl - djnz .2 - call nmi_on - ld a,h - cp $1b - jp nz,.1 - jp vdp_generic_sprites - -mode_2: - ld hl,mode - set 3,(hl) - ld bc,$0000 - ld de,$8000 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$0020 - ld a,$f0 - call FILVRM - call nmi_on - call cls - jp vdp_generic_sprites - endif - - if MSX -ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) -RSLREG: EQU $0138 ; Read slot status in A - - ; - ; Get slot mapping - ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) - ; A = Current slot selection status (CALL RSLREG) - ; -get_slot_mapping: - call rotate_slot - ld c,a - add a,$C1 ; EXPTBL - ld l,a - ld h,$FC - ld a,(hl) - and $80 ; Get expanded flag - or c - ld c,a - inc hl - inc hl - inc hl - inc hl - ld a,(hl) ; SLTTBL - call rotate_slot - rlca - rlca - or c ; A contains bit 7 = Marks expanded - ; bit 6 - 4 = Doesn't care - ; bit 3 - 2 = Secondary mapper - ; bit 1 - 0 = Primary mapper - ret - -rotate_slot: - push bc - dec b - inc b - jr z,.1 -.0: rrca - rrca - djnz .0 -.1: and 3 - pop bc - ret - - endif - -nmi_handler: - push af - push hl - ld hl,mode - bit 0,(hl) - jr z,.1 - set 1,(hl) - pop hl - pop af - retn - -.0: res 1,(hl) - -.1: push bc - push de - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fff) - endif - if MSX - ld a,($bfff) - endif - push af - endif - if SORD+MEMOTECH - call ctc_reti - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - in a,(VDPR+1) - ld (vdp_status),a - endif - - ; - ; Update of sprite attribute table - ; - if SMS - bit 2,(hl) - jr z,.4 - ld hl,$3f00 - call SETWRT - ld hl,sprites - ld bc,$4000+VDP - outi - jp nz,$-2 - ld hl,$3f80 - call SETWRT - ld hl,sprites - ld bc,$8000+VDP - outi - jp nz,$-2 - jr .5 - -.4: ld hl,$3f00 - call SETWRT - ld a,(flicker) - inc a - and $3f - ld (flicker),a - ld l,a - ld h,sprites>>8 - ld bc,$4000+VDP - ld de,6 - outi - add hl,de - res 7,l - jp nz,$-5 - ld hl,$3f80 - call SETWRT - ld a,(flicker) - add a,a - or $80 - ld l,a - ld h,sprites>>8 - ld bc,$8000+VDP - ld de,12 - outi - nop - nop - nop - outi - add hl,de - res 7,l - jp nz,$-10 -.5: - else - ld bc,$8000+VDP - bit 2,(hl) - jr z,.4 - - ld hl,$1b00 - call SETWRT - ld hl,sprites -.7: - if PV2000 - ld a,(hl) - ld (VDP),a - inc hl - djnz .7 - else - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp nz,.7 - endif - jr .5 - -.4: - ld hl,$1b00 - call SETWRT - ld a,(flicker) - add a,$04 - ld (flicker),a - ld de,24 - ld b,128 - ld l,a - if SORD - else - ld h,sprites>>8 - endif -.6: - if SORD - set 7,l - ld h,sprites>>8 - else - res 7,l - endif - if PV2000 - ld a,(hl) ; 7 8 - ld (VDP),a ; 13 14 - inc hl ; 6 7 - dec b ; 4 5 - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - else - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - endif - add hl,de - jp nz,.6 -.5: - endif - - if COLECO - out (JOYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - or $b0 - ld b,a - in a,(JOY2) - or $b0 - ld c,a - - out (KEYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - ld d,a - in a,(JOY2) - ld e,a - - ld a,d - rlca - or $7f - and b - cpl - ld (joy1_data),a - - ld a,e - rlca - or $7f - and c - cpl - ld (joy2_data),a - - ld a,d - and $0f - ld c,a - ld b,0 - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key1_data),a - - ld a,e - and $0f - ld c,a - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key2_data),a - endif - if SG1000+SMS - ld a,$07 - out ($de),a - ld b,$ff - in a,(JOY1) - ld h,a - in a,(JOY2) - ld l,a - in a,($de) - cp 7 - jp nz,.sg1000 - - ld a,$00 - out ($de),a - in a,($dc) - rra - ld c,1 - jr nc,.sg1 - in a,($dd) - rra - ld c,8 - jr nc,.sg1 - ld a,$01 - out ($de),a - in a,($dc) - rra - ld c,2 - jr nc,.sg1 - in a,($dd) - rra - ld c,9 - jr nc,.sg1 - ld a,$02 - out ($de),a - in a,($dc) - rra - ld c,3 - jr nc,.sg1 - in a,($dd) - rra - ld c,0 - jr nc,.sg1 - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a - ld c,10 - jr z,.sg1 - rra - ld c,4 - jr nc,.sg1 - ld a,$04 - out ($de),a - in a,($dc) - rra - ld c,5 - jr nc,.sg1 - ld a,$05 - out ($de),a - in a,($dc) - bit 6,a - ld c,11 - jr z,.sg1 - rra - ld c,6 - jr nc,.sg1 - ld a,$06 - out ($de),a - in a,($dc) - rra - ld c,7 - jr nc,.sg1 - ld c,15 -.sg1: ld a,c - ld (key1_data),a - - ld a,$04 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard down. - jr nz,$+4 - res 1,h - ld a,$05 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard left. - jr nz,$+4 - res 2,h - ld a,$06 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard right. - jr nz,$+4 - res 3,h - bit 6,a ; Keyboard up. - jr nz,$+4 - res 0,h - ld a,$02 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Ins - jr nz,$+4 - res 4,h - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Del - jr nz,$+4 - res 5,h -.sg1000: - bit 0,h - jr nz,$+4 - res 0,b - bit 1,h - jr nz,$+4 - res 2,b - bit 2,h - jr nz,$+4 - res 3,b - bit 3,h - jr nz,$+4 - res 1,b - bit 4,h - jr nz,$+4 - res 6,b - bit 5,h - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - - ld a,$ff - bit 6,h - jr nz,$+4 - res 0,a - bit 7,h - jr nz,$+4 - res 2,a - - bit 0,l - jr nz,$+4 - res 3,a - bit 1,l - jr nz,$+4 - res 1,a - bit 2,l - jr nz,$+4 - res 4,a - bit 3,l - jr nz,$+4 - res 5,a - cpl - ld (joy2_data),a - - endif - if MSX - ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php - ld a,15 - call RDPSG - and $b0 - or $4f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - ld b,$ff - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy2_data),a - - in a,($aa) - and $f0 - or $00 - out ($aa),a - in a,($a9) - cp $ff - ld c,$ff - jr nz,.key1 - in a,($aa) - and $f0 - or $01 - out ($aa),a - in a,($a9) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - in a,($aa) - and $f0 - or $07 - out ($aa),a - in a,($a9) - bit 5,a ; BS - ld c,$0a - jr z,.key2 - bit 7,a ; RET - ld c,$0b - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - in a,($aa) - and $f0 - or $08 - out ($aa),a - in a,($a9) - bit 5,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 6,a - jr nz,$+4 - res 2,b - bit 4,a - jr nz,$+4 - res 3,b - bit 0,a - jr nz,$+4 - res 6,b - in a,($aa) - and $f0 - or $04 - out ($aa),a - in a,($a9) - bit 2,a - jr nz,$+4 - res 7,b - - ld a,15 - call RDPSG - and $b0 - or $0f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - - ld a,b - cpl - ld (joy1_data),a - endif - if SVI - ld a,14 - call RDPSG - ld b,$ff - bit 4,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 5,a - jr nz,$+4 - res 2,b - bit 6,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 5,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy2_data),a - - ld a,$10 - out ($96),a - in a,($99) - cp $ff - ld c,$ff - jr nz,.key1 - ld a,$11 - out ($96),a - in a,($99) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - ld a,$16 - out ($96),a - in a,($99) - bit 6,a - ld c,$0b - jr z,.key2 - ld a,$15 - out ($96),a - in a,($99) - bit 6,a - ld c,$0a - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - ld a,$15 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 0,b - ld a,$18 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 1,b - ld a,$17 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 2,b - ld a,$16 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 3,b - ld a,$18 - out ($96),a - in a,($99) - bit 0,a - jr nz,$+4 - res 6,b - ld a,$13 - out ($96),a - in a,($99) - bit 5,a - jr nz,$+4 - res 7,b - - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 4,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy1_data),a - endif - if SORD - ld bc,$ffff - in a,($37) ; Read joystick - rra - jr nc,$+4 - res 1,b - rra - jr nc,$+4 - res 0,b - rra - jr nc,$+4 - res 3,b - rra - jr nc,$+4 - res 2,b - rra - jr nc,$+4 - res 1,c - rra - jr nc,$+4 - res 0,c - rra - jr nc,$+4 - res 3,c - rra - jr nc,$+4 - res 2,c - in a,($31) - rra - jr nc,$+4 - res 6,b - rra - jr nc,$+4 - res 7,b - rra - rra - rra - jr nc,$+4 - res 6,c - rra - jr nc,$+4 - res 7,c - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - in a,($31) ; Keyboard 1-8 - or a - ld c,$00 - jr nz,.key3 - in a,($35) - bit 0,a ; 9 - ld c,$09 - jr nz,.key5 - bit 1,a ; 0 - ld c,$00 - jr nz,.key5 - bit 7,a ; Backspace - ld c,$0a - jr nz,.key5 - in a,($30) - bit 7,a ; Enter - ld c,$0b - jr nz,.key5 - ld c,$0f - jr .key5 - -.key3: rra - inc c - jr nc,.key3 -.key5: - ld a,c - ld (key1_data),a - - endif - if MEMOTECH - ld bc,$ffff - - ld a,$fb - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 0,b ; Up direction. - bit 3,a ; Y - jr nz,$+4 - res 0,c ; Up direction. - - ld a,$ef - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 1,b ; Right key. - ld a,$bf - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 2,b ; Down key. - ld a,$f7 - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 3,b ; Left key. - ld a,$df - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a ; Home key. - jr nz,$+4 - res 6,b ; Button 1 - - ld a,$7F - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 2,a ; B - jr nz,$+4 - res 0,c ; Up key. - bit 1,a ; C - jr nz,$+4 - res 1,c ; Right key. - bit 3,a ; M - jr nz,$+4 - res 2,c ; Down key. - bit 0,a ; Z - jr nz,$+4 - res 3,c ; Left key. - bit 5,a ; - - jr nz,$+4 - res 7,c ; Button 2 for player 2. - bit 7,a ; - - jr nz,$+4 - res 7,b ; Button 2 for player 1. - in a,($06) ; Read keyboard data. - bit 0,a ; Space - jr nz,$+4 - res 6,c ; Button 1. - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$fe - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - ld b,1 - jr nc,.mt1 - rra - ld b,3 - jr nc,.mt1 - rra - ld b,5 - jr nc,.mt1 - rra - ld b,7 - jr nc,.mt1 - rra - ld b,9 - jr nc,.mt1 - ld a,$df - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - bit 6,a - ld b,11 - jr z,.mt1 - ld a,$fd - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - rra - ld b,2 - jr nc,.mt1 - rra - ld b,4 - jr nc,.mt1 - rra - ld b,6 - jr nc,.mt1 - rra - ld b,8 - jr nc,.mt1 - rra - ld b,0 - jr nc,.mt1 - in a,($06) - rra - ld b,10 - jr nc,.mt1 - ld b,15 -.mt1: - ld a,b - ld (key1_data),a - endif - if EINSTEIN - ld bc,$ffff - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 0,b ; Up - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 4,a - jr nz,$+4 - res 1,b ; Right - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - jr nz,$+4 - res 2,b ; Down - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - jr nz,$+4 - res 3,b ; Left - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 6,b ; Fire - ld a,$0e - out ($02),a - ld a,$7f - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 0,a - jr nz,$+4 - res 7,b ; 2nd fire - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$0e - out ($02),a - ld a,$ef - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - rra - ld b,7 - jr nc,.te1 - rra - ld b,6 - jr nc,.te1 - rra - ld b,5 - jr nc,.te1 - rra - ld b,4 - jr nc,.te1 - rra - ld b,3 - jr nc,.te1 - rra - ld b,2 - jr nc,.te1 - rra - ld b,1 - jr nc,.te1 - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - ld b,8 - jr z,.te1 - bit 4,a - ld b,10 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - ld b,9 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - ld b,11 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 7,a - ld b,0 - jr z,.te1 - ld b,15 -.te1: - ld a,b - ld (key1_data),a - endif - if PV2000 - ld bc,$ffff - ld a,7 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 0,b - bit 0,a - jr z,$+4 - res 3,b - ld a,6 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 1,b - bit 0,a - jr z,$+4 - res 2,b - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 0,a - jr z,$+4 - res 6,b - bit 1,a - jr z,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - ld a,0 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - and $0f - ld b,$04 - jr nz,.pv1 - in a,($10) - and $0f - ld b,$08 - jr nz,.pv1 - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($10) - ld b,11 - bit 0,a - jr nz,.pv2 - ld a,4 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - ld b,10 - bit 3,a - jr nz,.pv2 - in a,($10) - ld b,9 - bit 0,a - jr nz,.pv2 - ld b,0 - bit 3,a - jr nz,.pv2 - ld b,15 - jr .pv2 - -.pv1: rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b -.pv2: ld a,b - ld (key1_data),a - endif - if NABU - ld a,(nabu_data0) - and $cf - ld (joy1_data),a - ld a,(nabu_data1) - and $cf - ld (joy2_data),a - ld a,(nabu_data2) - ld (key1_data),a - ld a,$0f - ld (nabu_data2),a - endif - - if CVBASIC_MUSIC_PLAYER - ld a,(music_mode) - or a - call nz,music_hardware - endif - - ld hl,(frame) - inc hl - ld (frame),hl - - ld hl,lfsr ; Make LFSR more random - inc (hl) - inc (hl) - inc (hl) - - if CVBASIC_MUSIC_PLAYER - ; - ; Music is played with a 50hz clock. - ; - ld a,(ntsc) - or a - jr z,.2 - ld a,(music_tick) - inc a - cp 6 - jr nz,$+3 - xor a - ld (music_tick),a - jr z,.3 -.2: - ld a,(music_mode) - or a - call nz,music_generate -.3: - endif - - if CVBASIC_BANK_SWITCHING - pop af - if COLECO - ld l,a - ld h,$ff - ld a,(hl) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - pop de - pop bc - pop hl - if COLECO - in a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - if SG1000+SMS+SVI+NABU - pop af - ei - reti - endif - if MSX - pop af - ret - endif - if SORD+MEMOTECH - pop af - ei - ret - -ctc_reti: - reti - endif - if EINSTEIN - pop af - ret - endif - if PV2000 - ld a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - - if NABU -keyboard_handler: - push af - push bc - push hl - in a,($90) - ld c,a - cp $0d ; Enter - ld a,11 - jr z,.8 - ld a,c - cp $7f ; Del - ld a,10 - jr z,.8 - ld a,c - cp $30 - jr c,.7 - cp $3a - jr nc,.7 - sub $30 -.8: ld (nabu_data2),a - jr .1 -.7: - cp $a0 - jr c,.2 - cp $c0 - jr c,.joystick -.2: - ld hl,nabu_data0 - cp $80 - jr nz,.3 - res 4,(hl) - jr .1 -.3: - cp $81 - jr nz,.4 - set 4,(hl) - jr .1 -.4: - cp $e0 - jr c,.1 - and $0f - ld b,2 - jr z,.5 - dec a - ld b,8 - jr z,.5 - dec a - ld b,1 - jr z,.5 - dec a - ld b,4 - jr z,.5 - dec a - ld b,$80 - jr z,.5 - dec a - ld b,$40 - jr nz,.1 -.5: bit 4,c - jr nz,.6 - ld a,(hl) - or b - ld (hl),a - jr .1 - -.6: - ld a,b - cpl - and (hl) - ld (hl),a - jr .1 - -.joystick: - ld hl,nabu_data0 - bit 4,(hl) - jr z,$+5 - ld hl,nabu_data1 - ld b,$00 - bit 3,c - jr z,$+4 - set 0,b - bit 2,c - jr z,$+4 - set 1,b - bit 1,c - jr z,$+4 - set 2,b - bit 0,c - jr z,$+4 - set 3,b - bit 4,c - jr z,$+4 - set 6,b - ld (hl),b -.1: - pop hl - pop bc - pop af - ei - reti - endif - if SORD -wait: - ld de,(frame) -.1: - ld hl,(frame) - or a - sbc hl,de - jr z,.1 - ret - endif - if EINSTEIN -wait: - in a,(VDP+1) - nop - in a,(VDP+1) - bit 7,a - jr z,$-4 - ld (vdp_status),a - jp nmi_handler - endif - - ; - ; The music player code comes from my - ; game Princess Quest for Colecovision (2012) - ; - - ; - ; Init music player. - ; -music_init: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$9f - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$bf - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$df - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ff - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ec - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 -MIX_BASE: equ $b8 - endif - if EINSTEIN+NABU -MIX_BASE: equ $78 - endif - if MSX+SVI+EINSTEIN+NABU - ld a,$08 - ld e,$00 - call WRTPSG - ld a,$09 - ld e,$00 - call WRTPSG - ld a,$0a - ld e,$00 - call WRTPSG - ld a,$07 - ld e,MIX_BASE - call WRTPSG - endif - if SGM - ld b,$08 - xor a - call ay3_reg - ld b,$09 - call ay3_reg - ld b,$0a - call ay3_reg - ld b,$07 - ld a,$b8 - call ay3_reg - endif - if CVBASIC_MUSIC_PLAYER - else - ret - endif - - if CVBASIC_MUSIC_PLAYER - ld a,$ff - ld (audio_vol4hw),a - ld a,$ec - ld (audio_control),a - ld a,MIX_BASE - ld (audio_mix),a - ld hl,music_silence - ; - ; Play a music. - ; HL = Pointer to music. - ; -music_play: - call nmi_off - ld a,(hl) - ld (music_timing),a - inc hl - ld (music_start),hl - ld (music_pointer),hl - xor a - ld (music_note_counter),a - inc a - ld (music_playing),a - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fff) - endif - if MSX - ld a,($bfff) - endif - ld (music_bank),a - endif - jp nmi_on - - ; - ; Generates music. - ; -music_generate: - ld a,(audio_mix) - and $c0 - or $38 - ld (audio_mix),a - xor a ; Turn off all the sound channels. - ld l,a - ld h,a - ld (audio_vol1),hl ; audio_vol1/audio_vol2 - ld (audio_vol3),a - ld a,$ff - ld (audio_vol4hw),a - - ld a,(music_note_counter) - or a - jp nz,.6 - ld hl,(music_pointer) -.15: push hl - if CVBASIC_BANK_SWITCHING - ld a,(music_bank) - if COLECO - ld e,a - ld d,$ff - ld a,(de) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - ld b,(hl) - inc hl - ld c,(hl) - inc hl - ld d,(hl) - inc hl - ld e,(hl) - pop hl - ld a,(music_timing) - rlca - jr nc,.16 - ld e,d - ld d,0 - jr .17 - -.16: rlca - jr nc,.17 - ld e,0 -.17: ld a,b ; Read first byte. - cp -2 ; End of music? - jr nz,.19 ; No, jump. - xor a ; Keep at same place. - ld (music_playing),a - ret - -.19: cp -3 ; Repeat music? - jp nz,.0 - ld hl,(music_start) - jr .15 - -.0: ld a,(music_timing) - and $3f ; Restart note time. - ld (music_note_counter),a - ld a,b - cp $3f ; Sustain? - jr z,.1 - rlca - rlca - and 3 - ld (music_instrument_1),a - ld a,b - and $3f - ld (music_note_1),a - xor a - ld (music_counter_1),a -.1: ld a,c - cp $3f - jr z,.2 - rlca - rlca - and 3 - ld (music_instrument_2),a - ld a,c - and $3f - ld (music_note_2),a - xor a - ld (music_counter_2),a -.2: ld a,d - cp $3f - jr z,.3 - rlca - rlca - and 3 - ld (music_instrument_3),a - ld a,d - and $3f - ld (music_note_3),a - xor a - ld (music_counter_3),a -.3: ld a,e - ld (music_drum),a - xor a - ld (music_counter_4),a - inc hl - inc hl - inc hl - ld a,(music_timing) - and $c0 - jr nz,.14 - inc hl -.14: ld (music_pointer),hl - -.6: ld a,(music_note_1) - or a - jr z,.7 - ld bc,(music_instrument_1) - call music_note2freq - ld (audio_freq1),hl - ld (audio_vol1),a - -.7: ld a,(music_note_2) - or a - jr z,.8 - ld bc,(music_instrument_2) - call music_note2freq - ld (audio_freq2),hl - ld (audio_vol2),a - -.8: ld a,(music_note_3) - or a - jr z,.9 - ld bc,(music_instrument_3) - call music_note2freq - ld (audio_freq3),hl - ld (audio_vol3),a - -.9: ld a,(music_drum) - or a - jr z,.4 - dec a ; 1 - Long drum. - jr nz,.5 - ld a,(music_counter_4) - cp 3 - jp nc,.4 -.10: ld a,5 - ld (audio_noise),a - call enable_drum - jr .4 - -.5: dec a ; 2 - Short durm. - jr nz,.11 - ld a,(music_counter_4) - or a - jp nz,.4 - ld a,8 - ld (audio_noise),a - call enable_drum - jr .4 - -.11: ;dec a ; 3 - Roll. - ;jp nz,.4 - ld a,(music_timing) - and $3e - rrca - ld b,a - ld a,(music_counter_4) - cp 2 - jp c,.10 - cp b - jp c,.4 - dec a - dec a - cp b - jp c,.10 -.4: - ld a,(music_counter_1) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_1),a - - ld a,(music_counter_2) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_2),a - - ld a,(music_counter_3) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_3),a - - ld hl,music_counter_4 - inc (hl) - ld hl,music_note_counter - dec (hl) - ret - - ; - ; Converts note to frequency. - ; Input: - ; A = Note (1-62). - ; B = Instrument counter. - ; C = Instrument. - ; Output: - ; HL = Frequency. - ; A = Volume. - ; -music_note2freq: - add a,a - ld e,a - ld d,0 - ld hl,music_notes_table - add hl,de - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - ld a,c - or a - jp z,music_piano - dec a - jp z,music_clarinet - dec a - jp z,music_flute - ; - ; Bass instrument. - ; -music_bass: - add hl,hl - - ; - ; Piano instrument. - ; -music_piano: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ret - -.1: - db 12,11,11,10,10,9,9,8 - db 8,7,7,6,6,5,5,4 - db 4,4,5,5,4,4,3,3 - - ; - ; Clarinet instrument. - ; -music_clarinet: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - srl h - rr l - jp nc,.2 - inc hl -.2: ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - - db 13,14,14,13,13,12,12,12 - db 11,11,11,11,12,12,12,12 - db 11,11,11,11,12,12,12,12 - - ; - ; Flute instrument. - ; -music_flute: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - - db 10,12,13,13,12,12,12,12 - db 11,11,11,11,10,10,10,10 - db 11,11,11,11,10,10,10,10 - - ; - ; Emit sound. - ; -music_hardware: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.7 ; Yes, jump. - ld a,(audio_vol2) - or a - jp nz,.7 - ld a,(audio_vol3) - or a - jp z,.7 - ld (audio_vol2),a - xor a - ld (audio_vol3),a - ld hl,(audio_freq3) - ld (audio_freq2),hl -.7: - ld hl,(audio_freq1) - ld a,h - cp 4 - ld a,$9f - jp nc,.1 - ld a,l - and $0f - or $80 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol1) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $90 -.1: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld hl,(audio_freq2) - ld a,h - cp 4 - ld a,$bf - jp nc,.2 - ld a,l - and $0f - or $a0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol2) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $b0 -.2: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.6 ; Yes, jump. - - ld hl,(audio_freq3) - ld a,h - cp 4 - ld a,$df - jp nc,.3 - ld a,l - and $0f - or $c0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol3) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $d0 -.3: out (PSG),a - if MEMOTECH - in a,($03) - endif - -.6: - ld a,(music_mode) - and 1 ; NO DRUMS? - ret z ; Yes, return. - - ld a,(audio_vol4hw) - inc a - jr z,.4 - ld a,(audio_noise) - cp 16 - ld b,$ec - jp c,.5 - ld b,$ed -; ld b,$ee -.5: ld a,(audio_control) - cp b - jr z,.4 - ld a,b - ld (audio_control),a - out (PSG),a - if MEMOTECH - in a,($03) - endif -.4: ld a,(audio_vol4hw) - out (PSG),a - if MEMOTECH - in a,($03) - endif - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.8 ; Yes, jump. - ld hl,audio_freq1 - ld bc,$0b00 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret -.8: - ld hl,audio_freq1 - ld bc,$0400 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - inc hl - inc hl - inc c - inc c - ld a,(music_mode) - and 1 - jr z,.9 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - jr .10 -.9: inc hl - inc c - inc hl - inc c -.10: ld b,$02 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret - endif - - ; - ; Enable drum. - ; -enable_drum: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$f5 - ld (audio_vol4hw),a - else - ld hl,audio_mix - ld a,(audio_vol2) - or a - jr nz,.1 - ld a,10 - ld (audio_vol2),a - set 1,(hl) -.1: res 4,(hl) - endif - ret - - ; - ; Musical notes table. - ; -music_notes_table: - ; Silence - 0 - dw 0 - if MEMOTECH+EINSTEIN - ; Values for 4.00 mhz. - ; 2nd octave - Index 1 - dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 - ; 3rd octave - Index 13 - dw 956,902,851,804,758,716,676,638,602,568,536,506 - ; 4th octave - Index 25 - dw 478,451,426,402,379,358,338,319,301,284,268,253 - ; 5th octave - Index 37 - dw 239,225,213,201,190,179,169,159,150,142,134,127 - ; 6th octave - Index 49 - dw 119,113,106,100,95,89,84,80,75,71,67,63 - ; 7th octave - Index 61 - dw 60,56,53 - else - ; Values for 3.58 mhz. - ; 2nd octave - Index 1 - dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 - ; 3rd octave - Index 13 - dw 855,807,762,719,679,641,605,571,539,508,480,453 - ; 4th octave - Index 25 - dw 428,404,381,360,339,320,302,285,269,254,240,226 - ; 5th octave - Index 37 - dw 214,202,190,180,170,160,151,143,135,127,120,113 - ; 6th octave - Index 49 - dw 107,101,95,90,85,80,76,71,67,64,60,57 - ; 7th octave - Index 61 - dw 53,50,48 - endif - - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ; - ; Converts AY-3-8910 volume to SN76489 - ; -ay2sn: - db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 - endif - -music_silence: - db 8 - db 0,0,0,0 - db -2 - endif - - if CVBASIC_COMPRESSION -define_char_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - else - ld a,(mode) - and 8 - jp z,unpack3 - endif - jp unpack - - if SMS - else -define_color_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d -unpack3: - call .1 - call .1 -.1: - push de - push hl - call unpack - pop hl - pop de - ld a,d - add a,8 - ld d,a - ret - endif - - ; - ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) - ; -unpack: -; Initialization - ld a,(hl) - inc hl - exx - ld de,0 - add a,a - inc a - rl e - add a,a - rl e - add a,a - rl e - rl e - ld hl,.modes - add hl,de - ld c,(hl) - inc hl - ld b,(hl) - push bc - pop ix - ld e,1 - exx - ld iy,.loop - -; Main depack loop -.literal: - ex af,af' - call nmi_off - ld a,(hl) - ex de,hl - call WRTVRM - ex de,hl - inc hl - inc de - call nmi_on - ex af,af' -.loop: add a,a - call z,.getbit - jr nc,.literal - -; Compressed data - exx - ld h,d - ld l,e -.getlen: add a,a - call z,.getbitexx - jr nc,.lenok -.lus: add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr nc,.lenok - add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr c,.lus -.lenok: inc hl - exx - ld c,(hl) - inc hl - ld b,0 - bit 7,c - jr z,.offsok - jp (ix) - -.mode6: add a,a - call z,.getbit - rl b -.mode5: add a,a - call z,.getbit - rl b -.mode4: add a,a - call z,.getbit - rl b -.mode3: add a,a - call z,.getbit - rl b -.mode2: add a,a - call z,.getbit - rl b - add a,a - call z,.getbit - jr nc,.offsok - or a - inc b - res 7,c -.offsok: inc bc - push hl - exx - push hl - exx - ld l,e - ld h,d - sbc hl,bc - pop bc - ex af,af' -.loop2: - call nmi_off - call RDVRM ; unpack - ex de,hl - call WRTVRM - ex de,hl ; 4 - call nmi_on - inc hl ; 6 - inc de ; 6 - dec bc ; 6 - ld a,b ; 4 - or c ; 4 - jr nz,.loop2 ; 10 - ex af,af' - pop hl - jp (iy) - -.getbit: ld a,(hl) - inc hl - rla - ret - -.getbitexx: - exx - ld a,(hl) - inc hl - exx - rla - ret - -.modes: - dw .offsok - dw .mode2 - dw .mode3 - dw .mode4 - dw .mode5 - dw .mode6 - - endif - -START: - if SVI+SG1000+SMS - im 1 - endif - if MEMOTECH -Z80_CTC: equ $08 - endif - if EINSTEIN -Z80_CTC: equ $28 - endif - - if EINSTEIN+MEMOTECH - di - im 2 - ld a,rom_start>>8 - ld i,a - ld a,$03 ; Reset Z80 CTC - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - ld a,$08 ; Interrupt vector offset - out (Z80_CTC+0),a - endif - if MEMOTECH - ld a,$25 ; Disable channel 2 interrupt. - out (Z80_CTC+2),a - ld a,$9c - out (Z80_CTC+2),a - ld a,$25 ; Disable channel 1 interrupt. - out (Z80_CTC+1),a - ld a,$9c - out (Z80_CTC+1),a - ld a,$c5 ; Enable channel 0 interrupt (VDP). - out (Z80_CTC+0),a - ld a,$01 - out (Z80_CTC+0),a - endif - if SORD - ld hl,$186c ; Disable handling of CTC Channel 1 interruption. - ld ($7002),hl - ld hl,$7040 - set 0,(hl) ; Avoid BIOS VDP handling. - endif - if SVI - ld e,$00 - ld a,$08 - call WRTPSG - ld a,$09 - call WRTPSG - ld a,$0A - call WRTPSG - ld a,$07 - ld e,$b8 - call WRTPSG - ld a,$92 ; Setup 8255 for keyboard/joystick reading. - out ($97),a - endif - if SG1000+SMS - ; Contributed by SiRioKD - ld a,$9F ; Turn off PSG - out (PSG),a - ld a,$BF - out (PSG),a - ld a,$DF - out (PSG),a - ld a,$FF - out (PSG),a - ld a,$92 ; Setup 8255 for SC3000. - out ($df),a - endif - if SG1000+SMS+SVI - ; Wait for VDP ready (around 1000 ms) - ld b,11 - ld de,$FFFF -.delay1: - ld hl,$39DE -.delay2: - add hl,de - jr c,.delay2 - djnz .delay1 - else - di - ld sp,STACK - endif - if NABU - im 2 - ld a,nabu_int>>8 - ld i,a - ld a,$03 ; Disable ROM - out ($00),a - ld a,$07 - out ($41),a - ld a,$78 ; Setup output ports and mixer. - out ($40),a - ld a,$0e - out ($41),a - ld a,$30 ; Enable video and keyboard. - out ($40),a - endif - if PV2000 - ld hl,nmi_handler - ld ($7499),hl - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - else - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - endif - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffc0) ; Megacart - endif - if SG1000+SMS - ld a,1 ; Sega mapper - ld ($fffe),a - endif - if MSX - ld a,1 ; ASCII 16K - ld ($7000),a - endif - endif - if MEMOTECH+EINSTEIN+NABU - ld ix,(lfsr) - ld hl,ram_start - ld de,ram_start+1 - ld bc,ram_end-ram_start-1 - ld (hl),0 - ldir - ld (lfsr),ix - else - ld hl,(lfsr) ; Save RAM trash for random generator. - ld de,BASE_RAM - xor a - ld (de),a - inc de - if PV2000 - bit 7,d - else - bit 2,d - endif - jp z,$-4 - ld (lfsr),hl - endif - - if SGM -WRITE_REGISTER: equ $1fd9 -FILL_VRAM: equ $1f82 -WRITE_VRAM: equ $1fdf - - ld b,$00 ; First step. -.0: ld hl,$2000 ; RAM at $2000. -.1: ld (hl),h ; Try to write a byte. - inc h - jp p,.1 ; Repeat until reaching $8000. - ld h,$20 ; Go back at $2000. -.2: ld a,(hl) ; Read back byte. - cp h ; Is it correct? - jr nz,.3 ; No, jump. - inc h - jp p,.2 ; Repeat until reaching $8000. - jp .4 ; Memory valid! - -.3: ld a,$01 ; Enable SGM - out ($53),a - inc b - bit 1,b ; Already enabled? - jr z,.0 ; No, test RAM again. - - ld bc,$0000 - call WRITE_REGISTER - ld bc,$0180 - call WRITE_REGISTER - ld bc,$0206 - call WRITE_REGISTER - ld bc,$0380 - call WRITE_REGISTER - ld bc,$0400 - call WRITE_REGISTER - ld bc,$0536 - call WRITE_REGISTER - ld bc,$0607 - call WRITE_REGISTER - ld bc,$070D - call WRITE_REGISTER - ld bc,$03F0 - ld de,$00E8 - ld hl,$158B ; Note! direct access to Colecovision ROM - call WRITE_VRAM - ld hl,$2000 - ld de,32 - ld a,$FD - call FILL_VRAM - ld hl,$1B00 - ld de,128 - ld a,$D1 - call FILL_VRAM - ld hl,$1800 - ld de,769 - ld a,$20 - call FILL_VRAM - ld bc,$0020 - ld de,$1980 - ld hl,.5 - call WRITE_VRAM - ld bc,$01C0 - call WRITE_REGISTER - jr $ - -.5: db " SUPER GAME MODULE NOT DETECTED " - -.4: - ld ix,(lfsr) - ld hl,$2000 - ld de,$2001 - ld bc,$5FFF - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO - ld a,($0069) - cp 50 - ld a,1 - jr nz,$+3 - dec a - endif - if SG1000+SMS+SVI+SORD+PV2000+NABU - ld a,1 ; Always NTSC. - endif - if MEMOTECH+EINSTEIN - ld a,0 ; Always PAL. - endif - if MSX - call RSLREG - ld b,1 ; $4000-$7fff - call get_slot_mapping - ld h,$80 - call ENASLT ; Map into $8000-$BFFF - - ld a,($002b) - cpl - rlca - and $01 - endif - ld (ntsc),a - - call music_init - - xor a - ld (mode),a - if SMS - call mode_4 - else - call mode_0 - endif - - xor a - ld (joy1_data),a - ld (joy2_data),a - if NABU - ld (nabu_data0),a - ld (nabu_data1),a - endif - ld a,$0f - ld (key1_data),a - ld (key2_data),a - if NABU - ld (nabu_data2),a - endif - - if MSX - ld hl,nmi_handler - ld ($fd9b),hl - ld a,$c3 - ld ($fd9a),a - endif - if SORD - ld hl,nmi_handler - ld ($7006),hl - endif - - ; CVBasic program start. - ; rem - ; rem Test of IntyBASIC music player - ; rem by Oscar Toledo G. http://nanochess.org - ; rem Aug/26/2014 - ; rem - ; - ; REM Include useful predefined constants - ; - ; main: -cvb_MAIN: - ; V=0 - SUB A - LD (cvb_V),A - ; - ; wait_key: -cvb_WAIT_KEY: - ; CLS - CALL cls - ; PRINT AT 66,"Press button" - LD HL,132 - LD (cursor),HL - LD HL,cv1 - LD A,12 - CALL print_string - JP cv2 -cv1: - DB $50,$72,$65,$73,$73,$20,$62,$75 - DB $74,$74,$6f,$6e -cv2: - ; FOR c = 0 TO 60 - SUB A - LD (cvb_C),A -cv3: - ; WAIT - HALT - ; NEXT c - LD HL,cvb_C - INC (HL) - LD A,(HL) - CP 61 - JP C,cv3 - ; wait_loop: -cvb_WAIT_LOOP: - ; IF CONT1.BUTTON THEN GOTO play_1 - LD A,(joy1_data) - AND 64 - JP Z,cv4 - JP cvb_PLAY_1 -cv4: - ; IF CONT1.BUTTON2 THEN GOTO play_2 - LD A,(joy1_data) - AND 128 - JP Z,cv5 - JP cvb_PLAY_2 -cv5: - ; - ; GOTO wait_loop - JP cvb_WAIT_LOOP - ; - ; play_1: -cvb_PLAY_1: - ; PRINT AT 66,"Bach Invention 8" - LD HL,132 - LD (cursor),HL - LD HL,cv6 - LD A,16 - CALL print_string - JP cv7 -cv6: - DB $42,$61,$63,$68,$20,$49,$6e,$76 - DB $65,$6e,$74,$69,$6f,$6e,$20,$38 -cv7: - ; PRINT AT 130,"(fragment)" - LD HL,260 - LD (cursor),HL - LD HL,cv8 - LD A,10 - CALL print_string - JP cv9 -cv8: - DB $28,$66,$72,$61,$67,$6d,$65,$6e - DB $74,$29 -cv9: - ; WAIT - HALT - ; PLAY SIMPLE - LD A,3 - LD (music_mode),A - ; PLAY tune_1 - LD HL,cvb_TUNE_1 - CALL music_play - ; - ; ' Sound effect if button touch - ; repeat: -cvb_REPEAT: - ; WAIT - HALT - ; IF CONT1.BUTTON2 THEN V=15 - LD A,(joy1_data) - AND 128 - JP Z,cv10 - LD A,15 - LD (cvb_V),A -cv10: - ; SOUND 2,300,V - LD HL,300 - LD A,$c0 - CALL sn76489_freq - LD A,(cvb_V) - LD B,$d0 - CALL sn76489_vol - ; IF V>0 THEN V=V-1 - LD A,(cvb_V) - CP 1 - JP C,cv11 - LD HL,cvb_V - DEC (HL) -cv11: - ; IF MUSIC.PLAYING THEN GOTO repeat - LD A,(music_playing) - OR A - JP Z,cv12 - JP cvb_REPEAT -cv12: - ; GOTO wait_key - JP cvb_WAIT_KEY - ; - ; play_2: -cvb_PLAY_2: - ; PRINT AT 66,"Mecha-8 Level 4 " - LD HL,132 - LD (cursor),HL - LD HL,cv13 - LD A,16 - CALL print_string - JP cv14 -cv13: - DB $4d,$65,$63,$68,$61,$2d,$38,$20 - DB $4c,$65,$76,$65,$6c,$20,$34,$20 -cv14: - ; PRINT AT 130,"(fragment)" - LD HL,260 - LD (cursor),HL - LD HL,cv15 - LD A,10 - CALL print_string - JP cv16 -cv15: - DB $28,$66,$72,$61,$67,$6d,$65,$6e - DB $74,$29 -cv16: - ; WAIT - HALT - ; PLAY FULL - LD A,5 - LD (music_mode),A - ; PLAY tune_2 - LD HL,cvb_TUNE_2 - CALL music_play - ; repeat2: -cvb_REPEAT2: - ; WAIT - HALT - ; IF CONT1.BUTTON THEN PLAY OFF: GOTO wait_key - LD A,(joy1_data) - AND 64 - JP Z,cv17 - LD HL,music_silence - CALL music_play - JP cvb_WAIT_KEY -cv17: - ; GOTO repeat2 - JP cvb_REPEAT2 - ; - ; ' Bach Invention 8 (BWV779) - ; ' Fragment - ; tune_1: DATA BYTE 7 -cvb_TUNE_1: - DB $07 - ; MUSIC F4,- - db $1e,$00,$00,$00 - ; MUSIC S,- - db $3f,$00,$00,$00 - ; MUSIC A4,- - db $22,$00,$00,$00 - ; MUSIC S,- - db $3f,$00,$00,$00 - ; MUSIC F4,- - db $1e,$00,$00,$00 - ; MUSIC S,- - db $3f,$00,$00,$00 - ; MUSIC C5,- - db $25,$00,$00,$00 - ; MUSIC S,- - db $3f,$00,$00,$00 - ; MUSIC F4,- - db $1e,$00,$00,$00 - ; MUSIC S,- - db $3f,$00,$00,$00 - ; - ; MUSIC F5,- - db $2a,$00,$00,$00 - ; MUSIC S,- - db $3f,$00,$00,$00 - ; MUSIC E5,F3 - db $29,$12,$00,$00 - ; MUSIC D5,S - db $27,$3f,$00,$00 - ; MUSIC C5,A3 - db $25,$16,$00,$00 - ; MUSIC D5,S - db $27,$3f,$00,$00 - ; MUSIC C5,F3 - db $25,$12,$00,$00 - ; MUSIC A4#,S - db $23,$3f,$00,$00 - ; MUSIC A4,C4 - db $22,$19,$00,$00 - ; MUSIC A4#,S - db $23,$3f,$00,$00 - ; MUSIC A4,F3 - db $22,$12,$00,$00 - ; MUSIC G4,S - db $20,$3f,$00,$00 - ; - ; MUSIC F4,F4 - db $1e,$1e,$00,$00 - ; MUSIC S,S - db $3f,$3f,$00,$00 - ; MUSIC A4,E4 - db $22,$1d,$00,$00 - ; MUSIC S,D4 - db $3f,$1b,$00,$00 - ; MUSIC C5,C4 - db $25,$19,$00,$00 - ; MUSIC S,D4 - db $3f,$1b,$00,$00 - ; MUSIC A4,C4 - db $22,$19,$00,$00 - ; MUSIC S,A3# - db $3f,$17,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC S,A3# - db $3f,$17,$00,$00 - ; MUSIC C5,A3 - db $25,$16,$00,$00 - ; MUSIC S,G3 - db $3f,$14,$00,$00 - ; - ; MUSIC A5,F3 - db $2e,$12,$00,$00 - ; MUSIC C6,S - db $31,$3f,$00,$00 - ; MUSIC A5#,A3 - db $2f,$16,$00,$00 - ; MUSIC C6,S - db $31,$3f,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; MUSIC C6,S - db $31,$3f,$00,$00 - ; MUSIC A5#,A3 - db $2f,$16,$00,$00 - ; MUSIC C6,S - db $31,$3f,$00,$00 - ; MUSIC A5,F4 - db $2e,$1e,$00,$00 - ; MUSIC C6,S - db $31,$3f,$00,$00 - ; MUSIC A5#,C4 - db $2f,$19,$00,$00 - ; MUSIC C6,S - db $31,$3f,$00,$00 - ; - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; MUSIC G5,A3# - db $2c,$17,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; MUSIC G5,A3# - db $2c,$17,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; MUSIC G5,A3# - db $2c,$17,$00,$00 - ; MUSIC A5,C4 - db $2e,$19,$00,$00 - ; - ; MUSIC D5,F3 - db $27,$12,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC E5,G3 - db $29,$14,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC D5,F3 - db $27,$12,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC E5,G3 - db $29,$14,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC D5,F3 - db $27,$12,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; MUSIC E5,G3 - db $29,$14,$00,$00 - ; MUSIC F5,A3 - db $2a,$16,$00,$00 - ; - ; MUSIC B4,D3 - db $24,$0f,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC G4,E3 - db $20,$11,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC D5,D3 - db $27,$0f,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC B4,E3 - db $24,$11,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC F5,D3 - db $2a,$0f,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC D5,E3 - db $27,$11,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; - ; MUSIC G5,B3 - db $2c,$18,$00,$00 - ; MUSIC A5,S - db $2e,$3f,$00,$00 - ; MUSIC G5,G3 - db $2c,$14,$00,$00 - ; MUSIC F5,S - db $2a,$3f,$00,$00 - ; MUSIC E5,C4 - db $29,$19,$00,$00 - ; MUSIC F5,S - db $2a,$3f,$00,$00 - ; MUSIC E5,G3 - db $29,$14,$00,$00 - ; MUSIC D5,S - db $27,$3f,$00,$00 - ; MUSIC C5,E4 - db $25,$1d,$00,$00 - ; MUSIC D5,S - db $27,$3f,$00,$00 - ; MUSIC C5,C4 - db $25,$19,$00,$00 - ; MUSIC A4#,S - db $23,$3f,$00,$00 - ; - ; MUSIC A4,F4 - db $22,$1e,$00,$00 - ; MUSIC S,G4 - db $3f,$20,$00,$00 - ; MUSIC D5,F4 - db $27,$1e,$00,$00 - ; MUSIC C5,E4 - db $25,$1d,$00,$00 - ; MUSIC B4,D4 - db $24,$1b,$00,$00 - ; MUSIC C5,E4 - db $25,$1d,$00,$00 - ; MUSIC B4,D4 - db $24,$1b,$00,$00 - ; MUSIC A4,C4 - db $22,$19,$00,$00 - ; MUSIC G4,B3 - db $20,$18,$00,$00 - ; MUSIC A4,C4 - db $22,$19,$00,$00 - ; MUSIC G4,B3 - db $20,$18,$00,$00 - ; MUSIC F4,A3 - db $1e,$16,$00,$00 - ; - ; MUSIC E4,G3 - db $1d,$14,$00,$00 - ; MUSIC F4,S - db $1e,$3f,$00,$00 - ; MUSIC E4,C4 - db $1d,$19,$00,$00 - ; MUSIC D4,B3 - db $1b,$18,$00,$00 - ; MUSIC C4,A3 - db $19,$16,$00,$00 - ; MUSIC S,B3 - db $3f,$18,$00,$00 - ; MUSIC C5,A3 - db $25,$16,$00,$00 - ; MUSIC B4,G3 - db $24,$14,$00,$00 - ; MUSIC C5,F3 - db $25,$12,$00,$00 - ; MUSIC S,G3 - db $3f,$14,$00,$00 - ; MUSIC E4,F3 - db $1d,$12,$00,$00 - ; MUSIC S,E3 - db $3f,$11,$00,$00 - ; - ; MUSIC F4,D3 - db $1e,$0f,$00,$00 - ; MUSIC S,E3 - db $3f,$11,$00,$00 - ; MUSIC C5,D3 - db $25,$0f,$00,$00 - ; MUSIC S,C3 - db $3f,$0d,$00,$00 - ; MUSIC E4,G3 - db $1d,$14,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC C5,E3 - db $25,$11,$00,$00 - ; MUSIC S,F3 - db $3f,$12,$00,$00 - ; MUSIC D4,G3 - db $1b,$14,$00,$00 - ; MUSIC S,S - db $3f,$3f,$00,$00 - ; MUSIC B4,G2 - db $24,$08,$00,$00 - ; MUSIC S,S - db $3f,$3f,$00,$00 - ; - ; MUSIC C5,C4 - db $25,$19,$00,$00 - ; MUSIC S,S - db $3f,$3f,$00,$00 - ; MUSIC S,S - db $3f,$3f,$00,$00 - ; MUSIC S,S - db $3f,$3f,$00,$00 - ; MUSIC STOP - db $fe,$00,$00,$00 - ; - ; ' Mecha-8 level 5: alone - ; ' Fragment - ; tune_2: DATA BYTE 5 -cvb_TUNE_2: - DB $05 - ; MUSIC G5#Y,C3#,-,M1 - db $ad,$0e,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC F5#,G3#,-,M2 - db $ab,$15,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC E5,C3#,-,M1 - db $a9,$0e,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC D5#,G3#,-,M2 - db $a8,$15,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC E5,C3#,-,M1 - db $a9,$0e,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC F5#,G3#,-,M2 - db $ab,$15,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC G5#,C3#,-,M1 - db $ad,$0e,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,G3#,-,M2 - db $3f,$15,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,C3#,-,M1 - db $3f,$0e,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC C5#,G3#,-,M2 - db $a6,$15,$00,$02 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC G5#,C3#,-,M1 - db $ad,$0e,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC E5,G3#,-,M2 - db $a9,$15,$00,$02 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC F5#,B2,-,M1 - db $ab,$0c,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,F3#,-,M2 - db $3f,$13,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,B2,-,M1 - db $3f,$0c,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC -,F3#,-,M2 - db $00,$13,$00,$02 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,B2,-,M1 - db $00,$0c,$00,$01 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,F3#,-,M2 - db $00,$13,$00,$02 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,B2,-,M1 - db $00,$0c,$00,$01 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,F3#,-,M1 - db $00,$13,$00,$01 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC C5#,B2,-,M1 - db $a6,$0c,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC F5#,F3#,-,M1 - db $ab,$13,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC C5#,B2,-,M1 - db $a6,$0c,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC E5,A2,-,M1 - db $a9,$0a,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,E3,-,M1 - db $3f,$11,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,A2,-,M1 - db $3f,$0a,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,E3,-,M1 - db $3f,$11,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,A2,-,M1 - db $3f,$0a,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,E3,-,M1 - db $3f,$11,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,A2,-,M1 - db $3f,$0a,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC F5#,E3,-,M1 - db $ab,$11,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC E5,A2,-,M2 - db $a9,$0a,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC D5#,E3,-,M1 - db $a8,$11,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,A2,-,M2 - db $3f,$0a,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC C5,G2#,-,M1 - db $a5,$09,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,D3#,-,M2 - db $3f,$10,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,G2#,-,M1 - db $3f,$09,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,D3#,-,M2 - db $3f,$10,$00,$02 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC S,G2#,-,M1 - db $3f,$09,$00,$01 - ; MUSIC S,S,-,M2 - db $3f,$3f,$00,$02 - ; MUSIC -,D3#,-,M2 - db $00,$10,$00,$02 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,G2#,-,M1 - db $00,$09,$00,$01 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,D3#,-,M2 - db $00,$10,$00,$02 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,G2#,-,M1 - db $00,$09,$00,$01 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,D3#,-,M1 - db $00,$10,$00,$01 - ; MUSIC -,S,-,M3 - db $00,$3f,$00,$03 - ; MUSIC -,G2#,-,M1 - db $00,$09,$00,$01 - ; MUSIC -,S,-,M2 - db $00,$3f,$00,$02 - ; MUSIC -,D3#,-,M1 - db $00,$10,$00,$01 - ; MUSIC -,S,-,M3 - db $00,$3f,$00,$03 - ; MUSIC -,G2#,-,M1 - db $00,$09,$00,$01 - ; MUSIC -,S,-,M1 - db $00,$3f,$00,$01 - ; MUSIC -,D3#,-,M1 - db $00,$10,$00,$01 - ; MUSIC -,S,-,M1 - db $00,$3f,$00,$01 - ; MUSIC REPEAT - db $fd,$00,$00,$00 - ; - ; CVBasic epilogue (BASIC compiler for Colecovision) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and - ; read_pointer variables. - ; Revision date: Mar/04/2024. Added music player. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/13/2024. Added Pletter decompressor. - ; Revision date: Mar/19/2024. Added support for sprite flicker. - ; Revision date: Apr/11/2024. Added support for Super Game Module. - ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. - ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it - ; can remain accessible in bank 0 (bank switching). - ; Revision date: Aug/02/2024. Added rom_end label for Memotech. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. - ; Revision date: Nov/12/2024. Added vdp_status. - ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. - ; - -rom_end: - - ; ROM final size rounding - if MSX+COLECO+SG1000+SMS+SVI+SORD - TIMES (($+$1FFF)&$1e000)-$ DB $ff - endif - if MEMOTECH+EINSTEIN+NABU - ; Align following data to a 256-byte page. - TIMES $100-($&$ff) DB $4f - endif - if PV2000 - TIMES $10000-$ DB $ff - endif - if SG1000+SMS - forg $7FF0 - org $7FF0 - db "TMR SEGA" - db 0,0 - db 0,0 ; Checksum - db $11,$78 ; Product code - db $00 ; Version - db $4c ; SMS Export + 32KB for checksum - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 - org BASE_RAM - endif -ram_start: - -sprites: - if SMS - rb 256 - else - rb 128 - endif -sprite_data: - rb 4 -frame: - rb 2 -read_pointer: - rb 2 -cursor: - rb 2 -lfsr: - rb 2 -mode: - rb 1 -flicker: - rb 1 -joy1_data: - rb 1 -joy2_data: - rb 1 -key1_data: - rb 1 -key2_data: - rb 1 -ntsc: - rb 1 -vdp_status: - rb 1 - if NABU -nabu_data0: rb 1 -nabu_data1: rb 1 -nabu_data2: rb 1 - endif - - if CVBASIC_MUSIC_PLAYER -music_tick: rb 1 -music_mode: rb 1 - - if CVBASIC_BANK_SWITCHING -music_bank: rb 1 - endif -music_start: rb 2 -music_pointer: rb 2 -music_playing: rb 1 -music_timing: rb 1 -music_note_counter: rb 1 -music_instrument_1: rb 1 -music_counter_1: rb 1 -music_note_1: rb 1 -music_instrument_2: rb 1 -music_counter_2: rb 1 -music_note_2: rb 1 -music_instrument_3: rb 1 -music_counter_3: rb 1 -music_note_3: rb 1 -music_counter_4: rb 1 -music_drum: rb 1 - -audio_freq1: rb 2 -audio_freq2: rb 2 -audio_freq3: rb 2 -audio_noise: rb 1 -audio_mix: rb 1 -audio_vol1: rb 1 -audio_vol2: rb 1 -audio_vol3: rb 1 - -audio_control: rb 1 -audio_vol4hw: rb 1 - endif - - if SGM - org $2000 ; Start for variables. - endif -cvb_C: rb 1 -cvb_V: rb 1 -ram_end: diff --git a/music.rom b/music.rom deleted file mode 100644 index 6a5d562dc9a725e318643e85b8840843d7672aca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI0e{fXQ701te`|It`Y{HKwhJ?4-goF%|WeE(f$?mEk{Xrz-59rt`QNhG&NveR0 zF0k!5!?x4Ww9+9n?UYQl8pSp^#R>hR$=*bmY+lzYE7l>3iB3|Tn3-fKG&Z>D_rBeL z$aJ*-^^beA@1A#l+;h(Tyti*3oL@yF1J#bX0iroRzP5bQ97*@>y%pfu=wDXt+1)w5NORT4ZQ1B`4tE_5xa9kG$F+=a%&} zVRuAss&n`h+Cucc~j`V1o4X53}c^%JjzR&2N1K+sUyrW=b8RQAs81 z#Hg~_Ojd=tKgNpl$=Rfb)|DyjJkkf%bg$PNq;zjI6YT#N%_b2#`8|a_F>blIZtIzo zNH%d@Y6~s!c4PMP&X!2231XvGD{>@J<`c?ySEjZ}`5znjyq)-L(`Sipfr6^Rnx4AJ z+fUyw6=i&?J<>B+UuD=^Xbk$y(pa^^lqfIPtnd0T=PEduiQU@W)Oga%rCQPzl4L>^vUtiw#A76u>#Gj%?2b^up}U}g5>&!pxZ;F z1+-$HWYs*HyT1RDl#KRV(4w!`%M;l-wOyW`8mO0}FJEomkTq-3!DvnMzM57q@*!K$ zt>tU($sb_5-<69(_5GV_)<=TXd+S&9V2RscXSQL+emHV4a`7S+)XiE`V`oGjqU9-Za2-urW8e)B40Q* z6^DHW>oE`?=N~R3Sc%+7t_v>JFt5VY#uVzuref$TD`VV$g4cx;%i`3=yHVQ+O)9#*y))6-9w%hMn4$Q)U0pmb zJ~-Ib(SdjuJd)s-=@G1hs{oFH}clGpSPfM38P-5 ziH`^o-@QUK<>O?dm{bTk7_zHf#{aK*Ww z6K~7L$3e0Q<*|P%RQSFCuYCmj;8t!Ydb0}y^4K5>K(;|}yIwD*=R-oG6A2WCJpuse zm)}O%7x5jUKV4$~kVx0aB?q9}J6aSZoWUiZp+Z#+t7;+E>w^-iiW??@xNw&nb6Xn{ zw>8q(c@HJF|0xT863z|3x6~#1b_~D2)TQ|D4N6&y?7M?otiDY_IcqWa zZsHd51%d`{(VAVhs+CJ!M&I(FF&kp?l?F|^?{SyCs$i+h>~jXqS)auxyYlw>-7Fid zwW_lA^ISAPKa>sB?Z43;hvlhkWvv%@MUQ)0d5eus&rUW3kE9O-`*3`KV-ClsT>5KS@KgV4 z7ChmvVV-gaey#TVi;;LSD=TE({w1u=e;vcGSD=QCCoZl-RCjB0nUDGX=oqU5OIS~T zy|ucKjos?K&AY{W?`WWyS$w9u7gM1LAWJEd$*87oq)BEz?|)yZUd#&9h{3I~gheu; zs(g!O+~6-^5m=U@W+~fy*{ZU=u$IBjrG&YtvFLM~%oua_rHsFD|* z2bO||bMiYSEH!N{t73j13zTI|s&1-g{#7hcku`aB(+a++KqX8!*Q*7AWh`Sj-D?e+ z{3}`NX?x-I^=dwhJ^ipLIa?7g8O+th$OtGsfVN({?-F9q`VYeR)V92>95kg{^Nme$~AHVte{P zb+sPXcY3uR*Lfvw)s;BBdSokBAvsU`!Rh<;@WhpH|CR7J_3&|NFi^|tstN-uS;lSt z^la2_o(!yJC#uX5d@&GHizykrfSVm0|7gC={7=(wO${c=^k?I4;~L{RwX1dK zVgDMo$Fqjj?$6YpJ?;p&*m!to$T9G)ei|D(;~3cL9O!f8l6>L_x_Oe%95>(hK#TgV zoqKld-1SiFPIaBfDDf&bXVAt27CNgQeDuENAHuzSPtf3B#5~8HsolyRULiKL(upS5 zGS3Prm`MFe4yZTogc08iis=4w%&6R)ls`4gY{;jxu15$*Sx(OD6<^Y; zbNccEqDm~NSe%p4z0k{wauT`I5LIJ6mpo5sA<;^#TZQ-< z=v=Nu+*LaA>3Yu2*YlVa$id}T>6OUOW0s>9mtUoq=bW2=ZtcaGs3%>&Wg)Y^jm^FrN~zTUomV& zu!SHwzjF90&@1Oy!XFs}j=M~r_rH|Wk22h1Ox#=KoAfF1OY)n5D)|e0YN|z5Cr}|2;d*9Vh93)fFK|U z2m*qDARq_`0)l`bAP5Kof`A|(2nYg#fFK|U2m*qDARq_`0)l`bAP5Kof`A|(2nYg# zfFK|U2m*qDARq_`0)l`bAP5Kof`A|(2nYg#fFK|U2m*qDARq_`0)l`bAP5Kof`A|( z2nYg#fFK|U2m*qDARq_`0)l`bAP5Kof`A|(2nYg#fFK|U2m*qDARq_`0)l`bAP5Ko Zg24Ys;Le8I)jKw9you=7OY Date: Sat, 26 Apr 2025 21:27:01 -0600 Subject: [PATCH 021/155] Converted face_joystick.bas to SMS --- examples/face_joystick_sms.bas | 82 ++++++++++++++++++++++++++++++++++ examples/happy_face_sms.bas | 1 + 2 files changed, 83 insertions(+) create mode 100644 examples/face_joystick_sms.bas diff --git a/examples/face_joystick_sms.bas b/examples/face_joystick_sms.bas new file mode 100644 index 0000000..594455e --- /dev/null +++ b/examples/face_joystick_sms.bas @@ -0,0 +1,82 @@ + ' + ' Joystick moving with joystick (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Mar/03/2024. + ' Revision date: Apr/26/2025. Adapted for Sega Master System. + ' + + DEFINE SPRITE 0,2,happy_face + + PRINT AT 36,"Happy face!" + + x = 50 + y = 100 + + SPRITE 2, 96, 128, 0 + SPRITE 3, 96, 136, 1 + +game_loop: + WAIT + PRINT AT 0, "VDP.STATUS = ", <>VDP.STATUS , " " + + SPRITE 0,y-1,x,0 + SPRITE 1,y-1,x+8,1 + + IF FRAME AND 1 THEN + IF cont1.up THEN IF y > 0 THEN y = y - 1 + IF cont1.left THEN IF x > 0 THEN x = x - 1 + IF cont1.right THEN IF x < 240 THEN x = x + 1 + IF cont1.down THEN IF y < 176 THEN y = y + 1 + IF cont1.button THEN + PALETTE 10+16,$30 + ELSEIF cont1.button2 THEN + PALETTE 10+16,$03 + ELSE + PALETTE 10+16,$0F + END IF + END IF + + GOTO game_loop + + ' The face includes the color for the sprite + ' A = Yellow in the default palette. + ' F = White + ' 4 = Yellow + ' 6 = Red +happy_face: + BITMAP "......AA" + BITMAP "....AAAA" + BITMAP "...AAAAA" + BITMAP "..AAAAAA" + BITMAP ".AAAAAAA" + BITMAP ".AAFFFAA" + BITMAP "AAAFFFAA" + BITMAP "AAAFF4AA" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + BITMAP ".AAAAAAA" + BITMAP ".AAA66AA" + BITMAP "..AAA666" + BITMAP "...AAA66" + BITMAP "....AAAA" + BITMAP "......AA" + + BITMAP "AA......" + BITMAP "AAAA...." + BITMAP "AAAAA..." + BITMAP "AAAAAA.." + BITMAP "AAAAAAA." + BITMAP "AAFFFAA." + BITMAP "AAFFFAAA" + BITMAP "AA4FFAAA" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAA." + BITMAP "AA66AAA." + BITMAP "666AAA.." + BITMAP "66AAA..." + BITMAP "AAAA...." + BITMAP "AA......" diff --git a/examples/happy_face_sms.bas b/examples/happy_face_sms.bas index 81ea0ef..03689e4 100644 --- a/examples/happy_face_sms.bas +++ b/examples/happy_face_sms.bas @@ -5,6 +5,7 @@ ' https://nanochess.org/ ' ' Creation date: Feb/28/2024. + ' Revision date: Apr/26/2025. Adapted for Sega Master System. ' DEFINE SPRITE 0,2,happy_face From a976c586e8fc296dcac1695b917f317fc4b0ec1a Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 26 Apr 2025 21:54:55 -0600 Subject: [PATCH 022/155] Support for 16x16 sprites BITMAP for SMS. Adapted brinquitos to SMS --- cvbasic.c | 113 ++++++++--- examples/brinquitos_sms.bas | 361 ++++++++++++++++++++++++++++++++++++ 2 files changed, 452 insertions(+), 22 deletions(-) create mode 100644 examples/brinquitos_sms.bas diff --git a/cvbasic.c b/cvbasic.c index fe65785..b410af1 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -218,7 +218,7 @@ struct loop { static struct loop *loops; -static unsigned char bitmap[32]; +static unsigned char bitmap[128]; static int bitmap_byte; /* @@ -3973,35 +3973,104 @@ void compile_statement(int check_for_else) get_lex(); if (lex != C_STRING ) { emit_error("syntax error in BITMAP"); - } else if (name_size == 16 && machine != SMS) { /* Sprites */ + } else if (name_size == 16) { /* Sprites */ int c; - value = 0; - for (c = 0; c < 16; c++) { - if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ - && name[c] != 0x20 && name[c] != 0x2e) /* space and . */ - value |= 0x8000 >> c; - } - get_lex(); - bitmap[bitmap_byte] = value >> 8; - bitmap[bitmap_byte + 16] = value; - bitmap_byte++; - if (bitmap_byte >= 16) { - bitmap_byte = 0; - for (c = 0; c < 32; c += 8) { - if (target == CPU_9900) { - sprintf(temp, "\tbyte >%02x,>%02x,>%02x,>%02x,>%02x,>%02x,>%02x,>%02x\n", - bitmap[c], bitmap[c + 1], bitmap[c + 2], bitmap[c + 3], - bitmap[c + 4], bitmap[c + 5], bitmap[c + 6], bitmap[c + 7]); - } else { + if (machine == SMS) { + int first_time = 1; + + value = 0; + for (c = 0; c < 8; c++) { + if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ + && name[c] != 0x20 && name[c] != 0x2e) { /* space and . */ + int d; + + if (isxdigit(name[c])) { + d = toupper(name[c]) - 0x30; + if (d > 9) + d -= 7; + } else { + if (first_time) { + emit_warning("invalid hexadecimal value in BITMAP"); + first_time = 0; + } + d = 0; + } + value |= ((d & 1) << 7) >> c; + value |= ((d & 2) << 6) >> c << 8; + value |= ((d & 4) << 5) >> c << 16; + value |= ((d & 8) << 4) >> c << 24; + } + } + bitmap[bitmap_byte + 0] = value; + bitmap[bitmap_byte + 1] = value >> 8; + bitmap[bitmap_byte + 2] = value >> 16; + bitmap[bitmap_byte + 3] = value >> 24; + value = 0; + for (c = 0; c < 8; c++) { + if (name[8 + c] != 0x30 && name[8 + c] != 0x5f /* 0 and _ */ + && name[8 + c] != 0x20 && name[8 + c] != 0x2e) { /* space and . */ + int d; + + if (isxdigit(name[8 + c])) { + d = toupper(name[8 + c]) - 0x30; + if (d > 9) + d -= 7; + } else { + if (first_time) { + emit_warning("invalid hexadecimal value in BITMAP"); + first_time = 0; + } + d = 0; + } + value |= ((d & 1) << 7) >> c; + value |= ((d & 2) << 6) >> c << 8; + value |= ((d & 4) << 5) >> c << 16; + value |= ((d & 8) << 4) >> c << 24; + } + } + get_lex(); + bitmap[bitmap_byte + 64] = value; + bitmap[bitmap_byte + 65] = value >> 8; + bitmap[bitmap_byte + 66] = value >> 16; + bitmap[bitmap_byte + 67] = value >> 24; + bitmap_byte += 4; + if (bitmap_byte == 64) { + bitmap_byte = 0; + for (c = 0; c < 128; c += 8) { sprintf(temp, "\tDB $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", bitmap[c], bitmap[c + 1], bitmap[c + 2], bitmap[c + 3], bitmap[c + 4], bitmap[c + 5], bitmap[c + 6], bitmap[c + 7]); + fprintf(output, "%s", temp); + } + } + } else { + value = 0; + for (c = 0; c < 16; c++) { + if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ + && name[c] != 0x20 && name[c] != 0x2e) /* space and . */ + value |= 0x8000 >> c; + } + get_lex(); + bitmap[bitmap_byte] = value >> 8; + bitmap[bitmap_byte + 16] = value; + bitmap_byte++; + if (bitmap_byte >= 16) { + bitmap_byte = 0; + for (c = 0; c < 32; c += 8) { + if (target == CPU_9900) { + sprintf(temp, "\tbyte >%02x,>%02x,>%02x,>%02x,>%02x,>%02x,>%02x,>%02x\n", + bitmap[c], bitmap[c + 1], bitmap[c + 2], bitmap[c + 3], + bitmap[c + 4], bitmap[c + 5], bitmap[c + 6], bitmap[c + 7]); + } else { + sprintf(temp, "\tDB $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", + bitmap[c], bitmap[c + 1], bitmap[c + 2], bitmap[c + 3], + bitmap[c + 4], bitmap[c + 5], bitmap[c + 6], bitmap[c + 7]); + } + fprintf(output, "%s", temp); } - fprintf(output, "%s", temp); } } - } else if (name_size == 8) { int c; diff --git a/examples/brinquitos_sms.bas b/examples/brinquitos_sms.bas new file mode 100644 index 0000000..ffb8adf --- /dev/null +++ b/examples/brinquitos_sms.bas @@ -0,0 +1,361 @@ + ' + ' Brinquitos: Demo game + ' + ' by Oscar Toledo Gutiérrez + ' https://nanochess.org/ + ' + ' Creation date: Oct/06/2024. + ' Revision date: Apr/26/2025. Adapted to Sega Master System. + ' + + CONST MAX_CLOUDS = 4 + + ' + ' Cloud information + ' + DIM cloud_x(MAX_CLOUDS) ' X-coordinate + DIM cloud_y(MAX_CLOUDS) ' Y-coordinate + DIM cloud_e(MAX_CLOUDS) ' State + + ' + ' Restart game + ' +restart_game: + ' Clear the screen + CLS + ' Turquoise numbers + FOR #c = $0603 TO $07FF STEP 4 + VPOKE #c, 0 + NEXT #c + ' Blue background + FOR #c = $0402 TO $0FFE STEP 4 + VPOKE #c, VPEEK(#c) OR $FF + NEXT #c + + ' Define sprites + DEFINE SPRITE 0,8,sprites_bitmaps + + #puntos = 0 + + ' Setup initial clouds + cloud_y(3) = 176 + cloud_y(2) = 126 + cloud_y(1) = 76 + cloud_y(0) = 26 + + cloud_x(3) = 128 + cloud_e(3) = 0 + + c = 2 + GOSUB setup_cloud + c = 1 + GOSUB setup_cloud + c = 0 + GOSUB setup_cloud + + ' Setup player + x = 128 ' X-coordinate + y = 160 ' Y-coordinate + jump_state = 0 ' Jump state + standing_on = 3 ' Standing on cloud 3 + + PLAY SIMPLE + PLAY music_gladiators + + ' + ' Main loop + ' +main_loop: + + ' + ' Jump sound effect. + ' + IF jump_state >= 33 THEN ' Jumping + f = 2 + SOUND 2, y, 12 + ELSEIF jump_state THEN ' Falling + f = 4 + SOUND 2, y, 12 + ELSE ' Standing + f = 0 + SOUND 2, , 0 + END IF + + ' Show the player sprite + SPRITE 0, y - 1, x - 8, f + SPRITE 1, y - 1, x, f + 1 + + ' Show sprites for clouds + FOR c = 0 TO 3 + SPRITE c * 2 + 2, cloud_y(c) - 1, cloud_x(c) - 8, 6 + SPRITE c * 2 + 3, cloud_y(c) - 1, cloud_x(c), 7 + NEXT c + + ' Video synchronization + WAIT + + ' Update score + PRINT AT 1,<>#puntos + + ' Detect if it should do vertical displacement... + ' ...of the screen. + IF y < 110 AND jump_state = 0 THEN + y = y + 1 + FOR c = 0 TO MAX_CLOUDS - 1 + cloud_y(c) = cloud_y(c) + 1 + IF cloud_y(c) = 192 THEN + cloud_y(c) = -8 + GOSUB setup_cloud + END IF + NEXT c + END IF + + ' Detect if the player stands on a cloud + IF jump_state <> 0 AND jump_state < 33 AND standing_on = 255 THEN + FOR c = 0 TO MAX_CLOUDS - 1 + IF ABS(cloud_x(c) + 1 - x) < 8 AND ABS(cloud_y(c) - 16 - y) < 3 THEN + jump_state = 0 + y = cloud_y(c) - 16 + standing_on = c + IF was_on <> standing_on THEN + #puntos = #puntos + 1 + END IF + END IF + NEXT c + END IF + + ' Move the clouds + FOR c = 0 TO MAX_CLOUDS - 1 + IF cloud_e(c) = 1 THEN ' 1- Left + IF standing_on = c THEN x = x - 2 + cloud_x(c) = cloud_x(c) - 2 + IF cloud_x(c) < 18 THEN cloud_e(c) = 2 + ELSEIF cloud_e(c) = 2 THEN ' 2- Right + IF standing_on = c THEN x = x + 2 + cloud_x(c) = cloud_x(c) + 2 + IF cloud_x(c) > 238 THEN cloud_e(c) = 1 + END IF + NEXT c + + ' Handle jumping. + IF jump_state THEN + IF jump_state >= 33 THEN + jump_state = jump_state - 1 + y = y - 2 + ELSE + y = y + 2 + IF y = 200 OR y = 201 THEN GOTO end_of_game + END IF + END IF + + ' Jump if button pressed + IF cont.button THEN + IF jump_state = 0 THEN + jump_state = 64 + was_on = standing_on + standing_on = 255 + END IF + END IF + + GOTO main_loop + + ' + ' End of game + ' +end_of_game: + ' Turn off jumping sound effect + SOUND 2, , 0 + + ' Final music + PLAY music_end + + PRINT AT 135,"G A M E O V E R" + + FOR c = 1 TO 240 + WAIT + NEXT c + + GOTO restart_game + + ' + ' Setup a cloud + ' +setup_cloud: PROCEDURE + + ' + ' Choose a position with margin of 32 pixels at each side. + ' Make sure the minimum distance of 64 pixels... + ' ...against the next cloud so the jump is possible. + ' + DO + cloud_x(c) = RANDOM(96) * 2 + 32 + LOOP WHILE ABS(cloud_x(c) + 1 - cloud_x((c + 1) % MAX_CLOUDS)) < 64 + + ' Assign a movement direction. + cloud_e(c) = RANDOM(2) + 1 + END + + ' + ' Game sprites + ' +sprites_bitmaps: + BITMAP "................" ' Standing + BITMAP "................" + BITMAP "................" + BITMAP "......AAAA......" + BITMAP ".....AAAAAA....." + BITMAP "....AAAAAAAAA..." + BITMAP "...AA44AA44AA..." + BITMAP "...AA44AA44AA..." + BITMAP "..AAAAAAAAAAAA.." + BITMAP ".AAAAAFAAFAAAAA." + BITMAP "AA.A66AAAA66A.AA" + BITMAP "AA.AA666666AA.AA" + BITMAP "AA.AAAAAAAAAA.AA" + BITMAP "999..AA..AA..999" + BITMAP "....555..555...." + BITMAP "...5555..5555..." + + BITMAP ".99..........99." ' Jumping + BITMAP "999..........999" + BITMAP "AAA...AAAA...AAA" + BITMAP ".AA..AAAAAA..AA." + BITMAP ".AA.A44AA44A.AA." + BITMAP ".A.AA44AA44AA.A." + BITMAP ".A.AAAAAAAAAA.A." + BITMAP "..AAAAFAAFAAAA.." + BITMAP "...A66AAAA66A..." + BITMAP "...AA66AA66AA..." + BITMAP "...AAA6666AAA..." + BITMAP "...AAAAAAAAAA..." + BITMAP ".....AA..AA....." + BITMAP ".....AA..AA....." + BITMAP ".....55..55....." + BITMAP "....555..555...." + + BITMAP ".99..........99." ' Falling + BITMAP "999...AAAA...999" + BITMAP ".AA..AAAAAA..AA." + BITMAP ".AA.A44AA44A.AA." + BITMAP ".A.AA44AA44AA.A." + BITMAP ".A.AAAAAAAAAA.A." + BITMAP "..AAAAFAAFAAAA.." + BITMAP "...AAAAFFAAAA..." + BITMAP "...AA666666AA..." + BITMAP "...AAA6666AAA..." + BITMAP "...AAAAAAAAAA..." + BITMAP ".....AA..AA....." + BITMAP ".....AA..AA....." + BITMAP ".....55..55....." + BITMAP ".....55..55....." + BITMAP "....555..555...." + + BITMAP "..FFF1FFF1F....." ' Cloud + BITMAP ".FFFFE1FFE1FE..." + BITMAP ".FFEEFF1FFE1FE.." + BITMAP "FFE11FF1FFE1FE.." + BITMAP "EE1FFF11EEF11E.." + BITMAP ".1FFF1FF111FE..." + BITMAP ".FFFF1FFE1FFFE.." + BITMAP ".FFFF1FFE1FFFFE." + BITMAP "..EEEE..EE..EE.." + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + + ' + ' Gladiators music (circus entry) + ' +music_gladiators: + DATA BYTE 7 + MUSIC C5,C3,-,- + MUSIC S,S,-,- + MUSIC B4,G3,-,- + MUSIC S,S,-,- + MUSIC A4#,G2,-,- + MUSIC B4,S,-,- + MUSIC A4#,G3,-,- + MUSIC A4,S,-,- + + MUSIC G4#,C3,-,- + MUSIC S,S,-,- + MUSIC G4,G3,-,- + MUSIC S,S,-,- + MUSIC F4#,G2,-,- + MUSIC S,S,-,- + MUSIC G4,G3,-,- + MUSIC S,S,-,- + + MUSIC A4,C3,-,- + MUSIC S,S,-,- + MUSIC G4#,G3,-,- + MUSIC S,S,-,- + MUSIC G4,G2,-,- + MUSIC G4#,S,-,- + MUSIC G4,G3,-,- + MUSIC F4#,S,-,- + + MUSIC F4,C3,-,- + MUSIC S,S,-,- + MUSIC E4,G3,-,- + MUSIC S,S,-,- + MUSIC D4#,G2,-,- + MUSIC S,S,-,- + MUSIC E4,G3,-,- + MUSIC S,S,-,- + + MUSIC G4,B2,-,- + MUSIC S,S,-,- + MUSIC F4,G3,-,- + MUSIC F4,S,-,- + MUSIC C4#,G2,-,- + MUSIC S,S,-,- + MUSIC D4,G3,-,- + MUSIC S,S,-,- + + MUSIC G4,B2,-,- + MUSIC S,S,-,- + MUSIC F4,G3,-,- + MUSIC F4,S,-,- + MUSIC C4#,G2,-,- + MUSIC S,S,-,- + MUSIC D4,G3,-,- + MUSIC S,S,-,- + + MUSIC B3,B2,-,- + MUSIC C4,S,-,- + MUSIC C4S,G3,-,- + MUSIC D4,S,-,- + MUSIC D4S,G2,-,- + MUSIC E4,S,-,- + MUSIC F4,G3,-,- + MUSIC F4S,S,-,- + + MUSIC G4,B2,-,- + MUSIC G4S,S,-,- + MUSIC A4,G3,-,- + MUSIC B4,S,-,- + MUSIC A4,G2,-,- + MUSIC S,S,-,- + MUSIC G4,G3,-,- + MUSIC S,S,-,- + + MUSIC REPEAT + + ' + ' Music for end of game. + ' +music_end: + DATA BYTE 20 + MUSIC C4,-,-,- + MUSIC G3,-,-,- + MUSIC C3,-,-,- + MUSIC S,-,-,- + MUSIC S,-,-,- + MUSIC S,-,-,- + MUSIC STOP + From 9e2038d097cec64fcc4a7a762148112ceaa4ca6f Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 26 Apr 2025 22:42:26 -0600 Subject: [PATCH 023/155] Adjusted syntax on SMS for SPRITE --- cvbasic_prologue.asm | 38 ++- examples/brinquitos_sms.bas | 10 +- examples/face_joystick_sms.bas | 53 ++-- examples/happy_face_sms.bas | 51 ++-- examples/space_attack_sms.bas | 427 +++++++++++++++++++++++++++++++++ manual.txt | 8 +- 6 files changed, 489 insertions(+), 98 deletions(-) create mode 100644 examples/space_attack_sms.bas diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 76b8315..0c51546 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -767,28 +767,22 @@ define_sprite: update_sprite: if SMS - pop bc - add a,a - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - and $3f - ld e,a - ld d,sprites>>8 - ld a,(sprite_data) - ld (de),a - sla e - set 7,e - ld a,(sprite_data+1) - ld (de),a - inc e - ld a,(sprite_data+2) - ld (de),a + pop bc ; Pop return address. + pop de ; 3th. argument in D (Y-coordinate) + ld e,a ; 4th. argument in E (frame) + pop af ; 2nd. argument in A (X-coordinate) + pop hl ; 1st. argument in H (sprite number) + push bc ; Push return address. + ld l,h + res 7,l + res 6,l + ld h,sprites>>8 + ld (hl),a + sla l + set 7,l + ld (hl),d + inc l + ld (hl),e else pop bc ld (sprite_data+3),a diff --git a/examples/brinquitos_sms.bas b/examples/brinquitos_sms.bas index ffb8adf..fe05475 100644 --- a/examples/brinquitos_sms.bas +++ b/examples/brinquitos_sms.bas @@ -71,10 +71,10 @@ main_loop: ' Jump sound effect. ' IF jump_state >= 33 THEN ' Jumping - f = 2 + f = 4 SOUND 2, y, 12 ELSEIF jump_state THEN ' Falling - f = 4 + f = 8 SOUND 2, y, 12 ELSE ' Standing f = 0 @@ -83,12 +83,12 @@ main_loop: ' Show the player sprite SPRITE 0, y - 1, x - 8, f - SPRITE 1, y - 1, x, f + 1 + SPRITE 1, y - 1, x, f + 2 ' Show sprites for clouds FOR c = 0 TO 3 - SPRITE c * 2 + 2, cloud_y(c) - 1, cloud_x(c) - 8, 6 - SPRITE c * 2 + 3, cloud_y(c) - 1, cloud_x(c), 7 + SPRITE c * 2 + 2, cloud_y(c) - 1, cloud_x(c) - 8, 12 + SPRITE c * 2 + 3, cloud_y(c) - 1, cloud_x(c), 14 NEXT c ' Video synchronization diff --git a/examples/face_joystick_sms.bas b/examples/face_joystick_sms.bas index 594455e..52dc4ec 100644 --- a/examples/face_joystick_sms.bas +++ b/examples/face_joystick_sms.bas @@ -16,14 +16,14 @@ y = 100 SPRITE 2, 96, 128, 0 - SPRITE 3, 96, 136, 1 + SPRITE 3, 96, 136, 2 game_loop: WAIT PRINT AT 0, "VDP.STATUS = ", <>VDP.STATUS , " " SPRITE 0,y-1,x,0 - SPRITE 1,y-1,x+8,1 + SPRITE 1,y-1,x+8,2 IF FRAME AND 1 THEN IF cont1.up THEN IF y > 0 THEN y = y - 1 @@ -47,36 +47,19 @@ game_loop: ' 4 = Yellow ' 6 = Red happy_face: - BITMAP "......AA" - BITMAP "....AAAA" - BITMAP "...AAAAA" - BITMAP "..AAAAAA" - BITMAP ".AAAAAAA" - BITMAP ".AAFFFAA" - BITMAP "AAAFFFAA" - BITMAP "AAAFF4AA" - BITMAP "AAAAAAAA" - BITMAP "AAAAAAAA" - BITMAP ".AAAAAAA" - BITMAP ".AAA66AA" - BITMAP "..AAA666" - BITMAP "...AAA66" - BITMAP "....AAAA" - BITMAP "......AA" - - BITMAP "AA......" - BITMAP "AAAA...." - BITMAP "AAAAA..." - BITMAP "AAAAAA.." - BITMAP "AAAAAAA." - BITMAP "AAFFFAA." - BITMAP "AAFFFAAA" - BITMAP "AA4FFAAA" - BITMAP "AAAAAAAA" - BITMAP "AAAAAAAA" - BITMAP "AAAAAAA." - BITMAP "AA66AAA." - BITMAP "666AAA.." - BITMAP "66AAA..." - BITMAP "AAAA...." - BITMAP "AA......" + BITMAP "......AAAA......" + BITMAP "....AAAAAAAA...." + BITMAP "...AAAAAAAAAA..." + BITMAP "..AAAAAAAAAAAA.." + BITMAP ".AAAAAAAAAAAAAA." + BITMAP ".AAFFFAAAAFFFAA." + BITMAP "AAAFFFAAAAFFFAAA" + BITMAP "AAAFF4AAAA4FFAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP ".AAAAAAAAAAAAAA." + BITMAP ".AAA66AAAA66AAA." + BITMAP "..AAA666666AAA.." + BITMAP "...AAA6666AAA..." + BITMAP "....AAAAAAAA...." + BITMAP "......AAAA......" diff --git a/examples/happy_face_sms.bas b/examples/happy_face_sms.bas index 03689e4..cf7dded 100644 --- a/examples/happy_face_sms.bas +++ b/examples/happy_face_sms.bas @@ -21,7 +21,7 @@ game_loop: WAIT WAIT SPRITE 0,y-1,x,0 - SPRITE 1,y-1,x+8,1 + SPRITE 1,y-1,x+8,2 x = x + dx IF x = 0 THEN dx = -dx @@ -37,36 +37,19 @@ game_loop: ' 4 = Yellow ' 6 = Red happy_face: - BITMAP "......AA" - BITMAP "....AAAA" - BITMAP "...AAAAA" - BITMAP "..AAAAAA" - BITMAP ".AAAAAAA" - BITMAP ".AAFFFAA" - BITMAP "AAAFFFAA" - BITMAP "AAAFF4AA" - BITMAP "AAAAAAAA" - BITMAP "AAAAAAAA" - BITMAP ".AAAAAAA" - BITMAP ".AAA66AA" - BITMAP "..AAA666" - BITMAP "...AAA66" - BITMAP "....AAAA" - BITMAP "......AA" - - BITMAP "AA......" - BITMAP "AAAA...." - BITMAP "AAAAA..." - BITMAP "AAAAAA.." - BITMAP "AAAAAAA." - BITMAP "AAFFFAA." - BITMAP "AAFFFAAA" - BITMAP "AA4FFAAA" - BITMAP "AAAAAAAA" - BITMAP "AAAAAAAA" - BITMAP "AAAAAAA." - BITMAP "AA66AAA." - BITMAP "666AAA.." - BITMAP "66AAA..." - BITMAP "AAAA...." - BITMAP "AA......" + BITMAP "......AAAA......" + BITMAP "....AAAAAAAA...." + BITMAP "...AAAAAAAAAA..." + BITMAP "..AAAAAAAAAAAA.." + BITMAP ".AAAAAAAAAAAAAA." + BITMAP ".AAFFFAAAAFFFAA." + BITMAP "AAAFFFAAAAFFFAAA" + BITMAP "AAAFF4AAAA4FFAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP ".AAAAAAAAAAAAAA." + BITMAP ".AAA66AAAA66AAA." + BITMAP "..AAA666666AAA.." + BITMAP "...AAA6666AAA..." + BITMAP "....AAAAAAAA...." + BITMAP "......AAAA......" diff --git a/examples/space_attack_sms.bas b/examples/space_attack_sms.bas new file mode 100644 index 0000000..b4a89ce --- /dev/null +++ b/examples/space_attack_sms.bas @@ -0,0 +1,427 @@ + ' + ' Space Attack (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Feb/29/2024. + ' Revision date: Nov/13/2024. Added pixel stars background and double-speed enemies. + ' + + DEFINE SPRITE 0,4,sprites_bitmaps + + DIM enemy_x(8) + DIM enemy_y(8) + DIM enemy_s(8) + +restart_game: + CLS + MODE 2 ' In this mode, char definitions are faster + + #score = 0 + + player_x = 120 + player_y = 176 + bullet_y = 0 + FOR c = 0 TO 7 + enemy_s(c) = 0 + NEXT c + + ' Draw the stars background + ' + ' We make a vertical strip using 8 characters (numbers 16 to 23) + ' and we repeat it continuously (24 rows / 8 characters = 3 repetitions) + ' + FOR d = 0 TO 31 ' For each column + e = e + RANDOM(4) + 2 ' Displace the strip offset for this column. + FOR #c = 0 TO 736 STEP 32 + e = ((e + 1) AND 7) OR 16 ' Limit to range 16 to 23. + VPOKE $1800 + #c + d, e ' Put strip character. + NEXT #c + NEXT d + + GOSUB update_score + +game_loop: + WAIT + + ' Displace stars pixel by pixel + ' + ' This is almost magic because these characters are used in the whole screen, + ' so this redefinition of characters updates the whole screen. + ' + DEFINE CHAR 16,8,VARPTR pixel_bitmaps(((FRAME / 2) AND 63) XOR 63) + + ' Background "music" (two tones alternating each 16 video frames) + #c = 960 + IF FRAME AND 32 THEN #c = 1023 + d = (FRAME AND 31) / 2 + SOUND 0, #c, 15 - d + + ' Setup player sprite + SPRITE 0,player_y-1,player_x,0,10 + + ' Setup bullet sprite + IF bullet_y = 0 THEN ' Active? + SPRITE 1,$d1,0,0,0 ' No, remove sprite. + SOUND 1,,0 ' Disable sound. + ELSE + SPRITE 1,bullet_y-1,bullet_x,8,7 ' Setup sprite. + bullet_y = bullet_y - 4 ' Displace bullet. + SOUND 1,bullet_y+16,11 ' Make sound. + END IF + + ' + ' Display and move the enemies. + ' + FOR c = 0 TO 7 + IF enemy_s(c) = 0 THEN ' No enemy + SPRITE c + 2, $d1, 0, 0, 0 + ' Create one + enemy_x(c) = RANDOM(240) + enemy_y(c) = $c0 + c * 4 + enemy_s(c) = RANDOM(2) + 1 + ELSEIF enemy_s(c) < 3 THEN ' Enemy moving. + SPRITE c + 2, enemy_y(c) - 1, enemy_x(c), 4, 2 + + ' Slowly drift towards the player. + IF (FRAME AND 3) = 0 THEN + IF player_x < enemy_x(c) THEN + enemy_x(c) = enemy_x(c) - 1 + ELSE + enemy_x(c) = enemy_x(c) + 1 + END IF + END IF + ' Move down. + IF enemy_s(c) = 1 THEN + enemy_y(c) = enemy_y(c) + 2 + ELSE + enemy_y(c) = enemy_y(c) + 3 + END IF + IF enemy_y(c) >= $c0 AND enemy_y(c) <= $c7 THEN ' Reached bottom. + enemy_x(c) = RANDOM(240) + enemy_y(c) = $f2 ' Reset enemy. + enemy_s(c) = RANDOM(2) + 1 + END IF + + ' + ' Check if bullet has been launched. + ' + IF bullet_y <> 0 THEN ' Is bullet launched? + IF ABS(bullet_x + 1 - enemy_x(c)) < 8 THEN + IF ABS(bullet_y + 1 - enemy_y(c)) < 8 THEN + enemy_s(c) = 3 ' Enemy explodes + #score = #score + 1 + GOSUB update_score + bullet_y = 0 + sound 2,2 ' Start enemy explosion sound + SOUND 3,$E7,13 + END IF + END IF + END IF + + ' + ' Check if player is hit by enemy. + ' + IF ABS(player_y + 1 - enemy_y(c)) < 8 THEN + IF ABS(player_x + 1 - enemy_x(c)) < 8 THEN + GOTO player_dies + END IF + END IF + ELSE + ' Enemy explosion. + IF FRAME AND 4 THEN d = 10 ELSE d = 6 + SPRITE c + 2, enemy_y(c) - 1, enemy_x(c), 12, d + + ' Displace explosion slowly. + IF FRAME AND 1 THEN + IF enemy_y(c) < $c0 THEN enemy_y(c) = enemy_y(c) + 1 + END IF + + ' Explosion sound. + SOUND 2,enemy_s(c) + enemy_s(c) = enemy_s(c) + 1 + IF enemy_s(c) = 80 THEN ' Time reached. + SOUND 3,,0 + enemy_x(c) = RANDOM(240) + enemy_y(c) = $f2 + enemy_s(c) = 1 ' Bring back enemy. + END IF + END IF + NEXT c + + ' + ' Movement of the player. + ' + IF cont1.left THEN IF player_x > 0 THEN player_x = player_x - 2 + IF cont1.right THEN IF player_x < 240 THEN player_x = player_x + 2 + IF cont1.button THEN ' Fire! + IF bullet_y = 0 THEN ' Only if no bullet active. + bullet_y = player_y - 8 + bullet_x = player_x + END IF + END IF + GOTO game_loop + + ' + ' Player dies. + ' +player_dies: + PRINT AT 11,"GAME OVER" + + ' + ' Explosion effect and sound. + ' + SOUND 0,,0 + SOUND 1,,0 + SOUND 2,32,0 + FOR c = 0 TO 120 + WAIT + SOUND 3,$E4 + (c AND 3),13 + SPRITE 0, player_y - 1 + RANDOM(5) - 2, player_x + RANDOM(5) - 2, 12, RANDOM(14) + 2 + NEXT c + SOUND 3,,0 + + ' + ' Remove enemies. + ' + FOR c = 1 TO 9 + SPRITE c, $d1, 0, 0, 0 + NEXT c + + ' + ' Big delay. + ' + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + + GOTO restart_game + + ' + ' Update the score on the screen. + ' +update_score: PROCEDURE + PRINT AT 2,#score,"0" + END + + ' + ' Pixel scrolling stars + ' +pixel_bitmaps: + BITMAP "....X..." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "....X..." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' + ' Bitmaps for the game. + ' +sprites_bitmaps: + BITMAP ".......XX......." + BITMAP ".......XX......." + BITMAP "......XXXX......" + BITMAP "......XXXX......" + BITMAP "......XXXX......" + BITMAP ".....XXXXXX....." + BITMAP ".....XXXXXX....." + BITMAP ".....XX..XX....." + BITMAP ".....X....X....." + BITMAP "..XX.XXXXXX.XX.." + BITMAP ".XXX.XXXXXX.XXX." + BITMAP ".XXXXX....XXXXX." + BITMAP "XX..XXXXX.XX..XX" + BITMAP "XXX.XXXXXXXXX.XX" + BITMAP "XXXX.XXXXXX.XXXX" + BITMAP ".XX..XX..XX..XX." + + BITMAP "....XXXXXXXX...." + BITMAP "...X........X..." + BITMAP "..X.XX....XX.X.." + BITMAP ".X...XXXXXX...X." + BITMAP ".X...X.XX.X...X." + BITMAP ".X...XXXXXX...X." + BITMAP ".X....XXXX....X." + BITMAP ".X..XX....XX..X." + BITMAP ".XXXX.XXXX.XXXX." + BITMAP "XXX..X....X..XXX" + BITMAP "..XXXXXXXXXXXX.." + BITMAP "XXX....XX....XXX" + BITMAP "X.XXXX.XX.XXXX.X" + BITMAP "X..XX.XXXX.XX..X" + BITMAP "XXX..XX..XX..XXX" + BITMAP "..XXXX....XXXX.." + + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP ".......XX......." + BITMAP "......XXXX......" + BITMAP "......XXXX......" + BITMAP "......XXXX......" + BITMAP "......XXXX......" + BITMAP "....XXXXXXXX...." + BITMAP "...XXXXXXXXXX..." + BITMAP "......XXXX......" + BITMAP ".....XX...XX...." + BITMAP "................" + BITMAP "................" + BITMAP "................" + + BITMAP "................" + BITMAP "................" + BITMAP ".......X........" + BITMAP ".......XX......." + BITMAP "X......XXX......" + BITMAP "XXX.....XXX...XX" + BITMAP "XXXXX..XXXX..XXX" + BITMAP "...XXXXXXXXXXX.." + BITMAP ".....XXXXXX.X..." + BITMAP "......X..X.X...." + BITMAP ".....XXXXXXXX..." + BITMAP "....XXX.XXXXXX.." + BITMAP "...XXX.....XXXX." + BITMAP "...XX........XXX" + BITMAP "..XX............" + BITMAP "................" diff --git a/manual.txt b/manual.txt index 5ea69fe..4e44596 100644 --- a/manual.txt +++ b/manual.txt @@ -636,7 +636,9 @@ The following statements are available: X contains the X-coordinate for the sprite (0-255) F contains the sprite frame. You must multiply the desired sprite - definition (0-63) by 4 to show the right sprite. + definition (0-63) by 4 to show the right sprite. For Sega Master + System the sprite frame is based on 8x8 blocks, so you need to use + multiplies of 2 for each 8x16 sprite (0-254) C contains the color for the sprite (0-15). Alternatively, you can add the flag $80 (128 decimal) to displace the sprite by 32 pixels @@ -863,7 +865,9 @@ The following statements are available: Every other character will be interpreted as one. - For the Sega Master System, the colors are specified by using 1 to 9, + For the Sega Master System, the sprites are composed by 8x16 pixels. If you + use a 16x16 bitmap, it is automatically divided into 2 sprites of 8x16 pixels. + The colors for each pixel are specified by using hexadecimal digits 1 to 9, and A to F. From 9efd263190cbb30ce3b032f6c1ece91e7d8c7fd7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 26 Apr 2025 23:15:12 -0600 Subject: [PATCH 024/155] Ported Space Attack to SMS --- examples/space_attack_sms.bas | 270 ++++++++++++++-------------------- 1 file changed, 108 insertions(+), 162 deletions(-) diff --git a/examples/space_attack_sms.bas b/examples/space_attack_sms.bas index b4a89ce..3bb1d8a 100644 --- a/examples/space_attack_sms.bas +++ b/examples/space_attack_sms.bas @@ -6,9 +6,12 @@ ' ' Creation date: Feb/29/2024. ' Revision date: Nov/13/2024. Added pixel stars background and double-speed enemies. + ' Revision date: Apr/26/2025. Adapted for Sega Master System. ' - DEFINE SPRITE 0,4,sprites_bitmaps + DEFINE SPRITE 0,8,sprites_bitmaps + + DEFINE CHAR 16,8,pixel_bitmaps DIM enemy_x(8) DIM enemy_y(8) @@ -16,7 +19,8 @@ restart_game: CLS - MODE 2 ' In this mode, char definitions are faster + MODE 4 ' In this mode, char definitions are faster + BORDER ,4 ' Avoid scrolling in the columns 24-31 #score = 0 @@ -32,11 +36,10 @@ restart_game: ' We make a vertical strip using 8 characters (numbers 16 to 23) ' and we repeat it continuously (24 rows / 8 characters = 3 repetitions) ' - FOR d = 0 TO 31 ' For each column - e = e + RANDOM(4) + 2 ' Displace the strip offset for this column. - FOR #c = 0 TO 736 STEP 32 - e = ((e + 1) AND 7) OR 16 ' Limit to range 16 to 23. - VPOKE $1800 + #c + d, e ' Put strip character. + FOR d = 0 TO 46 STEP 2 ' For each column + FOR #c = 0 TO 1728 STEP 64 + e = RANDOM(8) + 16 + VPOKE $3800 + #c + d, e ' Put strip character. NEXT #c NEXT d @@ -45,12 +48,12 @@ restart_game: game_loop: WAIT - ' Displace stars pixel by pixel ' - ' This is almost magic because these characters are used in the whole screen, - ' so this redefinition of characters updates the whole screen. + ' Displace stars pixel by pixel ' - DEFINE CHAR 16,8,VARPTR pixel_bitmaps(((FRAME / 2) AND 63) XOR 63) + scroll_y = scroll_y - 1 + IF scroll_y = $ff THEN scroll_y = $df + SCROLL 0, scroll_y ' Background "music" (two tones alternating each 16 video frames) #c = 960 @@ -59,14 +62,17 @@ game_loop: SOUND 0, #c, 15 - d ' Setup player sprite - SPRITE 0,player_y-1,player_x,0,10 + SPRITE 0,player_y-1,player_x,0 + SPRITE 1,player_y-1,player_x+8,2 ' Setup bullet sprite IF bullet_y = 0 THEN ' Active? - SPRITE 1,$d1,0,0,0 ' No, remove sprite. + SPRITE 2,$e0,0,0 ' No, remove sprites. + SPRITE 3,$e0,0,0 SOUND 1,,0 ' Disable sound. ELSE - SPRITE 1,bullet_y-1,bullet_x,8,7 ' Setup sprite. + SPRITE 2,bullet_y-1,bullet_x,8 ' Setup sprites. + SPRITE 3,bullet_y-1,bullet_x+8,10 ' bullet_y = bullet_y - 4 ' Displace bullet. SOUND 1,bullet_y+16,11 ' Make sound. END IF @@ -76,13 +82,15 @@ game_loop: ' FOR c = 0 TO 7 IF enemy_s(c) = 0 THEN ' No enemy - SPRITE c + 2, $d1, 0, 0, 0 + SPRITE 4 + c * 2, $e0, 0, 0 + SPRITE 5 + c * 2, $e0, 0, 0 ' Create one - enemy_x(c) = RANDOM(240) + enemy_x(c) = RANDOM(168) + 4 enemy_y(c) = $c0 + c * 4 enemy_s(c) = RANDOM(2) + 1 ELSEIF enemy_s(c) < 3 THEN ' Enemy moving. - SPRITE c + 2, enemy_y(c) - 1, enemy_x(c), 4, 2 + SPRITE 4 + c * 2, enemy_y(c) - 1, enemy_x(c), 4 + SPRITE 5 + c * 2, enemy_y(c) - 1, enemy_x(c) + 8, 6 ' Slowly drift towards the player. IF (FRAME AND 3) = 0 THEN @@ -99,7 +107,7 @@ game_loop: enemy_y(c) = enemy_y(c) + 3 END IF IF enemy_y(c) >= $c0 AND enemy_y(c) <= $c7 THEN ' Reached bottom. - enemy_x(c) = RANDOM(240) + enemy_x(c) = RANDOM(168) + 4 enemy_y(c) = $f2 ' Reset enemy. enemy_s(c) = RANDOM(2) + 1 END IF @@ -130,8 +138,13 @@ game_loop: END IF ELSE ' Enemy explosion. - IF FRAME AND 4 THEN d = 10 ELSE d = 6 - SPRITE c + 2, enemy_y(c) - 1, enemy_x(c), 12, d + IF FRAME AND 4 THEN + SPRITE 4 + c * 2, $e0, 0, 0 + SPRITE 5 + c * 2, $e0, 0, 0 + ELSE + SPRITE 4 + c * 2, enemy_y(c) - 1, enemy_x(c), 12 + SPRITE 5 + c * 2, enemy_y(c) - 1, enemy_x(c) + 8, 14 + END IF ' Displace explosion slowly. IF FRAME AND 1 THEN @@ -143,7 +156,7 @@ game_loop: enemy_s(c) = enemy_s(c) + 1 IF enemy_s(c) = 80 THEN ' Time reached. SOUND 3,,0 - enemy_x(c) = RANDOM(240) + enemy_x(c) = RANDOM(168) + 4 enemy_y(c) = $f2 enemy_s(c) = 1 ' Bring back enemy. END IF @@ -154,7 +167,7 @@ game_loop: ' Movement of the player. ' IF cont1.left THEN IF player_x > 0 THEN player_x = player_x - 2 - IF cont1.right THEN IF player_x < 240 THEN player_x = player_x + 2 + IF cont1.right THEN IF player_x < 176 THEN player_x = player_x + 2 IF cont1.button THEN ' Fire! IF bullet_y = 0 THEN ' Only if no bullet active. bullet_y = player_y - 8 @@ -167,7 +180,8 @@ game_loop: ' Player dies. ' player_dies: - PRINT AT 11,"GAME OVER" + PRINT AT 250,"GAME" + PRINT AT 282,"OVER" ' ' Explosion effect and sound. @@ -178,15 +192,18 @@ player_dies: FOR c = 0 TO 120 WAIT SOUND 3,$E4 + (c AND 3),13 - SPRITE 0, player_y - 1 + RANDOM(5) - 2, player_x + RANDOM(5) - 2, 12, RANDOM(14) + 2 + e = player_y - 1 + RANDOM(5) - 2 + d = player_x + RANDOM(5) - 2 + SPRITE 0, e, d, 12 + SPRITE 1, e, d + 8, 14 NEXT c SOUND 3,,0 ' ' Remove enemies. ' - FOR c = 1 TO 9 - SPRITE c, $d1, 0, 0, 0 + FOR c = 2 TO 19 + SPRITE c, $e0, 0, 0 NEXT c ' @@ -203,32 +220,15 @@ player_dies: ' Update the score on the screen. ' update_score: PROCEDURE - PRINT AT 2,#score,"0" + PRINT AT 57,"SCORE:" + PRINT AT 89,#score,"0" END ' ' Pixel scrolling stars ' pixel_bitmaps: - BITMAP "....X..." - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" + BITMAP ".5......" BITMAP "........" BITMAP "........" BITMAP "........" @@ -239,7 +239,7 @@ pixel_bitmaps: BITMAP "........" BITMAP "........" - BITMAP "........" + BITMAP ".....5.." BITMAP "........" BITMAP "........" BITMAP "........" @@ -251,7 +251,7 @@ pixel_bitmaps: BITMAP "........" BITMAP "........" BITMAP "........" - BITMAP "........" + BITMAP "...5...." BITMAP "........" BITMAP "........" @@ -260,12 +260,12 @@ pixel_bitmaps: BITMAP "........" BITMAP "........" BITMAP "........" - BITMAP "........" + BITMAP ".5......" BITMAP "........" BITMAP "........" BITMAP "........" - BITMAP "........" + BITMAP "......5." BITMAP "........" BITMAP "........" BITMAP "........" @@ -279,12 +279,12 @@ pixel_bitmaps: BITMAP "........" BITMAP "........" BITMAP "........" - BITMAP "........" + BITMAP "......5." BITMAP "........" - BITMAP "....X..." BITMAP "........" BITMAP "........" + BITMAP "....5..." BITMAP "........" BITMAP "........" BITMAP "........" @@ -294,61 +294,7 @@ pixel_bitmaps: BITMAP "........" BITMAP "........" BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" - - BITMAP "........" - BITMAP "........" - BITMAP "........" - BITMAP "........" + BITMAP ".5......" BITMAP "........" BITMAP "........" BITMAP "........" @@ -358,70 +304,70 @@ pixel_bitmaps: ' Bitmaps for the game. ' sprites_bitmaps: - BITMAP ".......XX......." - BITMAP ".......XX......." - BITMAP "......XXXX......" - BITMAP "......XXXX......" - BITMAP "......XXXX......" - BITMAP ".....XXXXXX....." - BITMAP ".....XXXXXX....." - BITMAP ".....XX..XX....." - BITMAP ".....X....X....." - BITMAP "..XX.XXXXXX.XX.." - BITMAP ".XXX.XXXXXX.XXX." - BITMAP ".XXXXX....XXXXX." - BITMAP "XX..XXXXX.XX..XX" - BITMAP "XXX.XXXXXXXXX.XX" - BITMAP "XXXX.XXXXXX.XXXX" - BITMAP ".XX..XX..XX..XX." - - BITMAP "....XXXXXXXX...." - BITMAP "...X........X..." - BITMAP "..X.XX....XX.X.." - BITMAP ".X...XXXXXX...X." - BITMAP ".X...X.XX.X...X." - BITMAP ".X...XXXXXX...X." - BITMAP ".X....XXXX....X." - BITMAP ".X..XX....XX..X." - BITMAP ".XXXX.XXXX.XXXX." - BITMAP "XXX..X....X..XXX" - BITMAP "..XXXXXXXXXXXX.." - BITMAP "XXX....XX....XXX" - BITMAP "X.XXXX.XX.XXXX.X" - BITMAP "X..XX.XXXX.XX..X" - BITMAP "XXX..XX..XX..XXX" - BITMAP "..XXXX....XXXX.." + BITMAP ".......FF......." + BITMAP ".......FF......." + BITMAP "......FFFF......" + BITMAP "......FFFF......" + BITMAP "......FFFF......" + BITMAP ".....FFFFFF....." + BITMAP ".....FFFFFF....." + BITMAP ".....FF55FF....." + BITMAP ".....F5555F....." + BITMAP "..FF4FFFFFF4FF.." + BITMAP ".FFF4FFFFFF4FFF." + BITMAP ".FFFFF4444FFFFF." + BITMAP "FF44FFFFF4FF44FF" + BITMAP "FFF4FFFFFFFFF4FF" + BITMAP "FFFF.FFFFFF.FFFF" + BITMAP ".66..66..66..66." + + BITMAP "....33333333...." + BITMAP "...3........3..." + BITMAP "..3.FF....FF.3.." + BITMAP ".3...FFFFFF...3." + BITMAP ".3...FDFFDF...3." + BITMAP ".3...FFFFFF...3." + BITMAP ".3....FFFF ...3." + BITMAP ".3..DD.FF.DD..3." + BITMAP ".3DDD.DDDD.DDD3." + BITMAP "366..D5555D..663" + BITMAP "..333333333333.." + BITMAP "333CCCC33CCCC333" + BITMAP "3C3333C33C3333C3" + BITMAP "3CC33C3333C33CC3" + BITMAP "333CC33..33CC333" + BITMAP "..3333....3333.." BITMAP "................" BITMAP "................" BITMAP "................" BITMAP "................" - BITMAP ".......XX......." - BITMAP "......XXXX......" - BITMAP "......XXXX......" - BITMAP "......XXXX......" - BITMAP "......XXXX......" - BITMAP "....XXXXXXXX...." - BITMAP "...XXXXXXXXXX..." - BITMAP "......XXXX......" - BITMAP ".....XX...XX...." + BITMAP ".......F5......." + BITMAP "......F775......" + BITMAP "......F775......" + BITMAP "......F775......" + BITMAP "......F775......" + BITMAP "....FFF77775...." + BITMAP "...7777777775..." + BITMAP "......7555......" + BITMAP ".....75...75...." BITMAP "................" BITMAP "................" BITMAP "................" BITMAP "................" BITMAP "................" - BITMAP ".......X........" - BITMAP ".......XX......." - BITMAP "X......XXX......" - BITMAP "XXX.....XXX...XX" - BITMAP "XXXXX..XXXX..XXX" - BITMAP "...XXXXXXXXXXX.." - BITMAP ".....XXXXXX.X..." - BITMAP "......X..X.X...." - BITMAP ".....XXXXXXXX..." - BITMAP "....XXX.XXXXXX.." - BITMAP "...XXX.....XXXX." - BITMAP "...XX........XXX" - BITMAP "..XX............" + BITMAP ".......6........" + BITMAP ".......6A......." + BITMAP "6......66A......" + BITMAP "666.....666...66" + BITMAP "6666A..66A6..6A6" + BITMAP "...66A66AA666A.." + BITMAP ".....66AAAAA6..." + BITMAP "......6AAAA6...." + BITMAP ".....666AAA66..." + BITMAP "....666.66AA66.." + BITMAP "...6A6.....6666." + BITMAP "...6A........666" + BITMAP "..66............" BITMAP "................" From a7a1b9c468dd9579fb11d5a9d4901ea312a82261 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 27 Apr 2025 00:19:38 -0600 Subject: [PATCH 025/155] Ported Viboritas to SMS --- cvbasic_prologue.asm | 4 +- examples/viboritas_sms.bas | 672 +++++++++++++++++++++++++++++++++++++ 2 files changed, 674 insertions(+), 2 deletions(-) create mode 100644 examples/viboritas_sms.bas diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 0c51546..bc8db3c 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1231,8 +1231,8 @@ mode_4: ; TMS9118-alike palette .3: - db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f - db $00,$00,$08,$1d,$10,$30,$02,$3c,$03,$17,$0f,$1f,$04,$33,$2a,$3f + db $00,$00,$08,$1d,$20,$30,$02,$3c,$17,$2B,$0f,$1f,$04,$33,$2a,$3f + db $00,$00,$08,$1d,$20,$30,$02,$3c,$17,$2B,$0f,$1f,$04,$33,$2a,$3f else vdp_generic_mode: diff --git a/examples/viboritas_sms.bas b/examples/viboritas_sms.bas new file mode 100644 index 0000000..5683ddd --- /dev/null +++ b/examples/viboritas_sms.bas @@ -0,0 +1,672 @@ + ' + ' Viboritas (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Oct/1990. + ' Revision date: Feb/29/2024. Ported to CVBasic. + ' Revision date: Apr/26/2025. Adapted to Sega Master System. + ' + + ' The original game was made in Z80 assembler, + ' you can see it here: https://nanochess.org/viboritas.html + + ' It is easier to understand in CVBasic ;) + + DEFINE CHAR 128,21,game_bitmaps + DEFINE SPRITE 0,20,game_sprites + +restart_game: + lives = 2 + level = 1 +restart_level: + + PRINT AT 684,"Lives: ",lives + PRINT AT 745,"nanochess 1990" + +next_level: + GOSUB draw_level + + x_player = 8 + y_player = 16 + player_frame = 0 + + x_enemy1 = random(128) + 64 + y_enemy1 = 56 + enemy1_frame = 24 + x_enemy2 = random(128) + 80 + y_enemy2 = 96 + enemy2_frame = 32 + x_enemy3 = random(128) + 48 + y_enemy3 = 136 + enemy3_frame = 24 + + enemy_speed = 0 + + GOSUB start_song + +game_loop: + WHILE 1 + WAIT + GOSUB play_song + + SPRITE 0, y_player - 1, x_player, player_frame + SPRITE 1, y_player - 1, x_player + 8, player_frame + 2 + SPRITE 2, y_enemy1 - 1, x_enemy1, enemy1_frame + SPRITE 3, y_enemy1 - 1, x_enemy1 + 8, enemy1_frame + 2 + SPRITE 4, y_enemy2 - 1, x_enemy2, enemy2_frame + SPRITE 5, y_enemy2 - 1, x_enemy2 + 8, enemy2_frame + 2 + SPRITE 6, y_enemy3 - 1, x_enemy3, enemy3_frame + SPRITE 7, y_enemy3 - 1, x_enemy3 + 8, enemy3_frame + 2 + + GOSUB move_player + + c = $50 + level * 4 + enemy_speed = enemy_speed + c + WHILE enemy_speed >= $40 + enemy_speed = enemy_speed - $40 + GOSUB move_enemies + WEND + IF cont1.button THEN + IF x_player > 232 AND x_player < 248 AND y_player = 136 THEN + GOSUB sound_off + + FOR c = 1 to 10 + WAIT + SOUND 0, 200 - c * 10, 13 + NEXT c + + level = level + 1 + IF level = 6 THEN + GOSUB sound_off + PRINT AT 267," YOU WIN! " + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + level = 1 + GOTO restart_level + END IF + GOTO next_level + END IF + END IF + IF ABS(y_player + 1 - y_enemy1) < 8 THEN + IF ABS(x_player + 1 - x_enemy1) < 8 THEN GOTO player_dies + END IF + IF ABS(y_player + 1 - y_enemy2) < 8 THEN + IF ABS(x_player + 1 - x_enemy2) < 8 THEN GOTO player_dies + END IF + IF ABS(y_player + 1 - y_enemy3) < 8 THEN + IF ABS(x_player + 1 - x_enemy3) < 8 THEN GOTO player_dies + END IF + WEND + +player_dies: + GOSUB sound_off + + SOUND 0,640,13 + SOUND 1,320,13 + SOUND 2,160,13 + + player_frame = 0 + FOR c = 0 TO 30 + WAIT + WAIT + player_frame = player_frame XOR 8 + SPRITE 0, y_player - 1, x_player, player_frame + SPRITE 1, y_player - 1, x_player + 8, player_frame + 2 + NEXT c + + GOSUB sound_off + + DO + WAIT + SOUND 0,200 - y_player,13 + player_frame = player_frame XOR 8 + SPRITE 0, y_player - 1, x_player, player_frame + SPRITE 1, y_player - 1, x_player + 8, player_frame + 2 + y_player = y_player + 2 + LOOP WHILE y_player < 160 + + GOSUB sound_off + + IF lives = 0 THEN + PRINT AT 267," GAME OVER " + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + GOTO restart_game + END IF + lives = lives - 1 + GOTO restart_level + + ' + ' Draw the current level. + ' +draw_level: PROCEDURE + + ' Get the base character to draw the level. + base_character = 128 + (level - 1) * 4 + + ' Draw the background. + FOR #c = $3800 TO $3cf8 STEP 8 + VPOKE #c, base_character + VPOKE #c + 2, base_character + VPOKE #c + 4, base_character + VPOKE #c + 6, base_character + 1. + NEXT #c + + ' Draw over the floors. + FOR #c = $3900 TO $3cc0 STEP 320 + FOR #d = #c TO #c + 62 STEP 2 + VPOKE #d, base_character + 2. + NEXT #d + NEXT #c + + ' Draw the ladders. + ladders = 6 - level + + FOR #c = $3900 TO $3B80 STEP 320 + FOR d = 1 TO ladders + e = (RANDOM(28) + 2) * 2 + VPOKE #c + e, base_character + 3. + VPOKE #c + e + 64, base_character + 3. + VPOKE #c + e + 128, base_character + 3. + VPOKE #c + e + 192, base_character + 3. + VPOKE #c + e + 256, base_character + 3. + NEXT d + NEXT #c + + ' Draw the "exit". + VPOKE $3CBC, 148 + + END + + ' + ' Move the player + ' +move_player: PROCEDURE + IF cont1.left THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor + IF x_player > 0 THEN x_player = x_player - 1 + IF FRAME AND 4 THEN player_frame = 8 ELSE player_frame = 12 + END IF + END IF + IF cont1.right THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor + IF x_player < 240 THEN x_player = x_player + 1 + IF FRAME AND 4 THEN player_frame = 0 ELSE player_frame = 4 + END IF + END IF + IF cont1.up THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor. + column = (x_player + 7) /8 + row = (y_player + 8) / 8 + #c = $3800 + row * 64 + column * 2 + IF VPEEK(#c) = base_character + 3 THEN ' Ladder? + y_player = y_player - 1 + END IF + ELSE + IF FRAME AND 4 THEN player_frame = 16 ELSE player_frame = 20 + y_player = y_player - 1 + END IF + END IF + IF cont1.down THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor. + column = (x_player + 7) /8 + row = (y_player + 16) / 8 + #c = $3800 + row * 64 + column * 2 + IF VPEEK(#c) = base_character + 3 THEN ' Ladder? + y_player = y_player + 1 + END IF + ELSE + IF FRAME AND 4 THEN player_frame = 16 ELSE player_frame = 20 + y_player = y_player + 1 + END IF + END IF + END + + ' + ' Move the enemies. + ' +move_enemies: PROCEDURE + IF enemy1_frame < 32 THEN + x_enemy1 = x_enemy1 - 1. + IF x_enemy1 = 0 THEN enemy1_frame = 32 + ELSE + x_enemy1 = x_enemy1 + 1. + IF x_enemy1 = 240 THEN enemy1_frame = 24 + END IF + enemy1_frame = (enemy1_frame AND $f8) + (FRAME AND 4) + + IF enemy2_frame < 32 THEN + x_enemy2 = x_enemy2 - 1. + IF x_enemy2 = 0 THEN enemy2_frame = 32 + ELSE + x_enemy2 = x_enemy2 + 1. + IF x_enemy2 = 240 THEN enemy2_frame = 24 + END IF + enemy2_frame = (enemy2_frame AND $f8) + (FRAME AND 4) + + IF enemy3_frame < 32 THEN + x_enemy3 = x_enemy3 - 1. + IF x_enemy3 = 0 THEN enemy3_frame = 32 + ELSE + x_enemy3 = x_enemy3 + 1. + IF x_enemy3 = 240 THEN enemy3_frame = 24 + END IF + enemy3_frame = (enemy3_frame AND $f8) + (FRAME AND 4) + END + +game_bitmaps: + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + BITMAP "CCCCCCCC" + + BITMAP "222..222" + BITMAP "222..222" + BITMAP "222..222" + BITMAP "222..222" + BITMAP "222..222" + BITMAP "222..222" + BITMAP "222..222" + BITMAP "222..222" + + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + BITMAP "........" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + BITMAP "........" + BITMAP "AAAAAAAA" + BITMAP "AAAAAAAA" + + BITMAP ".5....5." + BITMAP ".5....5." + BITMAP ".555555." + BITMAP ".5....5." + BITMAP ".5....5." + BITMAP ".555555." + BITMAP ".5....5." + BITMAP ".5....5." + + BITMAP "55555554" + BITMAP "54444454" + BITMAP "54555454" + BITMAP "54545454" + BITMAP "54555454" + BITMAP "54444454" + BITMAP "55555554" + BITMAP "44444444" + + BITMAP "5.555.5." + BITMAP "5.555.5." + BITMAP "5.555.5." + BITMAP "5.555.5." + BITMAP "5.555.5." + BITMAP "5.555.5." + BITMAP "5.555.5." + BITMAP "5.555.5." + + BITMAP "FFF.FFF." + BITMAP "........" + BITMAP "EEEEEEEE" + BITMAP "EEEEEEEE" + BITMAP "EEEEEEEE" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".5....5." + BITMAP ".5....5." + BITMAP ".555555." + BITMAP ".5....5." + BITMAP ".5....5." + BITMAP ".555555." + BITMAP ".5....5." + BITMAP ".5....5." + + BITMAP "66686666" + BITMAP "66686666" + BITMAP "66686666" + BITMAP "88888888" + BITMAP "66666668" + BITMAP "66666668" + BITMAP "66666668" + BITMAP "88888888" + + BITMAP ".888888." + BITMAP ".888888." + BITMAP ".888888." + BITMAP "........" + BITMAP ".88.888." + BITMAP ".88.888." + BITMAP ".88.888." + BITMAP "........" + + BITMAP "........" + BITMAP "55555555" + BITMAP "55555555" + BITMAP "5.5.5.5." + BITMAP ".5...5.." + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".5....5." + BITMAP ".5....5." + BITMAP ".555555." + BITMAP ".5....5." + BITMAP ".5....5." + BITMAP ".555555." + BITMAP ".5....5." + BITMAP ".5....5." + + BITMAP "666.666." + BITMAP "666.666." + BITMAP "666.666." + BITMAP "........" + BITMAP "666.666." + BITMAP "666.666." + BITMAP "666.666." + BITMAP "........" + + BITMAP ".A......" + BITMAP "..AA...." + BITMAP "....AA.." + BITMAP "......AA" + BITMAP "....AA.." + BITMAP "..AA...." + BITMAP ".A......" + BITMAP ".A......" + + BITMAP "........" + BITMAP "FFFFFFFF" + BITMAP "........" + BITMAP "5.5.5.5." + BITMAP ".5.5.5.5" + BITMAP "........" + BITMAP "FFFFFFFF" + BITMAP "........" + + BITMAP "E......E" + BITMAP "E......E" + BITMAP "EE....EE" + BITMAP "E.EEEE.E" + BITMAP "E......E" + BITMAP "E......E" + BITMAP "EE....EE" + BITMAP "E.EEEE.E" + + BITMAP "86666668" + BITMAP "68688666" + BITMAP "66886888" + BITMAP "68666888" + BITMAP "66888668" + BITMAP "66866888" + BITMAP "68668668" + BITMAP "66866888" + + BITMAP "C2CCC222" + BITMAP "C2CC2CC2" + BITMAP "CC2CC222" + BITMAP "C2CCCCCC" + BITMAP "CC2C2CCC" + BITMAP "CCC2C2C2" + BITMAP "CCC2CC2C" + BITMAP "CC2CC222" + + BITMAP "........" + BITMAP "6666666E" + BITMAP "6666666E" + BITMAP "EEEEEEEE" + BITMAP "666E6666" + BITMAP "666E6666" + BITMAP "EEEEEEEE" + BITMAP "........" + + BITMAP "....CC.." + BITMAP "....CC.." + BITMAP "...CC..." + BITMAP "...CC..." + BITMAP "..CC...." + BITMAP "..CC...." + BITMAP "...CC..." + BITMAP "...CC..." + + BITMAP ".F.F.F.." + BITMAP "FFFFFFF." + BITMAP ".F.F.F.." + BITMAP "FFFFFFF." + BITMAP ".F.F.F.." + BITMAP "FFFFFFF." + BITMAP ".F.F.F.." + BITMAP "........" + +game_sprites: + BITMAP ".......1.1.1...." + BITMAP ".....11A1A1A1..." + BITMAP "....1A1999991..." + BITMAP ".....1A999991..." + BITMAP "....1A9999191..." + BITMAP ".....1A969991..." + BITMAP "....1FF966691..." + BITMAP "..1FFFF19991...." + BITMAP ".1FF1FFF11111..." + BITMAP "1FF11FFFF1FFF1.." + BITMAP "1FFF1FFFF1FFF1.." + BITMAP "1FFF1F1111111..." + BITMAP ".11111FFFF111..." + BITMAP "...1FFF1FF7771.." + BITMAP "...177711F77771." + BITMAP "...17777111111.." + + BITMAP "......11A1A1A1.." + BITMAP ".....1A1999991.." + BITMAP "......1A999991.." + BITMAP ".....1A9999191.." + BITMAP "......19969991.." + BITMAP ".....1FF966691.." + BITMAP ".....1FF19991..." + BITMAP "....1FFFF111...." + BITMAP "....1FFFFF1....." + BITMAP "....1FF1FFF1...." + BITMAP "....1FF1FFF1...." + BITMAP "....1FFF111....." + BITMAP ".....1FFFF1....." + BITMAP ".....1FF1......." + BITMAP ".....177771....." + BITMAP ".....1777771...." + + BITMAP "....1.1.1......." + BITMAP "...1A1A1A11....." + BITMAP "...1999991A1...." + BITMAP "...199999A1....." + BITMAP "...1919999A1...." + BITMAP "...199969A1....." + BITMAP "...1966699F1...." + BITMAP "....19991FFFF1.." + BITMAP ".....111FFF1FF1." + BITMAP "..1FFF1FFFF11FF1" + BITMAP "..1FFF1FFFF1FFF1" + BITMAP "...111.111F1FFF1" + BITMAP "...111FFFF11111." + BITMAP "..1777FF1FFF1..." + BITMAP ".17777F117771..." + BITMAP "..11111177771..." + + BITMAP "..1A1A1A11......" + BITMAP "..1999991A1....." + BITMAP "..199999A1......" + BITMAP "..1919999A1....." + BITMAP "..199969A1......" + BITMAP "..1966699A1....." + BITMAP "...19991FF1....." + BITMAP "....111FFFF1...." + BITMAP ".....1FFFFF1...." + BITMAP "....1FFF1FF1...." + BITMAP "....1FFF1FF1...." + BITMAP ".....111FFF1...." + BITMAP ".....1FFFF1....." + BITMAP "......11FF1....." + BITMAP ".....177771....." + BITMAP "....1777771....." + + BITMAP "...1A1A1A1A1...." + BITMAP "....1AAAAA1....." + BITMAP "...1AAAAAAA1...." + BITMAP "...1AAAAAAA1111." + BITMAP "....1AAAAA11FFF1" + BITMAP "....1AAAAA11FFF1" + BITMAP ".....199911FF11." + BITMAP "...1FF111FFF1..." + BITMAP ".11FF1FFFF11...." + BITMAP "1FFF1.1111......" + BITMAP "1FFF11FFFF1....." + BITMAP ".111.1F11FF11..." + BITMAP "....1FF1.17771.." + BITMAP "...11FF1.177771." + BITMAP "..177771..1111.." + BITMAP ".1777771........" + + BITMAP "....1A1A1A1A1..." + BITMAP ".....1AAAAA1...." + BITMAP "....1AAAAAAA1..." + BITMAP ".1111AAAAAAA1..." + BITMAP "1FFF11AAAAA1...." + BITMAP "1FFF11AAAAA1...." + BITMAP ".11FF1199911...." + BITMAP "...1FFF111FF1..." + BITMAP "....11FFFF1FF11." + BITMAP "......1111.1FFF1" + BITMAP ".....1FFFF11FFF1" + BITMAP "...11FF11F1.111." + BITMAP "..17771.1FF1...." + BITMAP ".17771..1FF11..." + BITMAP "..111...177771.." + BITMAP "........1777771." + + BITMAP "..1331321......." + BITMAP ".13F33F21......." + BITMAP ".13F33F21......." + BITMAP ".1331321........" + BITMAP ".11333321......." + BITMAP "1633331321......" + BITMAP "6113313321....1." + BITMAP "...1113321...131" + BITMAP "...133321....131" + BITMAP "..1333321...1321" + BITMAP ".1333321....1321" + BITMAP ".133321.11.13321" + BITMAP ".13332113311321." + BITMAP ".13333333331321." + BITMAP "..1333333333321." + BITMAP "...12222112221.." + + BITMAP "....11.11......." + BITMAP "...1331321......" + BITMAP "..13F33F21......" + BITMAP "..13F33F21......" + BITMAP "..1331321......." + BITMAP "...1333321......" + BITMAP ".1133331321....." + BITMAP "16133313321....." + BITMAP "16611113321..1.." + BITMAP ".111333321..131." + BITMAP "..13333211.1321." + BITMAP "..13332132.1321." + BITMAP "..133321321321.." + BITMAP "..133333333321.." + BITMAP "...13333313321.." + BITMAP "....122211221..." + + BITMAP ".......1231331.." + BITMAP ".......12F33F31." + BITMAP ".......12F33F31." + BITMAP "........1231331." + BITMAP ".......12333311." + BITMAP "......1231333361" + BITMAP ".1....1233133116" + BITMAP "131...1233111..." + BITMAP "131....123331..." + BITMAP "1231...1233331.." + BITMAP "1231....1233331." + BITMAP "12331.11.123331." + BITMAP ".12311331123331." + BITMAP ".12313333333331." + BITMAP ".1233333333331.." + BITMAP "..12221122221..." + + BITMAP ".......11.11...." + BITMAP "......1231331..." + BITMAP "......12F33F31.." + BITMAP "......12F33F31.." + BITMAP ".......1231331.." + BITMAP "......1233331..." + BITMAP ".....123133331.." + BITMAP ".....12331333161" + BITMAP "..1..12331111661" + BITMAP ".131..1233331..." + BITMAP ".1231.11233331.." + BITMAP ".1231133123331.." + BITMAP "..123133123331.." + BITMAP "..123333333331.." + BITMAP "..12331333331..." + BITMAP "...122112221...." + +start_song: PROCEDURE + tick_note = 8 + song_note = 47 + END + +play_song: PROCEDURE + tick_note = tick_note + 1. + IF tick_note = 16. THEN + tick_note = 0. + song_note = song_note + 1. + IF song_note = 48. THEN song_note = 0. + note = song_notes(song_note) + SOUND 0, #note_freq(note - 1) + END IF + SOUND 0, , volume_effect(tick_note) + END + +sound_off: PROCEDURE + SOUND 0,,0 + SOUND 1,,0 + SOUND 2,,0 + SOUND 3,,0 + END + +volume_effect: + DATA BYTE 11,12,13,12,12,11,11,10 + DATA BYTE 10,9,9,10,10,9,9,8 + +song_notes: + DATA BYTE 1,2,3,4,5,4,3,2 + DATA BYTE 1,2,3,4,5,4,3,2 + DATA BYTE 6,4,7,8,9,8,7,4 + DATA BYTE 6,4,7,8,9,8,7,4 + DATA BYTE 3,12,8,10,11,10,8,12 + DATA BYTE 6,4,7,8,9,8,7,4 + +#note_freq: + DATA $01AC + DATA $0153 + DATA $011D + DATA $00FE + DATA $00F0 + DATA $0140 + DATA $00D6 + DATA $00BE + DATA $00B4 + DATA $00AA + DATA $00A0 + DATA $00E2 From 6e22310ebabca8bc171d3ec1d216b75026afcfb7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 27 Apr 2025 00:34:57 -0600 Subject: [PATCH 026/155] More examples ported to SMS --- examples/test1.bas | 5 +-- examples/test2.bas | 2 +- examples/test3_sms.bas | 73 +++++++++++++++++++++++++++++++++++++++ examples/varptr_sms.bas | 70 +++++++++++++++++++++++++++++++++++++ examples/vgm.bas | 2 +- examples/vramcopy_sms.bas | 47 +++++++++++++++++++++++++ 6 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 examples/test3_sms.bas create mode 100644 examples/varptr_sms.bas create mode 100644 examples/vramcopy_sms.bas diff --git a/examples/test1.bas b/examples/test1.bas index 1da0cdc..b00bd28 100644 --- a/examples/test1.bas +++ b/examples/test1.bas @@ -5,6 +5,7 @@ ' https://nanochess.org/ ' ' Creation date: Feb/29/2024. + ' Revision date: Apr/27/2025. Uses new CHR$ syntax. ' DIM #stars(24) @@ -20,10 +21,10 @@ WAIT FOR c = 0 TO 23 - VPOKE $1800 + #stars(c), 32 + PRINT AT #stars(c), CHR$(32) #stars(c) = #stars(c) + 32 IF #stars(c) >= 768 THEN #stars(c) = #stars(c) - 736 - VPOKE $1800 + #stars(c), 42 + PRINT AT #stars(c), CHR$(42) NEXT c WEND diff --git a/examples/test2.bas b/examples/test2.bas index ac8ad31..7e167cd 100644 --- a/examples/test2.bas +++ b/examples/test2.bas @@ -105,7 +105,7 @@ READ BYTE c IF c = 0 THEN EXIT DO - VPOKE #pointer, c + PRINT AT #pointer, CHR$(c) #pointer = #pointer + 1 LOOP WHILE 1 diff --git a/examples/test3_sms.bas b/examples/test3_sms.bas new file mode 100644 index 0000000..bb801f6 --- /dev/null +++ b/examples/test3_sms.bas @@ -0,0 +1,73 @@ + ' + ' Test 3 + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Nov/12/2024. + ' Revision date: Apr/27/2025. Adapted for Sega Master System. + ' + + DEFINE SPRITE 0, 2, sprite_bitmap + + sprite_x = 148 + sprite_y = 116 + + #state = 0 + d = 1 + + WHILE 1 + + SPRITE 0, sprite_y - 1, sprite_x, 0 + SPRITE 1, sprite_y - 1, sprite_x + 8, 2 + + WAIT + WAIT + + d = d - 1 + IF d = 0 THEN + d = 40 + #state = #state + 1 + IF #state = 10 THEN #state = 1 + END IF + + SELECT CASE #state + CASE 1 + PALETTE 10 + 16, $0F + sprite_x = sprite_x - 2 + CASE 2 + sprite_y = sprite_y - 2 + CASE 3 + sprite_x = sprite_x + 2 + CASE 4 + sprite_y = sprite_y + 2 + CASE 5 TO 6 + sprite_x = sprite_x - 1 + sprite_y = sprite_y - 1 + CASE 7 TO 8 + sprite_x = sprite_x + 1 + sprite_y = sprite_y + 1 + CASE ELSE + PALETTE 10 + 16, RANDOM(63) + 1 + END SELECT + + WEND + + +sprite_bitmap: + BITMAP "......AAAA......" + BITMAP "......AAAA......" + BITMAP "......AAAA......" + BITMAP "......AAAA......" + BITMAP ".......AA......." + BITMAP "..A....AA......." + BITMAP ".AAAAAAAAAAA...." + BITMAP ".AAAAAAAAAAAA..." + BITMAP ".......AA...AA.." + BITMAP ".......AA....AA." + BITMAP "......AAAA....AA" + BITMAP ".....AA..AA....." + BITMAP ".....AA..AA....." + BITMAP ".....AA..AA....." + BITMAP ".....AA..AA....." + BITMAP "....AAA..AAA...." diff --git a/examples/varptr_sms.bas b/examples/varptr_sms.bas new file mode 100644 index 0000000..f83f415 --- /dev/null +++ b/examples/varptr_sms.bas @@ -0,0 +1,70 @@ + ' + ' Using VARPTR to redefine graphics for levels + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Aug/26/2024. + ' Revision date: Sep/27/2025. Adapted to Sega Master System. + ' + + level = 1 + + WHILE 1 + + CLS + + DEFINE CHAR 128,2,VARPTR level_bitmaps((level - 1) * 64) ' Each character is 32 bytes. 2*32 = 64 + + FOR c = 1 TO 10 + PRINT AT RANDOM(768),"\128" + NEXT c + FOR c = 1 TO 10 + PRINT AT RANDOM(768),"\129" + NEXT c + + FOR c = 1 TO 120: WAIT: NEXT + + level = level + 1 + + IF level = 3 THEN level = 1 + + WEND + +level_bitmaps: + BITMAP "..aaaa.." + BITMAP ".a....a." + BITMAP "a.a..a.a" + BITMAP "a......a" + BITMAP "a.a..a.a" + BITMAP "a..aa..a" + BITMAP ".a....a." + BITMAP "..aaaa.." + + BITMAP ".....3.." + BITMAP "....3333" + BITMAP "33..3.33" + BITMAP ".3333333" + BITMAP "..3333.." + BITMAP ".33333.." + BITMAP ".33..33." + BITMAP ".33..33." + + BITMAP "..9999.." + BITMAP ".9....9." + BITMAP "9......9" + BITMAP "9.9..9.9" + BITMAP "9......9" + BITMAP "9......9" + BITMAP ".9....9." + BITMAP "..9999.." + + BITMAP "..5..5.." + BITMAP ".55..55." + BITMAP ".555555." + BITMAP ".5.55.5." + BITMAP ".55555.5" + BITMAP "..5555.5" + BITMAP ".55.5555" + BITMAP ".55.5555" + diff --git a/examples/vgm.bas b/examples/vgm.bas index 466e8ae..33289f8 100644 --- a/examples/vgm.bas +++ b/examples/vgm.bas @@ -12,7 +12,7 @@ ' ' I/O port where the PSG is located in hardware. ' -' CONST VGM_PSG_PORT = $7F ' For SG-1000 +' CONST VGM_PSG_PORT = $7F ' For SG-1000/SMSs CONST VGM_PSG_PORT = $FF ' For Colecovision ON FRAME GOSUB vgm_play diff --git a/examples/vramcopy_sms.bas b/examples/vramcopy_sms.bas new file mode 100644 index 0000000..5ca61fc --- /dev/null +++ b/examples/vramcopy_sms.bas @@ -0,0 +1,47 @@ + ' + ' Example of DEFINE VRAM READ + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Oct/15/2024. + ' Revision date: Apr/27/2025. Adapted for Sega Master System. + ' + + DIM array(128) + + CLS + MODE 4 + DEFINE CHAR 16,2,wall_bitmaps + + FOR #c = 0 TO 126 STEP 2 + VPOKE $3800 + #c, RANDOM(2) + 16 + NEXT #c + + DEFINE VRAM READ $3800,$0080,VARPTR array(0) + + FOR #c = 128 TO 1408 STEP 128 + DEFINE VRAM $3800 + #c, $0080, VARPTR array(0) + NEXT #c + + WHILE 1: WEND + +wall_bitmaps: + BITMAP "666E6666" + BITMAP "666E6666" + BITMAP "666E6666" + BITMAP "EEEEEEEE" + BITMAP "6666666E" + BITMAP "6666666E" + BITMAP "6666666E" + BITMAP "EEEEEEEE" + + BITMAP "FFFFFFF1" + BITMAP "F55F55FF" + BITMAP "F55F55FF" + BITMAP "F44F44FF" + BITMAP "F44F44FF" + BITMAP "F44F44FF" + BITMAP "FFFFFFFF" + BITMAP "1FFFFFFF" + From 4b27f7da872d90b0b4b8ef4527873a4afc957b16 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 27 Apr 2025 01:10:42 -0600 Subject: [PATCH 027/155] Adapted Demo.bas to Sega Master System --- cvbasic_prologue.asm | 8 +- examples/demo_sms.bas | 411 ++++++++++++++++++++++++++++++++++++++ examples/portrait_sms.bas | 271 +++++++++++++++++++++++++ examples/vgm.bas | 2 +- 4 files changed, 689 insertions(+), 3 deletions(-) create mode 100644 examples/demo_sms.bas create mode 100644 examples/portrait_sms.bas diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index bc8db3c..cc949aa 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -479,7 +479,11 @@ CPYBLK: ld b,0 call LDIRVM pop hl + if SMS + ld bc,$0040 + else ld bc,$0020 + endif add hl,bc ex de,hl pop hl @@ -1231,8 +1235,8 @@ mode_4: ; TMS9118-alike palette .3: - db $00,$00,$08,$1d,$20,$30,$02,$3c,$17,$2B,$0f,$1f,$04,$33,$2a,$3f - db $00,$00,$08,$1d,$20,$30,$02,$3c,$17,$2B,$0f,$1f,$04,$33,$2a,$3f + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f else vdp_generic_mode: diff --git a/examples/demo_sms.bas b/examples/demo_sms.bas new file mode 100644 index 0000000..65c686c --- /dev/null +++ b/examples/demo_sms.bas @@ -0,0 +1,411 @@ + ' + ' Demo of graphics for CVBasic + ' + ' by Oscar Toledo G. + ' + ' Creation date: Mar/08/2024. + ' Revision date: Aug/06/2024. Added endless loop. + ' Revision date: Apr/27/2025. Adapted for Sega Master System. + ' + + DIM x(32),y(32),col(32) + + MODE 4 + + DEFINE SPRITE 0,28,sprite_bitmap + + ' Make a bold font + FOR #c = $0400 TO $0FFF + d = VPEEK(#c) + VPOKE #c, d OR (d + d) + NEXT #c + FOR #c = $0403 TO $0FFF STEP 4 + VPOKE #c, 0 + NEXT #c + + DEFINE CHAR 128,62,portrait_char + + WHILE 1 + + CLS + + SCREEN portrait_pattern,0,260,8,8,8 + + GOSUB small_wait + + RESTORE message_1 + + GOSUB show_message + + GOSUB small_wait + + FOR c = 0 TO 7 + WAIT + WAIT + #c = 260 + c * 32 + SCREEN spaces,0,#c,8,1 + SCREEN portrait_pattern,0,#c+32,8,8,8 + NEXT c + + FOR c = 0 TO 7 + WAIT + WAIT + #c = 516 + c + SCREEN spaces,0,#c,1,8,1 + SCREEN portrait_pattern,0,#c+1,8,8,8 + NEXT c + + RESTORE message_2 + + GOSUB show_message + + GOSUB small_wait + + FOR c = 0 TO 144 + WAIT + SPRITE 0,$A0,c,$00 + SPRITE 1,$A0,c+8,$02 + NEXT c + + RESTORE message_3 + + GOSUB show_message + + GOSUB small_wait + + FOR c = 0 TO 31 + x(c) = RANDOM(176) + y(c) = RANDOM(240) + col(c) = (c % 14) * 4 + SPRITE c * 2,y(c),x(c),col(c) + SPRITE c * 2 + 1,y(c),x(c) + 8,col(c) + 2 + NEXT c + + FOR c = 0 TO 240 + WAIT + FOR d = 0 TO 15 + SPRITE d * 2,y(d),x(d),col(d) + SPRITE d * 2 + 1,y(d),x(d) + 8,col(d) + 2 + y(d) = y(d) + 1 + IF y(d) = $c0 THEN y(d) = $f1 + NEXT d + FOR d = 16 TO 31 + SPRITE d * 2,y(d),x(d),col(d) + SPRITE d * 2 + 1,y(d),x(d) + 8,col(d) + 2 + x(d) = x(d) + 1 + IF x(d) = $ff THEN x(d) = $00 + NEXT d + NEXT c + + FOR c = 0 TO 63 + SPRITE c,$E0,0,0 + NEXT c + + RESTORE message_4 + + GOSUB show_message + + GOSUB small_wait + + WEND + +spaces: + DATA BYTE $20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00 + + INCLUDE "portrait_sms.bas" + +small_wait: PROCEDURE + FOR c = 0 TO 60 + WAIT + NEXT c + END + +show_message: PROCEDURE + + ' + ' Erase area. + ' + FOR #position = $3A1C TO $3BDC STEP 64 + FOR #c = 0 TO $22 STEP 2 + VPOKE #position + #c, 32 + NEXT #c + NEXT #position + + ' + ' Draw message. + ' + #position = $3800 + 270 * 2 + DO + READ BYTE d + IF d = $0D THEN + #position = ((#position + 64) AND $FFC0) + $001C + ELSEIF d <> 0 THEN + VPOKE #position, d + #position = #position + 2 + END IF + WAIT + LOOP WHILE d + + END + +message_1: + DATA BYTE "Hi! This is a",$0d + DATA BYTE "CVBasic demo",$0d + DATA BYTE "program.",$00 + +message_2: + DATA BYTE "You can displace",$0d + DATA BYTE "graphics moving",$0d + DATA BYTE "tiles on the",$0d + DATA BYTE "screen instead of",$0d + DATA BYTE "graphic data.",$00 + +message_3: + DATA BYTE "Sprites can",$0d + DATA BYTE "overlay",$0d + DATA BYTE "background",$0d + DATA BYTE "graphics.",$00 + +message_4: + DATA BYTE "I hope you",$0d + DATA BYTE "enjoyed the",$0d + DATA BYTE "demo.",$00 + +sprite_bitmap: + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + BITMAP "4444444444444444" + + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + BITMAP "5555555555555555" + + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + BITMAP "6666666666666666" + + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + BITMAP "7777777777777777" + + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + BITMAP "8888888888888888" + + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + BITMAP "9999999999999999" + + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + BITMAP "AAAAAAAAAAAAAAAA" + + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + BITMAP "BBBBBBBBBBBBBBBB" + + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + BITMAP "CCCCCCCCCCCCCCCC" + + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + BITMAP "DDDDDDDDDDDDDDDD" + + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + BITMAP "EEEEEEEEEEEEEEEE" + + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" + BITMAP "FFFFFFFFFFFFFFFF" diff --git a/examples/portrait_sms.bas b/examples/portrait_sms.bas new file mode 100644 index 0000000..3039d58 --- /dev/null +++ b/examples/portrait_sms.bas @@ -0,0 +1,271 @@ + ' TMSColor 3.0 Apr/27/2025 + ' Command: ../tmscolor/tmscolor -sms -b -n -t128 portrait.bmp portrait_sms.bas portrait + ' Created: Sun Apr 27 01:02:39 2025 + + ' + ' Recommended code: + ' MODE 4 + ' DEFINE CHAR 128,62,portrait_char + ' SCREEN portrait_pattern,0,0,8,8,8 + ' + ' Start tile = 128. Total_tiles = 62 +portrait_char: + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$f8,$00,$07,$07 + DATA BYTE $c0,$00,$3f,$3f,$00,$00,$ff,$ff + DATA BYTE $01,$01,$fe,$fe,$33,$33,$cc,$cc + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$1f,$00,$e0,$e0 + DATA BYTE $1f,$00,$e0,$e0,$0f,$00,$f0,$f0 + DATA BYTE $0f,$00,$f0,$f0,$07,$00,$f8,$f8 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$fe,$01,$00,$01 + DATA BYTE $fc,$03,$00,$03,$f8,$07,$00,$07 + DATA BYTE $f0,$0f,$00,$0f,$e0,$1f,$00,$1f + DATA BYTE $ff,$3f,$00,$3f,$f0,$7f,$00,$7f + DATA BYTE $00,$ff,$00,$ff,$00,$ff,$00,$ff + DATA BYTE $00,$ff,$00,$ff,$00,$ff,$00,$ff + DATA BYTE $00,$ff,$00,$ff,$00,$ff,$00,$ff + DATA BYTE $ff,$ff,$00,$ff,$1f,$ff,$00,$ff + DATA BYTE $2f,$ff,$00,$ff,$07,$ff,$00,$ff + DATA BYTE $07,$ff,$00,$ff,$01,$ff,$00,$ff + DATA BYTE $00,$ff,$00,$ff,$00,$ff,$00,$ff + DATA BYTE $ff,$00,$00,$00,$ff,$80,$00,$80 + DATA BYTE $ff,$e0,$00,$e0,$ff,$f0,$00,$f0 + DATA BYTE $ff,$f8,$00,$f8,$ff,$fc,$00,$fc + DATA BYTE $ff,$fe,$00,$fe,$fb,$fe,$00,$fe + DATA BYTE $11,$ee,$00,$00,$11,$ee,$00,$00 + DATA BYTE $ff,$00,$00,$00,$11,$00,$ee,$ee + DATA BYTE $11,$00,$ee,$ee,$ff,$00,$00,$00 + DATA BYTE $11,$00,$ee,$ee,$11,$00,$ee,$ee + DATA BYTE $11,$00,$ee,$ee,$11,$00,$ee,$ee + DATA BYTE $ff,$00,$00,$00,$11,$ee,$00,$00 + DATA BYTE $11,$ee,$00,$00,$ff,$00,$00,$00 + DATA BYTE $11,$00,$ee,$ee,$11,$00,$ee,$ee + DATA BYTE $60,$60,$9f,$9f,$00,$00,$ff,$ff + DATA BYTE $00,$00,$ff,$ff,$3f,$3f,$c0,$c0 + DATA BYTE $60,$60,$9f,$9f,$00,$00,$ff,$ff + DATA BYTE $01,$01,$fe,$fe,$37,$37,$c8,$c8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $c0,$3f,$00,$3f,$c0,$3f,$00,$3f + DATA BYTE $e0,$7f,$00,$7f,$fe,$7f,$00,$7f + DATA BYTE $ff,$ff,$00,$ff,$ff,$ff,$00,$ff + DATA BYTE $ff,$ff,$00,$ff,$ff,$ff,$20,$ff + DATA BYTE $00,$ff,$00,$ff,$0e,$ff,$00,$ff + DATA BYTE $0f,$ff,$00,$ff,$7f,$ff,$00,$ff + DATA BYTE $ff,$ff,$00,$ff,$ff,$ff,$00,$ff + DATA BYTE $ff,$ff,$00,$ff,$fe,$ff,$00,$ff + DATA BYTE $00,$ff,$00,$ff,$40,$ff,$00,$ff + DATA BYTE $c0,$ff,$00,$ff,$d0,$ff,$00,$ff + DATA BYTE $f0,$ff,$00,$ff,$f0,$ff,$00,$ff + DATA BYTE $f8,$ff,$00,$ff,$fc,$ff,$00,$ff + DATA BYTE $ff,$fe,$00,$fe,$7d,$ff,$00,$ff + DATA BYTE $7d,$ff,$00,$ff,$1f,$ff,$00,$ff + DATA BYTE $9e,$ff,$00,$ff,$ae,$ff,$00,$ff + DATA BYTE $a7,$ff,$00,$ff,$87,$ff,$00,$ff + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$80,$00,$80 + DATA BYTE $ff,$80,$00,$80,$ff,$80,$00,$80 + DATA BYTE $ff,$80,$00,$80,$ff,$c0,$00,$c0 + DATA BYTE $ff,$00,$00,$00,$11,$ee,$00,$00 + DATA BYTE $11,$ee,$00,$00,$ff,$00,$00,$00 + DATA BYTE $11,$00,$ee,$ee,$11,$00,$ee,$ee + DATA BYTE $ff,$00,$00,$00,$11,$00,$ee,$ee + DATA BYTE $28,$28,$d7,$d7,$00,$00,$ff,$ff + DATA BYTE $00,$00,$ff,$ff,$07,$00,$f8,$f8 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $0f,$00,$f0,$f0,$3f,$00,$c0,$c0 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$ff,$7f,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$fe,$ff + DATA BYTE $ff,$ff,$00,$ff,$ff,$ff,$00,$ff + DATA BYTE $ff,$ff,$00,$ff,$ff,$ff,$00,$ff + DATA BYTE $ff,$ff,$88,$ff,$ff,$ff,$98,$ff + DATA BYTE $ff,$ff,$9c,$ff,$bf,$80,$00,$c0 + DATA BYTE $dc,$ff,$00,$ff,$5c,$ff,$00,$ff + DATA BYTE $5a,$ff,$00,$ff,$fa,$ff,$00,$ff + DATA BYTE $fe,$ff,$00,$ff,$ff,$ff,$00,$ff + DATA BYTE $87,$87,$00,$ff,$07,$07,$00,$ff + DATA BYTE $43,$ff,$00,$ff,$e3,$ff,$00,$ff + DATA BYTE $63,$ff,$00,$ff,$6b,$ff,$00,$ff + DATA BYTE $6b,$ff,$00,$ff,$2b,$ff,$00,$ff + DATA BYTE $2b,$ff,$00,$ff,$2b,$ff,$00,$ff + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $3f,$c0,$00,$c0,$3f,$c0,$00,$c0 + DATA BYTE $11,$00,$ee,$ee,$ff,$00,$00,$00 + DATA BYTE $11,$ee,$00,$00,$11,$ee,$00,$00 + DATA BYTE $ff,$00,$00,$00,$11,$00,$ee,$ee + DATA BYTE $11,$00,$ee,$ee,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$e0,$00,$1f,$1f + DATA BYTE $00,$00,$ff,$ff,$00,$00,$ff,$ff + DATA BYTE $00,$00,$ff,$ff,$0e,$0e,$f1,$f1 + DATA BYTE $70,$70,$8f,$8f,$00,$00,$ff,$ff + DATA BYTE $ff,$00,$00,$00,$0f,$00,$f0,$f0 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $ff,$e0,$80,$e0,$80,$e0,$00,$ff + DATA BYTE $9f,$e0,$00,$ff,$9f,$e0,$00,$ff + DATA BYTE $9f,$e0,$00,$ff,$9f,$e0,$00,$ff + DATA BYTE $8f,$f0,$00,$ff,$cf,$f0,$00,$ff + DATA BYTE $00,$00,$00,$ff,$3f,$00,$00,$ff + DATA BYTE $3f,$00,$00,$ff,$3f,$00,$00,$ff + DATA BYTE $3f,$00,$00,$ff,$0f,$00,$00,$ff + DATA BYTE $0f,$00,$00,$ff,$1f,$00,$00,$ff + DATA BYTE $07,$07,$00,$ff,$87,$07,$00,$ff + DATA BYTE $87,$07,$00,$ff,$c7,$07,$00,$ff + DATA BYTE $c7,$07,$00,$ff,$c7,$07,$00,$ff + DATA BYTE $c7,$07,$00,$ff,$c7,$07,$00,$ff + DATA BYTE $ab,$ff,$00,$ff,$a3,$ff,$00,$ff + DATA BYTE $a3,$ff,$00,$ff,$a3,$ff,$00,$ff + DATA BYTE $a5,$ff,$00,$ff,$ad,$ff,$00,$ff + DATA BYTE $ad,$ff,$00,$ff,$ad,$ff,$00,$ff + DATA BYTE $7f,$c0,$00,$c0,$ff,$c0,$00,$c0 + DATA BYTE $ff,$c0,$00,$c0,$ff,$c0,$00,$c0 + DATA BYTE $ff,$c0,$00,$c0,$ff,$c0,$00,$c0 + DATA BYTE $ff,$c0,$00,$c0,$ff,$c0,$00,$c0 + DATA BYTE $02,$02,$fd,$fd,$7e,$7e,$81,$81 + DATA BYTE $00,$00,$ff,$ff,$00,$00,$ff,$ff + DATA BYTE $3f,$3f,$c0,$c0,$00,$00,$ff,$ff + DATA BYTE $00,$00,$ff,$ff,$00,$00,$ff,$ff + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $07,$00,$f8,$f8,$07,$00,$f8,$f8 + DATA BYTE $1f,$00,$e0,$e0,$7f,$00,$80,$80 + DATA BYTE $c7,$f8,$00,$ff,$c3,$fc,$00,$ff + DATA BYTE $c3,$fc,$00,$ff,$c1,$fe,$00,$ff + DATA BYTE $c0,$ff,$00,$ff,$c0,$ff,$00,$ff + DATA BYTE $c0,$ff,$00,$ff,$c0,$ff,$80,$ff + DATA BYTE $ff,$00,$00,$ff,$ff,$00,$00,$ff + DATA BYTE $07,$f8,$f8,$07,$07,$f8,$f8,$07 + DATA BYTE $8f,$70,$70,$8f,$ff,$00,$00,$fc + DATA BYTE $ff,$80,$00,$fc,$bf,$c0,$00,$fc + DATA BYTE $c7,$07,$00,$ff,$c7,$07,$00,$ff + DATA BYTE $87,$07,$00,$ff,$8f,$07,$00,$f7 + DATA BYTE $9f,$07,$00,$e7,$b7,$07,$01,$4f + DATA BYTE $e7,$07,$01,$1f,$87,$07,$03,$7f + DATA BYTE $af,$ff,$00,$ff,$af,$ff,$00,$ff + DATA BYTE $af,$ff,$00,$ff,$af,$ff,$00,$ff + DATA BYTE $af,$ff,$00,$ff,$af,$ff,$00,$ff + DATA BYTE $af,$ff,$00,$ff,$ef,$ff,$00,$ff + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $ff,$00,$00,$00,$11,$00,$ee,$ee + DATA BYTE $11,$00,$ee,$ee,$ff,$00,$00,$00 + DATA BYTE $11,$00,$ee,$ee,$11,$00,$ee,$ee + DATA BYTE $ff,$00,$00,$00,$11,$ee,$00,$00 + DATA BYTE $03,$00,$fc,$fc,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $c0,$ff,$80,$ff,$c0,$ff,$80,$ff + DATA BYTE $c0,$ff,$80,$ff,$c0,$ff,$80,$ff + DATA BYTE $c0,$ff,$80,$ff,$c0,$ff,$80,$ff + DATA BYTE $c0,$ff,$80,$ff,$c0,$ff,$80,$ff + DATA BYTE $bf,$c0,$00,$ff,$80,$e0,$00,$ff + DATA BYTE $87,$fc,$00,$ff,$87,$fc,$00,$ff + DATA BYTE $87,$fc,$00,$ff,$8b,$f4,$00,$ff + DATA BYTE $ff,$00,$fc,$ff,$ff,$00,$fc,$ff + DATA BYTE $07,$07,$03,$ff,$07,$07,$03,$ff + DATA BYTE $07,$07,$03,$ff,$87,$07,$03,$ff + DATA BYTE $87,$07,$02,$ff,$e7,$07,$02,$ff + DATA BYTE $ff,$07,$02,$ff,$bf,$07,$02,$ff + DATA BYTE $ed,$ff,$00,$ff,$ef,$ff,$00,$ff + DATA BYTE $ef,$ff,$00,$ff,$ed,$ff,$00,$ff + DATA BYTE $cd,$ff,$00,$ff,$cc,$ff,$00,$ff + DATA BYTE $8c,$ff,$00,$ff,$8c,$ff,$00,$ff + DATA BYTE $7f,$c0,$00,$c0,$7f,$c0,$00,$c0 + DATA BYTE $7f,$c0,$00,$c0,$3f,$c0,$00,$c0 + DATA BYTE $3f,$c0,$00,$c0,$1f,$e0,$00,$e0 + DATA BYTE $1f,$e0,$00,$e0,$1f,$e0,$00,$e0 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$01,$01,$01,$ff,$0f,$0f,$0f + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$02,$02,$02,$ff,$0f,$0f,$0f + DATA BYTE $ff,$3f,$3f,$3f,$ff,$7f,$7f,$7f + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $c0,$ff,$80,$ff,$c0,$ff,$80,$ff + DATA BYTE $c0,$ff,$80,$ff,$c1,$fe,$81,$ff + DATA BYTE $e1,$fe,$81,$ff,$e1,$ff,$81,$ff + DATA BYTE $e3,$ff,$83,$ff,$e3,$ff,$83,$ff + DATA BYTE $ff,$00,$fc,$ff,$7e,$80,$7e,$ff + DATA BYTE $7f,$80,$7f,$ff,$ff,$03,$ff,$ff + DATA BYTE $ff,$03,$ff,$ff,$ff,$03,$ff,$ff + DATA BYTE $ff,$03,$ff,$ff,$ff,$02,$ff,$ff + DATA BYTE $bf,$07,$02,$ff,$3f,$07,$00,$ff + DATA BYTE $7f,$07,$00,$ff,$3f,$07,$00,$ff + DATA BYTE $ff,$07,$f8,$ff,$ff,$07,$f8,$ff + DATA BYTE $fb,$07,$f8,$ff,$fb,$07,$f8,$ff + DATA BYTE $8c,$ff,$00,$ff,$8c,$ff,$00,$ff + DATA BYTE $8c,$ff,$00,$ff,$88,$ff,$00,$ff + DATA BYTE $83,$ff,$03,$ff,$87,$ff,$07,$ff + DATA BYTE $0f,$ff,$0f,$ff,$3f,$ff,$3f,$ff + DATA BYTE $1f,$e0,$00,$e0,$3f,$ff,$3f,$ff + DATA BYTE $7f,$ff,$7f,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$e0,$e0,$e0,$ff,$f8,$f8,$f8 + DATA BYTE $ff,$fc,$fc,$fc,$ff,$fe,$fe,$fe + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $7f,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $c3,$ff,$83,$ff,$c3,$ff,$c3,$ff + DATA BYTE $ff,$fe,$ff,$ff,$ff,$fe,$ff,$ff + DATA BYTE $01,$fe,$ff,$ff,$01,$fe,$ff,$ff + DATA BYTE $03,$fc,$ff,$ff,$07,$f8,$ff,$ff + DATA BYTE $ff,$04,$ff,$ff,$ff,$00,$ff,$ff + DATA BYTE $ff,$00,$ff,$ff,$ff,$00,$ff,$ff + DATA BYTE $ff,$00,$ff,$ff,$ff,$00,$ff,$ff + DATA BYTE $ff,$01,$ff,$ff,$ff,$03,$ff,$ff + DATA BYTE $fe,$03,$fc,$ff,$fc,$03,$fc,$ff + DATA BYTE $ff,$0f,$ff,$ff,$ff,$1f,$ff,$ff + DATA BYTE $ff,$7f,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $3f,$ff,$3f,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$fc,$ff,$ff,$ff + DATA BYTE $f0,$ff,$ff,$ff,$c0,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $f3,$ff,$ff,$ff,$c1,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $1f,$ff,$ff,$ff,$1f,$ff,$ff,$ff + DATA BYTE $0f,$ff,$ff,$ff,$0f,$ff,$ff,$ff + + ' Width = 8, height = 8 +portrait_pattern: + DATA BYTE $80,$00,$81,$00,$82,$00,$83,$00,$84,$00,$85,$00,$86,$00,$87,$00 + DATA BYTE $88,$00,$89,$00,$8a,$00,$8b,$00,$8c,$00,$8d,$00,$8e,$00,$8f,$00 + DATA BYTE $90,$00,$91,$00,$92,$00,$93,$00,$94,$00,$95,$00,$96,$00,$97,$00 + DATA BYTE $98,$00,$99,$00,$9a,$00,$9b,$00,$9c,$00,$9d,$00,$9e,$00,$86,$04 + DATA BYTE $9f,$00,$a0,$00,$a1,$00,$a2,$00,$a3,$00,$a4,$00,$a5,$00,$a6,$00 + DATA BYTE $a7,$00,$a8,$00,$a9,$00,$aa,$00,$ab,$00,$ac,$00,$ad,$00,$a6,$04 + DATA BYTE $ae,$00,$af,$00,$b0,$00,$b1,$00,$b2,$00,$b3,$00,$b4,$00,$b5,$00 + DATA BYTE $b6,$00,$b7,$00,$b8,$00,$b9,$00,$ba,$00,$bb,$00,$bc,$00,$bd,$00 diff --git a/examples/vgm.bas b/examples/vgm.bas index 33289f8..7c6aace 100644 --- a/examples/vgm.bas +++ b/examples/vgm.bas @@ -12,7 +12,7 @@ ' ' I/O port where the PSG is located in hardware. ' -' CONST VGM_PSG_PORT = $7F ' For SG-1000/SMSs +' CONST VGM_PSG_PORT = $7F ' For SG-1000/SMS CONST VGM_PSG_PORT = $FF ' For Colecovision ON FRAME GOSUB vgm_play From 392d85c43bbb15fbdd0f9716558490ade0e0a6ba Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 27 Apr 2025 09:05:39 -0600 Subject: [PATCH 028/155] Updated README --- README.md | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b650a30..35314b8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# CVBasic compiler v0.7.1 -*(c) Copyright 2024 Óscar Toledo Gutiérrez* +# CVBasic compiler v0.8.0 +*(c) Copyright 2024-2025 Óscar Toledo Gutiérrez* *https://nanochess.org/* CVBasic is a BASIC language cross-compiler with a syntax alike to QBasic originally written for the Colecovision video game console. @@ -19,9 +19,12 @@ Later it was extended to support the following platforms: * Casio PV2000. * Hanimex/Soundic Pencil II. * NABU PC. +* Sega Master System (supporting bank switching with Sega mapper) One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. +The only difference currently is the Sega Master System, although the compiler shares the core, the sprites are 8x16 and each pixel can have a different color, so the games aren't directly portable, but very easily translated. The examples include SMS versions for every game so you can see what's required to change. + The following files compose the compiler: cvbasic.h The CVBasic compiler global definitions. @@ -51,22 +54,32 @@ The following files compose the compiler: examples/bank.bas Bank-switching example. examples/brinquitos.bas Jumping game. + examples/brinquitos_sms.bas Jumping game (Sega Master System) examples/controller.bas Controller test. examples/demo.bas Demo of graphics. + examples/demo_sms.bas Demo of graphics (Sega Master System) examples/face_joystick.bas Moving face with joystick. + examples/face_joystick_sms.bas Moving face with joystick (Sega Master System) examples/happy_face.bas Bouncing face. + examples/happy_face_sms.bas Bouncing face (Sega Master System). examples/music.bas Music example. examples/oscar_compressed.bas High-resolution graphics example compressed with Pletter. examples/oscar.bas High-resolution graphics example. examples/portrait.bas Data used by demo.bas + examples/portrait_sms.bas Data used by demo_sms.bas examples/space_attack.bas Game example. + examples/space_attack_sms.bas Game example (Sega Master System) examples/test1.bas Moving stars. examples/test2.bas Arithmetic test. examples/test3.bas Shows usage of SELECT CASE / END CASE + examples/test3_sms.bas Shows usage of SELECT CASE / END CASE (Sega Master System) examples/varptr.bas VARPTR example for redefining graphics. + examples/varptr_sms.bas VARPTR example for redefining graphics (Sega Master System) examples/vgm.bas VGM audio player. examples/viboritas.bas Game example. + examples/viboritas_sms.bas Game example (Sega Master System) examples/vramcopy.bas VRAM copy example. + examples/vramcopy_sms.bas VRAM copy example (Sega Master System) ### Usage guide @@ -159,9 +172,16 @@ The .npz file is directlty usable by [MAME NABU port](https://github.com/onthesl I don't have tested the COM files for NABU CP/M yet. +Using CVBasic to compile a Sega Master System program: + + cvbasic --sms game.bas game.asm + gasm80 game.asm -o game.rom -sms + +The -sms option of gasm80 will generate automatically a valid checksum so the game can run on a real console. + ### Notes -The current official version is v0.7.0. +The current official version is v0.8.0. All platforms have been tested in emulation. @@ -177,7 +197,7 @@ Untested: MSX controller support only handles the two joysticks and keyboard arrows (plus Space and M for buttons). The keys 0-9, Backspace and Return emulate the Colecovision keypad (CONT1.KEY only). -The Sega SG1000 doesn't have any keypad, so CONT1.KEY and CONT2.KEY aren't operative, but the support includes compatibility with Sega SC3000 computer, and the keyboard can be used as first controller (code contributed by SiRioKD) and for CONT1.KEY using the keys 0-9, Delete and CR. +The Sega SG1000 and Sega Master System doesn't have any keypad, so CONT1.KEY and CONT2.KEY aren't operative, but the support includes compatibility with Sega SC3000 computer, and the keyboard can be used as first controller (code contributed by SiRioKD) and for CONT1.KEY using the keys 0-9, Delete and CR. The Spectravideo SVI-328 only has one button in the joystick. The keyboard can be used for the second button (letter M) and to have keypad (CONT1.KEY only) using the keys 0-9, Backspace and Return. @@ -200,6 +220,8 @@ Many people is developing games using CVBasic, feel free to check some of these There are some very good examples of games developed with CVBasic. +* Airlock II game by OriginalJohn. Demo available from [https://forums.atariage.com/topic/379104-cvbasic-airlock-ii-in-progress/](https://forums.atariage.com/topic/379104-cvbasic-airlock-ii-in-progress/) + * Beachhead by Eric Damain. Demo screenshots [https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/](https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/) * Camelot Knights by nanochess. Available from [https://forums.atariage.com/topic/363252-camelot-knights-game/](https://forums.atariage.com/topic/363252-camelot-knights-game/) @@ -208,15 +230,19 @@ There are some very good examples of games developed with CVBasic. * Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) +* Duocide by Jess Ragan. Demo available from [https://forums.atariage.com/topic/379738-duocide-the-side-switching-shooter/](https://forums.atariage.com/topic/379738-duocide-the-side-switching-shooter/) + * Gorilla.BAS by nanochess. Available from [https://forums.atariage.com/topic/370716-gorillabas-for-colecovision/](https://forums.atariage.com/topic/370716-gorillabas-for-colecovision/) +* Gun Fight by Eric Damain. Video at [https://forums.atariage.com/topic/379102-gun-fight-dev-log-cvbasic/](https://forums.atariage.com/topic/379102-gun-fight-dev-log-cvbasic/) + * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) * Monkey Moon by nanochess, example from the book **Programming Games for Colecovision**. Available from [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249) * Rogue-like Wip by Skywaffle. Available from [https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/](https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/) -* Unnamed game by OriginalJohn. Demo screenshot [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5471429) +* Sub Hunt by Eric Damain. Demo videos [https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/](https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/) * Whack'em Smack'em Byron by Jess Ragan. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) From 3945f02dff7b4339135428bd13c543e6855a7e82 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 27 Apr 2025 13:03:54 -0600 Subject: [PATCH 029/155] Bank switching working in SMS --- README.md | 2 + cvbasic.c | 15 +- cvbasic_epilogue.asm | 4 + cvbasic_prologue.asm | 24 +- examples/bank_sms.bas | 554 +++++++++++++++++++++ examples/oscar_compressed_sms.bas | 437 +++++++++++++++++ examples/oscar_sms.bas | 772 ++++++++++++++++++++++++++++++ 7 files changed, 1797 insertions(+), 11 deletions(-) create mode 100644 examples/bank_sms.bas create mode 100644 examples/oscar_compressed_sms.bas create mode 100644 examples/oscar_sms.bas diff --git a/README.md b/README.md index 35314b8..a4fe606 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,9 @@ The following files compose the compiler: examples/happy_face_sms.bas Bouncing face (Sega Master System). examples/music.bas Music example. examples/oscar_compressed.bas High-resolution graphics example compressed with Pletter. + examples/oscar_compressed_sms.bas High-resolution graphics example compressed with Pletter (Sega Master System) examples/oscar.bas High-resolution graphics example. + examples/oscar_sms.bas High-resolution graphics example (Sega Master System) examples/portrait.bas Data used by demo.bas examples/portrait_sms.bas Data used by demo_sms.bas examples/space_attack.bas Game example. diff --git a/cvbasic.c b/cvbasic.c index b410af1..fd01a9e 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -92,7 +92,7 @@ struct console consoles[TOTAL_TARGETS] = { 0, 0xe000, 0, 0xa0, 0xa0, 0, 1, CPU_Z80}, {"sms", "", "Sega Master System (8K RAM)", "Sega Master System", - 0xc000, 0xe000, 0x1000, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, + 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, }; static int err_code; @@ -280,15 +280,16 @@ void emit_warning(char *string) */ void bank_finish(void) { - if (machine == SG1000) { + if (machine == SG1000 || machine == SMS) { if (bank_current == 0) { - fprintf(output, "BANK_0_FREE:\tEQU $3fff-$\n"); - fprintf(output, "\tTIMES $3fff-$ DB $ff\n"); + fprintf(output, "BANK_0_FREE:\tEQU $3fbf-$\n"); + fprintf(output, "\tTIMES $3fbf-$ DB $ff\n"); } else { - fprintf(output, "BANK_%d_FREE:\tEQU $7fff-$\n", bank_current); - fprintf(output, "\tTIMES $7fff-$ DB $ff\n"); + fprintf(output, "BANK_%d_FREE:\tEQU $7fbf-$\n", bank_current); + fprintf(output, "\tTIMES $7fbf-$ DB $ff\n"); } fprintf(output, "\tDB $%02x\n", bank_current); + fprintf(output, "\tTIMES $40 DB $ff\n"); } else if (machine == MSX) { if (bank_current == 0) { fprintf(output, "BANK_0_FREE:\tEQU $7fff-$\n"); @@ -6165,8 +6166,10 @@ int main(int argc, char *argv[]) fprintf(output, "CVBASIC_MUSIC_PLAYER:\tequ %d\n", music_used); fprintf(output, "CVBASIC_COMPRESSION:\tequ %d\n", compression_used); fprintf(output, "CVBASIC_BANK_SWITCHING:\tequ %d\n", bank_switching); + fprintf(output, "CVBASIC_BANK_ROM_SIZE:\tequ %d\n", bank_rom_size); fprintf(output, "\n"); fprintf(output, "BASE_RAM:\tequ %c%04x\t; Base of RAM\n", hex, consoles[machine].base_ram - extra_ram); + fprintf(output, "RAM_SIZE:\tequ %c%04x\t; Base of RAM\n", hex, consoles[machine].memory_size + extra_ram); if ((machine == MEMOTECH || machine == EINSTEIN) && cpm_option != 0) fprintf(output, "STACK:\tequ %c%04x\t; Base stack pointer\n", hex, 0xe000); else diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index eaacad3..4547aaf 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -36,6 +36,10 @@ rom_end: TIMES $10000-$ DB $ff endif if SG1000+SMS + if CVBASIC_BANK_SWITCHING + forg CVBASIC_BANK_ROM_SIZE*1024-1 ; Force final ROM size + db $ff + endif forg $7FF0 org $7FF0 db "TMR SEGA" diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index cc949aa..8d9adff 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1191,7 +1191,7 @@ mode_4: call WRTVDP ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) call WRTVDP - ld bc,$ff06 ; $2000 for sprites bitmaps (or $fb for $0000) + ld bc,$0706 ; $2000 for sprites bitmaps (or $03 for $0000) call WRTVDP ld bc,$0007 call WRTVDP @@ -1439,7 +1439,7 @@ nmi_handler: ld a,($ffbf) endif if SG1000+SMS - ld a,($7fff) + ld a,($7fbf) endif if MSX ld a,($bfff) @@ -2859,7 +2859,7 @@ music_play: ld a,($ffbf) endif if SG1000+SMS - ld a,($7fff) + ld a,($7fbf) endif if MSX ld a,($bfff) @@ -3817,7 +3817,17 @@ Z80_CTC: equ $28 ld (hl),0 ldir ld (lfsr),ix - else + endif + if MSX+SVI+SMS + ld ix,(lfsr) + ld hl,BASE_RAM + ld de,BASE_RAM+1 + ld bc,RAM_SIZE-1 + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO+SG1000+SORD+PENCIL+PV2000 ld hl,(lfsr) ; Save RAM trash for random generator. ld de,BASE_RAM xor a @@ -3825,7 +3835,11 @@ Z80_CTC: equ $28 inc de if PV2000 bit 7,d - else + endif + if PENCIL + bit 3,d + endif + if COLECO+SG1000+SORD bit 2,d endif jp z,$-4 diff --git a/examples/bank_sms.bas b/examples/bank_sms.bas new file mode 100644 index 0000000..59923a3 --- /dev/null +++ b/examples/bank_sms.bas @@ -0,0 +1,554 @@ + rem + rem Bank-switching example + rem by Oscar Toledo G. http://nanochess.org + rem Apr/27/2024 + rem Apr/27/2025. Adapted for Sega Master System. + rem + + BANK ROM 128 ' Select a 128KB target ROM size. + ' Now it is in bank 0. + + PLAY FULL + BANK SELECT 1 ' Select bank 1 to access. + PLAY tune_2 + + BANK SELECT 2 ' Select bank 2 to access. + + ' Notice bank 2 is selected, but the + ' music is being played from bank 1. + + DEFINE CHAR PLETTER 64,185,image_char + PALETTE 9,$0B + PALETTE 11,$1B + PALETTE 14,$2B + SCREEN image_pattern,0,200,16,12,16 + + WHILE 1: WEND + + BANK 1 ' Start of bank 1 data + + ' Mecha-8 level 5: alone + ' Fragment +tune_2: DATA BYTE 5 + MUSIC G5#Y,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC E5,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC D5#,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC E5,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC G5#,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC S,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC C5#,G3#,-,M2 + MUSIC -,S,-,M2 + MUSIC G5#,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC E5,G3#,-,M2 + MUSIC -,S,-,M2 + MUSIC F5#,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,F3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC -,F3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,B2,-,M1 + MUSIC -,S,-,M2 + MUSIC -,F3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,B2,-,M1 + MUSIC -,S,-,M2 + MUSIC -,F3#,-,M1 + MUSIC -,S,-,M2 + MUSIC C5#,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,F3#,-,M1 + MUSIC S,S,-,M2 + MUSIC C5#,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC E5,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC E5,A2,-,M2 + MUSIC S,S,-,M2 + MUSIC D5#,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M2 + MUSIC S,S,-,M2 + MUSIC C5,G2#,-,M1 + MUSIC S,S,-,M2 + MUSIC S,D3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,G2#,-,M1 + MUSIC S,S,-,M2 + MUSIC S,D3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,G2#,-,M1 + MUSIC S,S,-,M2 + MUSIC -,D3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M2 + MUSIC -,D3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M2 + MUSIC -,D3#,-,M1 + MUSIC -,S,-,M3 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M2 + MUSIC -,D3#,-,M1 + MUSIC -,S,-,M3 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M1 + MUSIC -,D3#,-,M1 + MUSIC -,S,-,M1 + MUSIC REPEAT + + BANK 2 ' Start of bank 2 data. + + ' Start tile = 64. Total_tiles = 185 +image_char: + DATA BYTE $69,$b4,$ff,$00,$24,$8f,$03,$00 + DATA BYTE $e4,$03,$7f,$00,$00,$41,$1f,$00 + DATA BYTE $01,$ff,$fe,$ff,$dd,$03,$1f,$ba + DATA BYTE $61,$03,$00,$80,$80,$00,$02,$c0 + DATA BYTE $c0,$00,$c0,$40,$f0,$b0,$17,$f0 + DATA BYTE $00,$f0,$00,$01,$03,$04,$f0,$f4 + DATA BYTE $f4,$00,$f4,$33,$00,$79,$23,$de + DATA BYTE $03,$27,$80,$f9,$00,$80,$6f,$07 + DATA BYTE $22,$03,$f7,$00,$80,$f3,$00,$26 + DATA BYTE $80,$fb,$00,$34,$69,$0f,$03,$81 + DATA BYTE $8f,$a2,$03,$bf,$00,$f9,$13,$04 + DATA BYTE $8f,$03,$2a,$c7,$03,$ab,$e3,$03 + DATA BYTE $2f,$71,$03,$4f,$ae,$6a,$03,$f3 + DATA BYTE $00,$fe,$ec,$03,$00,$6e,$fc,$11 + DATA BYTE $03,$f8,$fd,$00,$00,$3f,$71,$00 + DATA BYTE $03,$04,$3b,$9c,$07,$b3,$29,$7b + DATA BYTE $00,$00,$de,$17,$01,$03,$0f,$b3 + DATA BYTE $b3,$bf,$07,$3f,$33,$1c,$03,$1b + DATA BYTE $64,$03,$7d,$03,$ff,$10,$fd,$ff + DATA BYTE $c0,$2e,$f9,$a0,$70,$30,$70,$f0 + DATA BYTE $a3,$60,$03,$ee,$ee,$e8,$00,$0e + DATA BYTE $e2,$e2,$e0,$80,$03,$44,$ec,$00 + DATA BYTE $80,$cc,$00,$00,$84,$96,$f8,$00 + DATA BYTE $5b,$f1,$00,$a0,$f3,$e6,$7b,$a2 + DATA BYTE $0b,$0f,$00,$20,$00,$07,$00,$80 + DATA BYTE $0f,$8f,$0f,$e0,$03,$a0,$1f,$bf + DATA BYTE $3f,$20,$b0,$0f,$03,$a0,$0f,$af + DATA BYTE $2f,$ed,$03,$51,$3b,$cf,$11,$00 + DATA BYTE $00,$c7,$00,$10,$c1,$18,$00,$04 + DATA BYTE $c0,$b5,$48,$f5,$00,$00,$fc,$bb + DATA BYTE $00,$07,$bb,$6f,$07,$8b,$b7,$bb + DATA BYTE $0b,$03,$e2,$a7,$61,$69,$03,$63 + DATA BYTE $e7,$30,$00,$61,$97,$98,$60,$17 + DATA BYTE $44,$40,$e8,$a7,$06,$41,$ec,$b8 + DATA BYTE $f1,$b3,$1a,$e8,$97,$c4,$bf,$cc + DATA BYTE $44,$83,$63,$66,$99,$07,$02,$46 + DATA BYTE $1d,$bf,$24,$c2,$cb,$77,$30,$03 + DATA BYTE $17,$bb,$c5,$cb,$e1,$f3,$bc,$74 + DATA BYTE $a3,$27,$aa,$85,$bb,$cf,$07,$ae + DATA BYTE $ce,$03,$a3,$27,$6f,$84,$87,$ef + DATA BYTE $f1,$0b,$68,$8f,$03,$48,$35,$07 + DATA BYTE $e6,$00,$7f,$e7,$03,$17,$a3,$31 + DATA BYTE $03,$f4,$0b,$e0,$8f,$03,$e4,$39 + DATA BYTE $03,$0f,$f2,$c2,$8f,$eb,$98,$00 + DATA BYTE $00,$e7,$64,$00,$ef,$00,$00,$5a + DATA BYTE $ed,$00,$2f,$03,$af,$00,$84,$af + DATA BYTE $20,$f0,$03,$d0,$f0,$20,$e1,$c1 + DATA BYTE $e0,$bb,$03,$0b,$8b,$03,$00,$e8 + DATA BYTE $00,$12,$f4,$f5,$4c,$bf,$12,$40 + DATA BYTE $e3,$00,$60,$00,$97,$b5,$80,$84 + DATA BYTE $e3,$fd,$02,$00,$7d,$7d,$7b,$07 + DATA BYTE $fb,$f9,$7f,$07,$1e,$ff,$fa,$ef + DATA BYTE $82,$fb,$df,$b7,$00,$18,$0f,$fe + DATA BYTE $9f,$6f,$f9,$8b,$a7,$88,$b7,$80 + DATA BYTE $2f,$88,$07,$30,$0f,$c7,$f8,$cf + DATA BYTE $83,$00,$03,$23,$23,$95,$db,$02 + DATA BYTE $c5,$a3,$bd,$03,$84,$b7,$20,$00 + DATA BYTE $c1,$e1,$e1,$60,$80,$e0,$e0,$40 + DATA BYTE $04,$08,$48,$48,$00,$78,$00,$00 + DATA BYTE $44,$79,$00,$80,$79,$b0,$7a,$2d + DATA BYTE $0b,$7d,$00,$11,$87,$7e,$69,$00 + DATA BYTE $0b,$c6,$ab,$ee,$98,$00,$00,$a7 + DATA BYTE $04,$41,$a7,$a7,$00,$27,$97,$b3 + DATA BYTE $b7,$17,$01,$af,$a8,$b7,$27,$ff + DATA BYTE $f9,$f7,$10,$87,$fb,$ff,$0b,$46 + DATA BYTE $0c,$bf,$0c,$c0,$8f,$22,$06,$8f + DATA BYTE $00,$00,$87,$00,$01,$c0,$fb,$bb + DATA BYTE $d3,$f0,$fe,$0e,$07,$e3,$83,$cb + DATA BYTE $c4,$a3,$64,$c7,$03,$40,$9d,$03 + DATA BYTE $17,$c9,$f3,$c2,$af,$f0,$c7,$0b + DATA BYTE $a8,$85,$b7,$fd,$03,$f3,$8f,$3c + DATA BYTE $78,$03,$26,$7a,$fd,$03,$b8,$1b + DATA BYTE $07,$bc,$ff,$30,$07,$b8,$93,$99 + DATA BYTE $98,$03,$bc,$ab,$4c,$3e,$03,$63 + DATA BYTE $1e,$03,$5f,$1e,$03,$1c,$7f,$03 + DATA BYTE $17,$d7,$ce,$00,$3f,$03,$ff,$9b + DATA BYTE $af,$c2,$f3,$63,$c0,$03,$88,$1c + DATA BYTE $03,$08,$e7,$5e,$03,$c3,$12,$e0 + DATA BYTE $cb,$c7,$cf,$f4,$d7,$5e,$03,$5a + DATA BYTE $fa,$00,$72,$03,$97,$a2,$81,$00 + DATA BYTE $00,$89,$00,$2c,$00,$ad,$00,$23 + DATA BYTE $07,$ce,$01,$de,$de,$df,$d3,$93 + DATA BYTE $d8,$03,$e3,$46,$ff,$03,$70,$07 + DATA BYTE $03,$83,$7f,$7c,$22,$ff,$c2,$f7 + DATA BYTE $00,$fb,$c0,$f1,$b1,$f0,$c0,$f8 + DATA BYTE $b8,$3a,$f8,$c0,$8f,$78,$9f,$e5 + DATA BYTE $ee,$00,$c4,$00,$d8,$d8,$18,$00 + DATA BYTE $f8,$f8,$64,$20,$9b,$b0,$40,$63 + DATA BYTE $e0,$0c,$00,$3f,$31,$2f,$0c,$6f + DATA BYTE $61,$6f,$00,$4f,$01,$00,$00,$93 + DATA BYTE $00,$40,$90,$b7,$00,$fb,$00,$8b + DATA BYTE $e3,$b8,$03,$fb,$96,$30,$00,$88 + DATA BYTE $4f,$03,$00,$01,$03,$11,$02,$03 + DATA BYTE $05,$03,$07,$31,$80,$d7,$21,$dc + DATA BYTE $83,$48,$8f,$5e,$1f,$8f,$03,$f8 + DATA BYTE $07,$a3,$7e,$df,$a6,$3c,$31,$03 + DATA BYTE $0e,$03,$03,$ae,$20,$1b,$07,$cf + DATA BYTE $d0,$e3,$98,$0a,$03,$02,$c6,$03 + DATA BYTE $82,$f1,$a3,$f3,$8b,$c9,$86,$16 + DATA BYTE $e7,$0b,$cf,$9c,$37,$0b,$e6,$03 + DATA BYTE $1f,$1b,$03,$9f,$7f,$37,$07,$0f + DATA BYTE $1d,$03,$07,$73,$f8,$e7,$4f,$3f + DATA BYTE $e3,$8f,$fc,$eb,$2e,$cb,$06,$f0 + DATA BYTE $e3,$0f,$fc,$7a,$a7,$77,$e9,$c7 + DATA BYTE $e6,$cb,$4a,$e1,$00,$01,$a2,$1c + DATA BYTE $f5,$b5,$21,$01,$67,$66,$67,$b2 + DATA BYTE $ff,$dd,$00,$ff,$80,$10,$6f,$6f + DATA BYTE $7f,$18,$c7,$f9,$56,$80,$51,$03 + DATA BYTE $00,$2f,$18,$fe,$e6,$fc,$08,$fe + DATA BYTE $f6,$09,$fe,$08,$e6,$e6,$d3,$57 + DATA BYTE $ce,$00,$16,$e3,$84,$e7,$b8,$0b + DATA BYTE $b8,$38,$00,$18,$00,$f8,$03,$0e + DATA BYTE $2f,$54,$21,$83,$2f,$70,$2f,$03 + DATA BYTE $27,$00,$37,$8b,$00,$00,$b7,$00 + DATA BYTE $45,$07,$27,$00,$a5,$bb,$6f,$66 + DATA BYTE $00,$c7,$82,$e0,$f3,$01,$f3,$f1 + DATA BYTE $a9,$43,$f7,$97,$01,$a1,$c0,$81 + DATA BYTE $f1,$aa,$12,$ef,$e0,$00,$60,$60 + DATA BYTE $71,$f0,$f8,$e0,$00,$f8,$70,$fe + DATA BYTE $ee,$fe,$03,$07,$04,$80,$ac,$0f + DATA BYTE $08,$0e,$07,$05,$0f,$0a,$4d,$00 + DATA BYTE $0f,$07,$1f,$18,$0f,$05,$1f,$1a + DATA BYTE $0e,$0f,$0d,$17,$12,$03,$7f,$1f + DATA BYTE $17,$ef,$7d,$53,$03,$13,$ab,$bf + DATA BYTE $d6,$9b,$1d,$c2,$e3,$5e,$0f,$6d + DATA BYTE $89,$03,$05,$9a,$74,$1b,$43,$01 + DATA BYTE $8e,$00,$47,$3b,$3b,$fb,$f0,$0d + DATA BYTE $0d,$f9,$ca,$03,$e7,$40,$04,$04 + DATA BYTE $fc,$f0,$0c,$0c,$70,$f0,$03,$20 + DATA BYTE $dc,$dc,$80,$a8,$1c,$1c,$7c,$e0 + DATA BYTE $e7,$4f,$bc,$18,$07,$1a,$87,$f0 + DATA BYTE $c3,$ca,$00,$10,$0b,$07,$f0,$e3 + DATA BYTE $9b,$01,$90,$6f,$f9,$63,$ab,$22 + DATA BYTE $77,$03,$98,$67,$03,$35,$10,$ef + DATA BYTE $89,$e7,$3f,$ae,$73,$07,$03,$f4 + DATA BYTE $1c,$4b,$f4,$eb,$5d,$0b,$b8,$03 + DATA BYTE $f0,$e4,$d7,$cf,$1b,$9b,$d3,$e2 + DATA BYTE $ef,$72,$02,$ab,$3c,$3f,$ab,$ee + DATA BYTE $03,$ee,$0b,$83,$75,$bc,$00,$14 + DATA BYTE $c3,$00,$00,$5c,$a0,$00,$e3,$3a + DATA BYTE $4a,$eb,$46,$00,$e2,$e3,$c9,$bf + DATA BYTE $16,$e6,$00,$66,$00,$88,$03,$2e + DATA BYTE $00,$00,$3e,$b8,$00,$bb,$98,$01 + DATA BYTE $9f,$65,$00,$08,$00,$a1,$eb,$7c + DATA BYTE $00,$60,$b8,$00,$cf,$c3,$c7,$ef + DATA BYTE $e8,$ef,$9c,$f9,$0c,$1f,$45,$13 + DATA BYTE $95,$38,$26,$0f,$2f,$04,$0f,$00 + DATA BYTE $0b,$0f,$24,$7e,$5a,$2e,$e4,$fe + DATA BYTE $38,$1a,$e6,$03,$e0,$f6,$18,$16 + DATA BYTE $e6,$f4,$c5,$00,$b7,$fc,$7f,$fc + DATA BYTE $97,$8c,$03,$fe,$82,$d9,$06,$df + DATA BYTE $3e,$0f,$cf,$a3,$2c,$f1,$a6,$10 + DATA BYTE $13,$e3,$11,$11,$03,$05,$87,$16 + DATA BYTE $e4,$11,$f2,$81,$f0,$19,$64,$64 + DATA BYTE $18,$03,$0d,$d7,$03,$8c,$77,$02 + DATA BYTE $76,$00,$12,$2f,$2d,$1f,$b1,$0e + DATA BYTE $0e,$3f,$40,$a7,$0b,$3f,$b6,$19 + DATA BYTE $09,$3e,$10,$9f,$70,$60,$d0,$00 + DATA BYTE $60,$40,$7f,$3c,$63,$43,$7c,$04 + DATA BYTE $70,$ce,$8e,$70,$40,$da,$1c,$87 + DATA BYTE $dd,$ab,$98,$df,$70,$06,$cc,$33 + DATA BYTE $33,$68,$fc,$0f,$c5,$1c,$c5,$00 + DATA BYTE $28,$af,$1d,$8b,$c0,$db,$db,$ff + DATA BYTE $3d,$42,$17,$42,$3f,$1d,$ff,$c1 + DATA BYTE $a9,$04,$fa,$bd,$60,$e5,$e5,$1e + DATA BYTE $32,$cd,$3b,$cd,$3e,$03,$94,$1f + DATA BYTE $c0,$51,$cb,$38,$19,$80,$82,$da + DATA BYTE $37,$ba,$1f,$33,$f2,$0a,$ca,$ca + DATA BYTE $1f,$03,$9e,$5c,$07,$e7,$40,$60 + DATA BYTE $98,$98,$e0,$01,$82,$9f,$b2,$52 + DATA BYTE $38,$38,$03,$c0,$93,$43,$02,$92 + DATA BYTE $60,$03,$0f,$82,$7c,$7c,$30,$80 + DATA BYTE $20,$e3,$58,$04,$03,$0c,$cf,$03 + DATA BYTE $87,$f3,$e3,$df,$eb,$c3,$e2,$e3 + DATA BYTE $f8,$f7,$89,$04,$f3,$84,$8b,$10 + DATA BYTE $e3,$df,$ed,$5b,$6e,$13,$e3,$26 + DATA BYTE $3b,$3c,$03,$1b,$97,$76,$1f,$6f + DATA BYTE $3f,$3c,$9f,$c7,$39,$cc,$3d,$f7 + DATA BYTE $fb,$d8,$03,$13,$80,$ce,$c7,$67 + DATA BYTE $80,$5f,$f2,$cf,$71,$6f,$10,$0f + DATA BYTE $85,$b7,$c5,$f7,$d8,$f7,$4f,$99 + DATA BYTE $00,$0e,$97,$c5,$02,$cf,$00,$9d + DATA BYTE $3b,$9f,$dc,$43,$fd,$ec,$07,$9f + DATA BYTE $52,$f7,$01,$26,$8b,$b8,$0c,$cd + DATA BYTE $1d,$ff,$01,$e2,$ff,$0d,$b3,$b2 + DATA BYTE $af,$10,$18,$8b,$f0,$e0,$c7,$00 + DATA BYTE $07,$e3,$80,$e1,$61,$a1,$c0,$e3 + DATA BYTE $38,$23,$e1,$a9,$bb,$59,$af,$8d + DATA BYTE $04,$9a,$e0,$10,$c1,$d2,$54,$86 + DATA BYTE $82,$07,$fb,$5f,$15,$f3,$f7,$8c + DATA BYTE $03,$e7,$db,$d2,$07,$90,$6a,$26 + DATA BYTE $97,$78,$07,$ff,$0e,$b7,$8b,$d7 + DATA BYTE $c2,$cf,$c0,$c0,$33,$c0,$dc,$00 + DATA BYTE $dc,$63,$c7,$43,$9f,$3b,$03,$07 + DATA BYTE $a9,$4f,$07,$a1,$43,$2f,$ff,$d0 + DATA BYTE $3f,$88,$e3,$08,$14,$01,$14,$08 + DATA BYTE $0c,$f1,$f1,$ac,$1c,$1b,$d6,$fd + DATA BYTE $4a,$03,$d2,$d8,$fd,$a7,$57,$b0 + DATA BYTE $a0,$e0,$7b,$48,$f7,$b7,$f8,$06 + DATA BYTE $71,$ff,$8e,$ff,$60,$23,$3d,$20 + DATA BYTE $bd,$bf,$3d,$24,$ff,$00,$04,$b1 + DATA BYTE $00,$a7,$81,$e1,$e4,$1b,$1b,$e7 + DATA BYTE $f6,$17,$68,$0f,$83,$1c,$03,$30 + DATA BYTE $81,$f6,$3c,$84,$e7,$be,$4c,$f2 + DATA BYTE $bf,$fe,$01,$e2,$1d,$1d,$fe,$c2 + DATA BYTE $3d,$3d,$a2,$03,$82,$d2,$b2,$fe + DATA BYTE $83,$bf,$2a,$2f,$92,$28,$cb,$82 + DATA BYTE $d0,$d0,$10,$50,$96,$50,$50,$64 + DATA BYTE $9b,$9b,$11,$64,$7c,$83,$15,$3f + DATA BYTE $c0,$1f,$91,$d9,$03,$a3,$b0,$f0 + DATA BYTE $49,$8f,$50,$03,$3f,$03,$9c,$9c + DATA BYTE $00,$e1,$0f,$fc,$02,$02,$22,$05 + DATA BYTE $03,$5d,$f8,$07,$e5,$0f,$34,$e3 + DATA BYTE $3f,$20,$02,$b3,$b3,$33,$20,$bd + DATA BYTE $bd,$e3,$51,$a7,$a7,$27,$c0,$0f + DATA BYTE $00,$a3,$a3,$22,$00,$25,$a1,$a1 + DATA BYTE $eb,$5c,$f9,$00,$e7,$45,$00,$9f + DATA BYTE $00,$a8,$bb,$13,$df,$be,$f2,$ce + DATA BYTE $57,$03,$36,$af,$f7,$a3,$22,$84 + DATA BYTE $00,$00,$44,$00,$d1,$9f,$bb,$03 + DATA BYTE $96,$13,$f7,$00,$a2,$1f,$41,$00 + DATA BYTE $30,$00,$10,$85,$80,$f6,$f6,$e0 + DATA BYTE $68,$7e,$76,$29,$78,$08,$1a,$13 + DATA BYTE $af,$40,$00,$43,$bd,$bf,$02,$d7 + DATA BYTE $d5,$10,$d7,$00,$83,$00,$40,$0a + DATA BYTE $6a,$0b,$0a,$40,$02,$42,$aa,$50 + DATA BYTE $40,$00,$ca,$ff,$75,$b8,$d4,$ff + DATA BYTE $71,$c5,$f3,$5d,$30,$bb,$2d,$85 + DATA BYTE $f3,$e1,$eb,$e3,$fe,$0c,$10,$3d + DATA BYTE $0c,$43,$b6,$9d,$00,$f3,$ee,$28 + DATA BYTE $e7,$eb,$b8,$d7,$95,$e0,$a1,$b3 + DATA BYTE $e1,$bb,$95,$20,$5b,$00,$ca,$fb + DATA BYTE $e3,$c9,$03,$10,$08,$00,$82,$3c + DATA BYTE $3c,$f8,$f1,$db,$4c,$80,$3e,$2f + DATA BYTE $e7,$03,$9e,$04,$b8,$8b,$a1,$30 + DATA BYTE $78,$7c,$04,$74,$93,$9b,$d0,$0b + DATA BYTE $68,$68,$40,$c6,$3b,$70,$8f,$9b + DATA BYTE $6d,$49,$03,$54,$0a,$13,$17,$82 + DATA BYTE $b8,$e7,$41,$21,$27,$06,$27,$dd + DATA BYTE $32,$bb,$cc,$0c,$03,$76,$de,$03 + DATA BYTE $30,$0e,$1e,$07,$17,$88,$4b,$88 + DATA BYTE $e7,$1e,$63,$1f,$43,$12,$af,$03 + DATA BYTE $e3,$10,$9f,$13,$2c,$2c,$92,$94 + DATA BYTE $1e,$30,$0f,$03,$9e,$77,$89,$ef + DATA BYTE $bd,$36,$c3,$62,$08,$8b,$4e,$36 + DATA BYTE $fe,$fb,$14,$f1,$7b,$f1,$5e,$27 + DATA BYTE $f7,$ff,$0c,$7e,$81,$81,$ff,$8f + DATA BYTE $28,$9d,$c0,$20,$20,$df,$26,$d9 + DATA BYTE $d9,$07,$3e,$44,$bb,$bb,$7c,$51 + DATA BYTE $4b,$0d,$af,$f1,$e3,$77,$0b,$07 + DATA BYTE $07,$c6,$39,$39,$fe,$10,$df,$38 + DATA BYTE $c6,$c6,$2f,$38,$80,$ce,$22,$80 + DATA BYTE $40,$a3,$71,$c0,$e3,$02,$1b,$e4 + DATA BYTE $e4,$1f,$5f,$ff,$26,$5f,$53,$fb + DATA BYTE $0f,$90,$03,$07,$db,$57,$e6,$00 + DATA BYTE $bf,$1f,$0a,$f5,$3b,$f5,$0a,$11 + DATA BYTE $c6,$03,$f1,$3b,$a3,$e1,$b0,$03 + DATA BYTE $99,$dc,$c1,$03,$02,$04,$fd,$fd + DATA BYTE $03,$04,$c1,$e8,$e0,$0c,$91,$9d + DATA BYTE $9d,$7c,$44,$81,$0c,$2d,$90,$80 + DATA BYTE $64,$3c,$81,$03,$3e,$61,$81,$80 + DATA BYTE $a2,$80,$03,$1d,$80,$17,$d2,$bf + DATA BYTE $6b,$63,$00,$a7,$f3,$00,$03,$30 + DATA BYTE $e1,$f1,$e1,$18,$e1,$00,$fb,$e1 + DATA BYTE $09,$d0,$df,$d0,$04,$18,$48,$1e + DATA BYTE $fc,$e2,$92,$00,$02,$f3,$13,$e2 + DATA BYTE $83,$21,$c3,$09,$bb,$80,$c3,$e7 + DATA BYTE $c8,$03,$0c,$0f,$80,$04,$18,$31 + DATA BYTE $31,$11,$cf,$e2,$79,$00,$77,$00 + DATA BYTE $d2,$03,$c2,$30,$1f,$40,$8f,$8f + DATA BYTE $87,$9a,$06,$03,$02,$0d,$0f,$8c + DATA BYTE $03,$01,$5a,$63,$01,$2f,$18,$33 + DATA BYTE $2f,$67,$a3,$bf,$63,$b7,$f3,$03 + DATA BYTE $8b,$e3,$e2,$03,$40,$24,$00,$21 + DATA BYTE $00,$7c,$00,$00,$74,$74,$12,$ab + DATA BYTE $34,$00,$e6,$c3,$65,$e0,$b7,$23 + DATA BYTE $e2,$47,$0d,$60,$b4,$dd,$5f,$5f + DATA BYTE $09,$4f,$00,$17,$17,$db,$96,$47 + DATA BYTE $00,$31,$cf,$86,$08,$0a,$d3,$02 + DATA BYTE $eb,$73,$7e,$80,$b2,$03,$db,$ee + DATA BYTE $40,$03,$5e,$70,$3a,$a2,$00,$01 + DATA BYTE $01,$e2,$e4,$e2,$0a,$0e,$70,$00 + DATA BYTE $12,$2f,$70,$50,$2c,$11,$00,$0d + DATA BYTE $18,$bf,$a7,$bf,$2c,$fb,$fc,$ec + DATA BYTE $68,$fc,$97,$16,$51,$87,$cf,$dc + DATA BYTE $07,$e3,$48,$03,$07,$83,$01,$00 + DATA BYTE $c2,$c2,$c3,$01,$62,$62,$63,$01 + DATA BYTE $96,$db,$12,$89,$db,$06,$96,$cf + DATA BYTE $0e,$c0,$03,$02,$f9,$06,$06,$72 + DATA BYTE $f9,$eb,$f1,$f7,$53,$cc,$91,$dd + DATA BYTE $d5,$9d,$77,$61,$03,$13,$f7,$7f + DATA BYTE $47,$83,$a1,$0d,$ee,$82,$bb,$8b + DATA BYTE $a0,$c7,$c7,$e0,$13,$ad,$c3,$f3 + DATA BYTE $dd,$c3,$cf,$83,$d8,$07,$ff,$c0 + DATA BYTE $f0,$3c,$c3,$c3,$fc,$c8,$97,$64 + DATA BYTE $78,$27,$72,$7e,$83,$cb,$88,$cf + DATA BYTE $d8,$27,$3b,$27,$f8,$4b,$15,$bf + DATA BYTE $08,$dd,$17,$03,$84,$cf,$02,$0c + DATA BYTE $06,$0b,$09,$06,$f7,$22,$0e,$88 + DATA BYTE $ee,$10,$8c,$8c,$73,$73,$63,$8c + DATA BYTE $17,$03,$4a,$03,$b6,$b6,$03,$1a + DATA BYTE $fb,$fb,$0b,$46,$03,$6b,$07,$18 + DATA BYTE $70,$03,$cf,$31,$1e,$03,$17,$8f + DATA BYTE $03,$05,$08,$03,$24,$c8,$00,$04 + DATA BYTE $da,$89,$00,$04,$db,$00,$c0,$84 + DATA BYTE $e3,$80,$00,$39,$3d,$39,$84,$3a + DATA BYTE $3e,$3a,$08,$c1,$ef,$e6,$03,$10 + DATA BYTE $f5,$b3,$04,$71,$71,$01,$08,$03 + DATA BYTE $09,$53,$00,$af,$08,$8c,$ba,$ba + DATA BYTE $aa,$af,$5b,$00,$4a,$d3,$40,$2f + DATA BYTE $00,$02,$21,$23,$23,$02,$43,$01 + DATA BYTE $84,$61,$7c,$90,$20,$c1,$cc,$e1 + DATA BYTE $bb,$22,$38,$fc,$00,$1d,$fc,$b0 + DATA BYTE $0e,$0b,$de,$03,$7c,$40,$8b,$58 + DATA BYTE $87,$05,$f9,$7c,$23,$91,$bb,$42 + DATA BYTE $bc,$4e,$00,$b0,$ac,$82,$80,$2e + DATA BYTE $01,$90,$00,$9c,$2d,$08,$a0,$26 + DATA BYTE $26,$b1,$22,$83,$d8,$38,$0a,$72 + DATA BYTE $05,$07,$05,$06,$e0,$06,$00,$ce + DATA BYTE $16,$bf,$b2,$dc,$03,$63,$7f,$03 + DATA BYTE $3f,$7c,$e6,$27,$c0,$3f,$b7,$8c + DATA BYTE $27,$0f,$f2,$67,$07,$46,$c7,$31 + DATA BYTE $03,$5b,$03,$1b,$8f,$03,$1f,$3b + DATA BYTE $1b,$03,$03,$b2,$3e,$70,$96,$39 + DATA BYTE $00,$20,$f6,$44,$47,$9b,$71,$03 + DATA BYTE $c3,$73,$83,$61,$a3,$32,$3f,$f7 + DATA BYTE $8a,$1f,$0e,$87,$c9,$0f,$06,$a7 + DATA BYTE $80,$07,$03,$0c,$0c,$03,$41,$41 + DATA BYTE $02,$f5,$c5,$c3,$85,$97,$e9,$f7 + DATA BYTE $5f,$57,$fb,$76,$b7,$68,$63,$03 + DATA BYTE $67,$bb,$a3,$4b,$f3,$ef,$2f,$b2 + DATA BYTE $03,$c3,$d8,$ff,$c7,$4d,$88,$3f + DATA BYTE $8f,$ec,$29,$c3,$47,$01,$60,$03 + DATA BYTE $9a,$f7,$d3,$2b,$38,$77,$d6,$a5 + DATA BYTE $f7,$09,$03,$7d,$83,$82,$03,$03 + DATA BYTE $1b,$fb,$fd,$ce,$03,$97,$50,$e1 + DATA BYTE $1f,$1e,$1f,$e2,$c3,$60,$00,$03 + DATA BYTE $80,$db,$5b,$85,$03,$fb,$7b,$fb + DATA BYTE $bb,$b7,$77,$d9,$03,$4f,$ba,$3c + DATA BYTE $03,$01,$03,$6b,$1f,$8c,$1b,$40 + DATA BYTE $03,$ee,$cf,$78,$f0,$03,$1c,$ce + DATA BYTE $cb,$23,$3f,$fe,$07,$7e,$ff,$67 + DATA BYTE $03,$7f,$99,$03,$12,$46,$d3,$22 + DATA BYTE $00,$b8,$c3,$5d,$7c,$03,$07,$30 + DATA BYTE $03,$bc,$03,$3c,$7e,$98,$00,$3d + DATA BYTE $03,$3e,$c6,$00,$1e,$68,$03,$ca + DATA BYTE $32,$af,$d3,$ee,$15,$cb,$03,$11 + DATA BYTE $07,$04,$c2,$cb,$00,$07,$c1,$2f + DATA BYTE $2e,$2f,$c2,$23,$03,$21,$22,$c3 + DATA BYTE $23,$20,$23,$89,$8b,$07,$bd,$03 + DATA BYTE $46,$e7,$b4,$0b,$b2,$7c,$a7,$5b + DATA BYTE $a3,$03,$7f,$ef,$17,$f1,$03,$01 + DATA BYTE $e3,$07,$fe,$c6,$03,$fc,$26,$03 + DATA BYTE $ee,$fd,$cb,$a7,$8e,$bd,$e9,$58 + DATA BYTE $a6,$78,$e4,$b9,$e8,$bd,$67,$b3 + DATA BYTE $7a,$01,$31,$0e,$04,$01,$02,$96 + DATA BYTE $01,$15,$ca,$17,$60,$f3,$01,$7f + DATA BYTE $12,$ed,$ed,$1e,$1c,$d4,$8a,$5f + DATA BYTE $d5,$3a,$57,$01,$94,$e3,$e0,$c1 + DATA BYTE $d7,$d8,$df,$a4,$c2,$f6,$20,$aa + DATA BYTE $e3,$4d,$2c,$f0,$f1,$16,$f2,$7e + DATA BYTE $ef,$0c,$d3,$bd,$44,$ab,$52,$05 + DATA BYTE $67,$0b,$20,$83,$56,$61,$13,$e3 + DATA BYTE $01,$14,$03,$80,$5f,$ae,$78,$e2 + DATA BYTE $ac,$f1,$03,$66,$d0,$97,$31,$f0 + DATA BYTE $23,$e1,$81,$83,$c5,$e7,$12,$b3 + DATA BYTE $bf,$eb,$3f,$4d,$03,$89,$c7,$60 + DATA BYTE $e1,$e3,$74,$03,$89,$9b,$b1,$00 + DATA BYTE $fc,$fe,$8f,$00,$ff,$59,$00,$1e + DATA BYTE $84,$cb,$1e,$c7,$07,$3c,$9d,$03 + DATA BYTE $0b,$bc,$9f,$e0,$41,$33,$32,$23 + DATA BYTE $00,$4c,$30,$00,$01,$03,$48,$05 + DATA BYTE $02,$20,$b3,$2e,$00,$bf,$05,$06 + DATA BYTE $83,$fc,$03,$10,$63,$02,$e7,$31 + DATA BYTE $73,$0f,$d2,$8f,$03,$d0,$18,$03 + DATA BYTE $d3,$03,$d8,$c6,$03,$49,$6f,$2b + DATA BYTE $13,$cf,$1f,$ab,$97,$c6,$03,$bf + DATA BYTE $b8,$cb,$4d,$3f,$70,$f7,$99,$fc + DATA BYTE $05,$cc,$03,$e0,$03,$68,$60,$11 + DATA BYTE $be,$c6,$03,$d7,$31,$03,$d6,$03 + DATA BYTE $db,$c5,$85,$f9,$03,$f4,$81,$7d + DATA BYTE $0f,$ac,$00,$10,$f1,$07,$02,$e1 + DATA BYTE $83,$7c,$f9,$4c,$20,$01,$a6,$1b + DATA BYTE $01,$18,$2e,$01,$0c,$01,$ff,$2d + DATA BYTE $6f,$34,$9b,$e1,$a8,$03,$ee,$f4 + DATA BYTE $4f,$71,$20,$c7,$00,$62,$67,$02 + DATA BYTE $04,$c3,$c7,$03,$f4,$03,$21,$83 + DATA BYTE $87,$5e,$87,$8f,$07,$15,$e0,$ca + DATA BYTE $dd,$a7,$1d,$b1,$8c,$30,$9b,$91 + DATA BYTE $70,$80,$c0,$4d,$b7,$88,$d6,$af + DATA BYTE $e7,$87,$45,$e0,$46,$00,$9b,$f8 + DATA BYTE $11,$f0,$a1,$7f,$e0,$14,$01,$3f + DATA BYTE $82,$5d,$f0,$31,$00,$01,$03,$8b + DATA BYTE $8c,$03,$8f,$03,$79,$af,$03,$bc + DATA BYTE $ab,$56,$2a,$ac,$00,$fe,$f9,$ab + DATA BYTE $b1,$03,$f8,$e3,$03,$fc,$ef,$03 + DATA BYTE $f1,$9f,$f9,$03,$06,$94,$93,$02 + DATA BYTE $ce,$03,$07,$22,$00,$98,$00,$00 + DATA BYTE $f9,$00,$d2,$df,$30,$03,$90,$ff + DATA BYTE $b1,$ee,$4d,$84,$c3,$0f,$c2,$fb + DATA BYTE $e6,$03,$0c,$34,$03,$06,$b7,$0b + DATA BYTE $00,$8b,$07,$00,$f1,$00,$5e,$b7 + DATA BYTE $66,$0d,$31,$03,$29,$03,$55,$ae + DATA BYTE $13,$e3,$fe,$c3,$ab,$63,$f6,$03 + DATA BYTE $88,$3f,$03,$ff,$ff,$ff,$f0 + + ' Width = 16, height = 12 +image_pattern: + DATA BYTE $40,$00,$41,$00,$42,$00,$43,$00,$44,$00,$45,$00,$46,$00,$47,$00,$48,$00,$48,$00,$48,$00,$49,$00,$4a,$00,$4b,$00,$4c,$00,$4d,$00 + DATA BYTE $4e,$00,$4f,$00,$50,$00,$51,$00,$52,$00,$53,$00,$54,$00,$55,$00,$56,$00,$48,$00,$48,$00,$57,$00,$58,$00,$59,$00,$5a,$00,$5b,$00 + DATA BYTE $5c,$00,$5d,$00,$5e,$00,$5f,$00,$60,$00,$61,$00,$62,$00,$63,$00,$64,$00,$65,$00,$66,$00,$67,$00,$68,$00,$69,$00,$6a,$00,$6b,$00 + DATA BYTE $6c,$00,$6d,$00,$6e,$00,$6f,$00,$70,$00,$71,$00,$72,$00,$73,$00,$74,$00,$75,$00,$76,$00,$77,$00,$78,$00,$79,$00,$7a,$00,$7b,$00 + DATA BYTE $7c,$00,$7d,$00,$7e,$00,$7f,$00,$80,$00,$81,$00,$82,$00,$83,$00,$84,$00,$85,$00,$86,$00,$87,$00,$88,$00,$89,$00,$8a,$00,$8b,$00 + DATA BYTE $8c,$00,$8d,$00,$8e,$00,$8f,$00,$90,$00,$91,$00,$92,$00,$93,$00,$94,$00,$95,$00,$96,$00,$97,$00,$98,$00,$99,$00,$9a,$00,$9b,$00 + DATA BYTE $9c,$00,$9d,$00,$9e,$00,$9f,$00,$a0,$00,$a1,$00,$a2,$00,$a3,$00,$a4,$00,$a5,$00,$a6,$00,$a7,$00,$a8,$00,$a9,$00,$aa,$00,$ab,$00 + DATA BYTE $ac,$00,$ad,$00,$ae,$00,$af,$00,$b0,$00,$b1,$00,$b2,$00,$b3,$00,$b4,$00,$b5,$00,$b6,$00,$b7,$00,$b8,$00,$b9,$00,$ba,$00,$bb,$00 + DATA BYTE $bc,$00,$bd,$00,$be,$00,$bf,$00,$c0,$00,$c1,$00,$c2,$00,$c3,$00,$c4,$00,$c5,$00,$c6,$00,$c7,$00,$c8,$00,$c9,$00,$ca,$00,$cb,$00 + DATA BYTE $6d,$00,$cc,$00,$cd,$00,$ce,$00,$cf,$00,$d0,$00,$d1,$00,$d2,$00,$d3,$00,$d4,$00,$d5,$00,$d6,$00,$d7,$00,$d8,$00,$d9,$00,$da,$00 + DATA BYTE $db,$00,$dc,$00,$dd,$00,$de,$00,$df,$00,$e0,$00,$e1,$00,$e2,$00,$e3,$00,$48,$00,$e4,$00,$e5,$00,$e6,$00,$e7,$00,$e8,$00,$e9,$00 + DATA BYTE $ea,$00,$eb,$00,$ec,$00,$ed,$00,$ee,$00,$ef,$00,$f0,$00,$f1,$00,$f2,$00,$48,$00,$f3,$00,$f4,$00,$f5,$00,$f6,$00,$f7,$00,$f8,$00 diff --git a/examples/oscar_compressed_sms.bas b/examples/oscar_compressed_sms.bas new file mode 100644 index 0000000..6cc7adb --- /dev/null +++ b/examples/oscar_compressed_sms.bas @@ -0,0 +1,437 @@ + ' TMSColor 3.0 Apr/27/2025 + ' Command: ../tmscolor/tmscolor -sms -z -p2 -b -t64 oscar_sms.bmp ../cvbasic/examples/oscar_compressed_sms.bas + ' Created: Sun Apr 27 11:43:16 2025 + + ' Sega Master System lacks VRAM to show a full screen picture. + + ' Display image. + MODE 4 + DEFINE CHAR PLETTER 64,185,image_char + PALETTE 9,$0B + PALETTE 11,$1B + PALETTE 14,$2B + SCREEN image_pattern,0,200,16,12,16 + WHILE 1: WEND + + ' Start tile = 64. Total_tiles = 185 +image_char: + DATA BYTE $69,$b4,$ff,$00,$24,$8f,$03,$00 + DATA BYTE $e4,$03,$7f,$00,$00,$41,$1f,$00 + DATA BYTE $01,$ff,$fe,$ff,$dd,$03,$1f,$ba + DATA BYTE $61,$03,$00,$80,$80,$00,$02,$c0 + DATA BYTE $c0,$00,$c0,$40,$f0,$b0,$17,$f0 + DATA BYTE $00,$f0,$00,$01,$03,$04,$f0,$f4 + DATA BYTE $f4,$00,$f4,$33,$00,$79,$23,$de + DATA BYTE $03,$27,$80,$f9,$00,$80,$6f,$07 + DATA BYTE $22,$03,$f7,$00,$80,$f3,$00,$26 + DATA BYTE $80,$fb,$00,$34,$69,$0f,$03,$81 + DATA BYTE $8f,$a2,$03,$bf,$00,$f9,$13,$04 + DATA BYTE $8f,$03,$2a,$c7,$03,$ab,$e3,$03 + DATA BYTE $2f,$71,$03,$4f,$ae,$6a,$03,$f3 + DATA BYTE $00,$fe,$ec,$03,$00,$6e,$fc,$11 + DATA BYTE $03,$f8,$fd,$00,$00,$3f,$71,$00 + DATA BYTE $03,$04,$3b,$9c,$07,$b3,$29,$7b + DATA BYTE $00,$00,$de,$17,$01,$03,$0f,$b3 + DATA BYTE $b3,$bf,$07,$3f,$33,$1c,$03,$1b + DATA BYTE $64,$03,$7d,$03,$ff,$10,$fd,$ff + DATA BYTE $c0,$2e,$f9,$a0,$70,$30,$70,$f0 + DATA BYTE $a3,$60,$03,$ee,$ee,$e8,$00,$0e + DATA BYTE $e2,$e2,$e0,$80,$03,$44,$ec,$00 + DATA BYTE $80,$cc,$00,$00,$84,$96,$f8,$00 + DATA BYTE $5b,$f1,$00,$a0,$f3,$e6,$7b,$a2 + DATA BYTE $0b,$0f,$00,$20,$00,$07,$00,$80 + DATA BYTE $0f,$8f,$0f,$e0,$03,$a0,$1f,$bf + DATA BYTE $3f,$20,$b0,$0f,$03,$a0,$0f,$af + DATA BYTE $2f,$ed,$03,$51,$3b,$cf,$11,$00 + DATA BYTE $00,$c7,$00,$10,$c1,$18,$00,$04 + DATA BYTE $c0,$b5,$48,$f5,$00,$00,$fc,$bb + DATA BYTE $00,$07,$bb,$6f,$07,$8b,$b7,$bb + DATA BYTE $0b,$03,$e2,$a7,$61,$69,$03,$63 + DATA BYTE $e7,$30,$00,$61,$97,$98,$60,$17 + DATA BYTE $44,$40,$e8,$a7,$06,$41,$ec,$b8 + DATA BYTE $f1,$b3,$1a,$e8,$97,$c4,$bf,$cc + DATA BYTE $44,$83,$63,$66,$99,$07,$02,$46 + DATA BYTE $1d,$bf,$24,$c2,$cb,$77,$30,$03 + DATA BYTE $17,$bb,$c5,$cb,$e1,$f3,$bc,$74 + DATA BYTE $a3,$27,$aa,$85,$bb,$cf,$07,$ae + DATA BYTE $ce,$03,$a3,$27,$6f,$84,$87,$ef + DATA BYTE $f1,$0b,$68,$8f,$03,$48,$35,$07 + DATA BYTE $e6,$00,$7f,$e7,$03,$17,$a3,$31 + DATA BYTE $03,$f4,$0b,$e0,$8f,$03,$e4,$39 + DATA BYTE $03,$0f,$f2,$c2,$8f,$eb,$98,$00 + DATA BYTE $00,$e7,$64,$00,$ef,$00,$00,$5a + DATA BYTE $ed,$00,$2f,$03,$af,$00,$84,$af + DATA BYTE $20,$f0,$03,$d0,$f0,$20,$e1,$c1 + DATA BYTE $e0,$bb,$03,$0b,$8b,$03,$00,$e8 + DATA BYTE $00,$12,$f4,$f5,$4c,$bf,$12,$40 + DATA BYTE $e3,$00,$60,$00,$97,$b5,$80,$84 + DATA BYTE $e3,$fd,$02,$00,$7d,$7d,$7b,$07 + DATA BYTE $fb,$f9,$7f,$07,$1e,$ff,$fa,$ef + DATA BYTE $82,$fb,$df,$b7,$00,$18,$0f,$fe + DATA BYTE $9f,$6f,$f9,$8b,$a7,$88,$b7,$80 + DATA BYTE $2f,$88,$07,$30,$0f,$c7,$f8,$cf + DATA BYTE $83,$00,$03,$23,$23,$95,$db,$02 + DATA BYTE $c5,$a3,$bd,$03,$84,$b7,$20,$00 + DATA BYTE $c1,$e1,$e1,$60,$80,$e0,$e0,$40 + DATA BYTE $04,$08,$48,$48,$00,$78,$00,$00 + DATA BYTE $44,$79,$00,$80,$79,$b0,$7a,$2d + DATA BYTE $0b,$7d,$00,$11,$87,$7e,$69,$00 + DATA BYTE $0b,$c6,$ab,$ee,$98,$00,$00,$a7 + DATA BYTE $04,$41,$a7,$a7,$00,$27,$97,$b3 + DATA BYTE $b7,$17,$01,$af,$a8,$b7,$27,$ff + DATA BYTE $f9,$f7,$10,$87,$fb,$ff,$0b,$46 + DATA BYTE $0c,$bf,$0c,$c0,$8f,$22,$06,$8f + DATA BYTE $00,$00,$87,$00,$01,$c0,$fb,$bb + DATA BYTE $d3,$f0,$fe,$0e,$07,$e3,$83,$cb + DATA BYTE $c4,$a3,$64,$c7,$03,$40,$9d,$03 + DATA BYTE $17,$c9,$f3,$c2,$af,$f0,$c7,$0b + DATA BYTE $a8,$85,$b7,$fd,$03,$f3,$8f,$3c + DATA BYTE $78,$03,$26,$7a,$fd,$03,$b8,$1b + DATA BYTE $07,$bc,$ff,$30,$07,$b8,$93,$99 + DATA BYTE $98,$03,$bc,$ab,$4c,$3e,$03,$63 + DATA BYTE $1e,$03,$5f,$1e,$03,$1c,$7f,$03 + DATA BYTE $17,$d7,$ce,$00,$3f,$03,$ff,$9b + DATA BYTE $af,$c2,$f3,$63,$c0,$03,$88,$1c + DATA BYTE $03,$08,$e7,$5e,$03,$c3,$12,$e0 + DATA BYTE $cb,$c7,$cf,$f4,$d7,$5e,$03,$5a + DATA BYTE $fa,$00,$72,$03,$97,$a2,$81,$00 + DATA BYTE $00,$89,$00,$2c,$00,$ad,$00,$23 + DATA BYTE $07,$ce,$01,$de,$de,$df,$d3,$93 + DATA BYTE $d8,$03,$e3,$46,$ff,$03,$70,$07 + DATA BYTE $03,$83,$7f,$7c,$22,$ff,$c2,$f7 + DATA BYTE $00,$fb,$c0,$f1,$b1,$f0,$c0,$f8 + DATA BYTE $b8,$3a,$f8,$c0,$8f,$78,$9f,$e5 + DATA BYTE $ee,$00,$c4,$00,$d8,$d8,$18,$00 + DATA BYTE $f8,$f8,$64,$20,$9b,$b0,$40,$63 + DATA BYTE $e0,$0c,$00,$3f,$31,$2f,$0c,$6f + DATA BYTE $61,$6f,$00,$4f,$01,$00,$00,$93 + DATA BYTE $00,$40,$90,$b7,$00,$fb,$00,$8b + DATA BYTE $e3,$b8,$03,$fb,$96,$30,$00,$88 + DATA BYTE $4f,$03,$00,$01,$03,$11,$02,$03 + DATA BYTE $05,$03,$07,$31,$80,$d7,$21,$dc + DATA BYTE $83,$48,$8f,$5e,$1f,$8f,$03,$f8 + DATA BYTE $07,$a3,$7e,$df,$a6,$3c,$31,$03 + DATA BYTE $0e,$03,$03,$ae,$20,$1b,$07,$cf + DATA BYTE $d0,$e3,$98,$0a,$03,$02,$c6,$03 + DATA BYTE $82,$f1,$a3,$f3,$8b,$c9,$86,$16 + DATA BYTE $e7,$0b,$cf,$9c,$37,$0b,$e6,$03 + DATA BYTE $1f,$1b,$03,$9f,$7f,$37,$07,$0f + DATA BYTE $1d,$03,$07,$73,$f8,$e7,$4f,$3f + DATA BYTE $e3,$8f,$fc,$eb,$2e,$cb,$06,$f0 + DATA BYTE $e3,$0f,$fc,$7a,$a7,$77,$e9,$c7 + DATA BYTE $e6,$cb,$4a,$e1,$00,$01,$a2,$1c + DATA BYTE $f5,$b5,$21,$01,$67,$66,$67,$b2 + DATA BYTE $ff,$dd,$00,$ff,$80,$10,$6f,$6f + DATA BYTE $7f,$18,$c7,$f9,$56,$80,$51,$03 + DATA BYTE $00,$2f,$18,$fe,$e6,$fc,$08,$fe + DATA BYTE $f6,$09,$fe,$08,$e6,$e6,$d3,$57 + DATA BYTE $ce,$00,$16,$e3,$84,$e7,$b8,$0b + DATA BYTE $b8,$38,$00,$18,$00,$f8,$03,$0e + DATA BYTE $2f,$54,$21,$83,$2f,$70,$2f,$03 + DATA BYTE $27,$00,$37,$8b,$00,$00,$b7,$00 + DATA BYTE $45,$07,$27,$00,$a5,$bb,$6f,$66 + DATA BYTE $00,$c7,$82,$e0,$f3,$01,$f3,$f1 + DATA BYTE $a9,$43,$f7,$97,$01,$a1,$c0,$81 + DATA BYTE $f1,$aa,$12,$ef,$e0,$00,$60,$60 + DATA BYTE $71,$f0,$f8,$e0,$00,$f8,$70,$fe + DATA BYTE $ee,$fe,$03,$07,$04,$80,$ac,$0f + DATA BYTE $08,$0e,$07,$05,$0f,$0a,$4d,$00 + DATA BYTE $0f,$07,$1f,$18,$0f,$05,$1f,$1a + DATA BYTE $0e,$0f,$0d,$17,$12,$03,$7f,$1f + DATA BYTE $17,$ef,$7d,$53,$03,$13,$ab,$bf + DATA BYTE $d6,$9b,$1d,$c2,$e3,$5e,$0f,$6d + DATA BYTE $89,$03,$05,$9a,$74,$1b,$43,$01 + DATA BYTE $8e,$00,$47,$3b,$3b,$fb,$f0,$0d + DATA BYTE $0d,$f9,$ca,$03,$e7,$40,$04,$04 + DATA BYTE $fc,$f0,$0c,$0c,$70,$f0,$03,$20 + DATA BYTE $dc,$dc,$80,$a8,$1c,$1c,$7c,$e0 + DATA BYTE $e7,$4f,$bc,$18,$07,$1a,$87,$f0 + DATA BYTE $c3,$ca,$00,$10,$0b,$07,$f0,$e3 + DATA BYTE $9b,$01,$90,$6f,$f9,$63,$ab,$22 + DATA BYTE $77,$03,$98,$67,$03,$35,$10,$ef + DATA BYTE $89,$e7,$3f,$ae,$73,$07,$03,$f4 + DATA BYTE $1c,$4b,$f4,$eb,$5d,$0b,$b8,$03 + DATA BYTE $f0,$e4,$d7,$cf,$1b,$9b,$d3,$e2 + DATA BYTE $ef,$72,$02,$ab,$3c,$3f,$ab,$ee + DATA BYTE $03,$ee,$0b,$83,$75,$bc,$00,$14 + DATA BYTE $c3,$00,$00,$5c,$a0,$00,$e3,$3a + DATA BYTE $4a,$eb,$46,$00,$e2,$e3,$c9,$bf + DATA BYTE $16,$e6,$00,$66,$00,$88,$03,$2e + DATA BYTE $00,$00,$3e,$b8,$00,$bb,$98,$01 + DATA BYTE $9f,$65,$00,$08,$00,$a1,$eb,$7c + DATA BYTE $00,$60,$b8,$00,$cf,$c3,$c7,$ef + DATA BYTE $e8,$ef,$9c,$f9,$0c,$1f,$45,$13 + DATA BYTE $95,$38,$26,$0f,$2f,$04,$0f,$00 + DATA BYTE $0b,$0f,$24,$7e,$5a,$2e,$e4,$fe + DATA BYTE $38,$1a,$e6,$03,$e0,$f6,$18,$16 + DATA BYTE $e6,$f4,$c5,$00,$b7,$fc,$7f,$fc + DATA BYTE $97,$8c,$03,$fe,$82,$d9,$06,$df + DATA BYTE $3e,$0f,$cf,$a3,$2c,$f1,$a6,$10 + DATA BYTE $13,$e3,$11,$11,$03,$05,$87,$16 + DATA BYTE $e4,$11,$f2,$81,$f0,$19,$64,$64 + DATA BYTE $18,$03,$0d,$d7,$03,$8c,$77,$02 + DATA BYTE $76,$00,$12,$2f,$2d,$1f,$b1,$0e + DATA BYTE $0e,$3f,$40,$a7,$0b,$3f,$b6,$19 + DATA BYTE $09,$3e,$10,$9f,$70,$60,$d0,$00 + DATA BYTE $60,$40,$7f,$3c,$63,$43,$7c,$04 + DATA BYTE $70,$ce,$8e,$70,$40,$da,$1c,$87 + DATA BYTE $dd,$ab,$98,$df,$70,$06,$cc,$33 + DATA BYTE $33,$68,$fc,$0f,$c5,$1c,$c5,$00 + DATA BYTE $28,$af,$1d,$8b,$c0,$db,$db,$ff + DATA BYTE $3d,$42,$17,$42,$3f,$1d,$ff,$c1 + DATA BYTE $a9,$04,$fa,$bd,$60,$e5,$e5,$1e + DATA BYTE $32,$cd,$3b,$cd,$3e,$03,$94,$1f + DATA BYTE $c0,$51,$cb,$38,$19,$80,$82,$da + DATA BYTE $37,$ba,$1f,$33,$f2,$0a,$ca,$ca + DATA BYTE $1f,$03,$9e,$5c,$07,$e7,$40,$60 + DATA BYTE $98,$98,$e0,$01,$82,$9f,$b2,$52 + DATA BYTE $38,$38,$03,$c0,$93,$43,$02,$92 + DATA BYTE $60,$03,$0f,$82,$7c,$7c,$30,$80 + DATA BYTE $20,$e3,$58,$04,$03,$0c,$cf,$03 + DATA BYTE $87,$f3,$e3,$df,$eb,$c3,$e2,$e3 + DATA BYTE $f8,$f7,$89,$04,$f3,$84,$8b,$10 + DATA BYTE $e3,$df,$ed,$5b,$6e,$13,$e3,$26 + DATA BYTE $3b,$3c,$03,$1b,$97,$76,$1f,$6f + DATA BYTE $3f,$3c,$9f,$c7,$39,$cc,$3d,$f7 + DATA BYTE $fb,$d8,$03,$13,$80,$ce,$c7,$67 + DATA BYTE $80,$5f,$f2,$cf,$71,$6f,$10,$0f + DATA BYTE $85,$b7,$c5,$f7,$d8,$f7,$4f,$99 + DATA BYTE $00,$0e,$97,$c5,$02,$cf,$00,$9d + DATA BYTE $3b,$9f,$dc,$43,$fd,$ec,$07,$9f + DATA BYTE $52,$f7,$01,$26,$8b,$b8,$0c,$cd + DATA BYTE $1d,$ff,$01,$e2,$ff,$0d,$b3,$b2 + DATA BYTE $af,$10,$18,$8b,$f0,$e0,$c7,$00 + DATA BYTE $07,$e3,$80,$e1,$61,$a1,$c0,$e3 + DATA BYTE $38,$23,$e1,$a9,$bb,$59,$af,$8d + DATA BYTE $04,$9a,$e0,$10,$c1,$d2,$54,$86 + DATA BYTE $82,$07,$fb,$5f,$15,$f3,$f7,$8c + DATA BYTE $03,$e7,$db,$d2,$07,$90,$6a,$26 + DATA BYTE $97,$78,$07,$ff,$0e,$b7,$8b,$d7 + DATA BYTE $c2,$cf,$c0,$c0,$33,$c0,$dc,$00 + DATA BYTE $dc,$63,$c7,$43,$9f,$3b,$03,$07 + DATA BYTE $a9,$4f,$07,$a1,$43,$2f,$ff,$d0 + DATA BYTE $3f,$88,$e3,$08,$14,$01,$14,$08 + DATA BYTE $0c,$f1,$f1,$ac,$1c,$1b,$d6,$fd + DATA BYTE $4a,$03,$d2,$d8,$fd,$a7,$57,$b0 + DATA BYTE $a0,$e0,$7b,$48,$f7,$b7,$f8,$06 + DATA BYTE $71,$ff,$8e,$ff,$60,$23,$3d,$20 + DATA BYTE $bd,$bf,$3d,$24,$ff,$00,$04,$b1 + DATA BYTE $00,$a7,$81,$e1,$e4,$1b,$1b,$e7 + DATA BYTE $f6,$17,$68,$0f,$83,$1c,$03,$30 + DATA BYTE $81,$f6,$3c,$84,$e7,$be,$4c,$f2 + DATA BYTE $bf,$fe,$01,$e2,$1d,$1d,$fe,$c2 + DATA BYTE $3d,$3d,$a2,$03,$82,$d2,$b2,$fe + DATA BYTE $83,$bf,$2a,$2f,$92,$28,$cb,$82 + DATA BYTE $d0,$d0,$10,$50,$96,$50,$50,$64 + DATA BYTE $9b,$9b,$11,$64,$7c,$83,$15,$3f + DATA BYTE $c0,$1f,$91,$d9,$03,$a3,$b0,$f0 + DATA BYTE $49,$8f,$50,$03,$3f,$03,$9c,$9c + DATA BYTE $00,$e1,$0f,$fc,$02,$02,$22,$05 + DATA BYTE $03,$5d,$f8,$07,$e5,$0f,$34,$e3 + DATA BYTE $3f,$20,$02,$b3,$b3,$33,$20,$bd + DATA BYTE $bd,$e3,$51,$a7,$a7,$27,$c0,$0f + DATA BYTE $00,$a3,$a3,$22,$00,$25,$a1,$a1 + DATA BYTE $eb,$5c,$f9,$00,$e7,$45,$00,$9f + DATA BYTE $00,$a8,$bb,$13,$df,$be,$f2,$ce + DATA BYTE $57,$03,$36,$af,$f7,$a3,$22,$84 + DATA BYTE $00,$00,$44,$00,$d1,$9f,$bb,$03 + DATA BYTE $96,$13,$f7,$00,$a2,$1f,$41,$00 + DATA BYTE $30,$00,$10,$85,$80,$f6,$f6,$e0 + DATA BYTE $68,$7e,$76,$29,$78,$08,$1a,$13 + DATA BYTE $af,$40,$00,$43,$bd,$bf,$02,$d7 + DATA BYTE $d5,$10,$d7,$00,$83,$00,$40,$0a + DATA BYTE $6a,$0b,$0a,$40,$02,$42,$aa,$50 + DATA BYTE $40,$00,$ca,$ff,$75,$b8,$d4,$ff + DATA BYTE $71,$c5,$f3,$5d,$30,$bb,$2d,$85 + DATA BYTE $f3,$e1,$eb,$e3,$fe,$0c,$10,$3d + DATA BYTE $0c,$43,$b6,$9d,$00,$f3,$ee,$28 + DATA BYTE $e7,$eb,$b8,$d7,$95,$e0,$a1,$b3 + DATA BYTE $e1,$bb,$95,$20,$5b,$00,$ca,$fb + DATA BYTE $e3,$c9,$03,$10,$08,$00,$82,$3c + DATA BYTE $3c,$f8,$f1,$db,$4c,$80,$3e,$2f + DATA BYTE $e7,$03,$9e,$04,$b8,$8b,$a1,$30 + DATA BYTE $78,$7c,$04,$74,$93,$9b,$d0,$0b + DATA BYTE $68,$68,$40,$c6,$3b,$70,$8f,$9b + DATA BYTE $6d,$49,$03,$54,$0a,$13,$17,$82 + DATA BYTE $b8,$e7,$41,$21,$27,$06,$27,$dd + DATA BYTE $32,$bb,$cc,$0c,$03,$76,$de,$03 + DATA BYTE $30,$0e,$1e,$07,$17,$88,$4b,$88 + DATA BYTE $e7,$1e,$63,$1f,$43,$12,$af,$03 + DATA BYTE $e3,$10,$9f,$13,$2c,$2c,$92,$94 + DATA BYTE $1e,$30,$0f,$03,$9e,$77,$89,$ef + DATA BYTE $bd,$36,$c3,$62,$08,$8b,$4e,$36 + DATA BYTE $fe,$fb,$14,$f1,$7b,$f1,$5e,$27 + DATA BYTE $f7,$ff,$0c,$7e,$81,$81,$ff,$8f + DATA BYTE $28,$9d,$c0,$20,$20,$df,$26,$d9 + DATA BYTE $d9,$07,$3e,$44,$bb,$bb,$7c,$51 + DATA BYTE $4b,$0d,$af,$f1,$e3,$77,$0b,$07 + DATA BYTE $07,$c6,$39,$39,$fe,$10,$df,$38 + DATA BYTE $c6,$c6,$2f,$38,$80,$ce,$22,$80 + DATA BYTE $40,$a3,$71,$c0,$e3,$02,$1b,$e4 + DATA BYTE $e4,$1f,$5f,$ff,$26,$5f,$53,$fb + DATA BYTE $0f,$90,$03,$07,$db,$57,$e6,$00 + DATA BYTE $bf,$1f,$0a,$f5,$3b,$f5,$0a,$11 + DATA BYTE $c6,$03,$f1,$3b,$a3,$e1,$b0,$03 + DATA BYTE $99,$dc,$c1,$03,$02,$04,$fd,$fd + DATA BYTE $03,$04,$c1,$e8,$e0,$0c,$91,$9d + DATA BYTE $9d,$7c,$44,$81,$0c,$2d,$90,$80 + DATA BYTE $64,$3c,$81,$03,$3e,$61,$81,$80 + DATA BYTE $a2,$80,$03,$1d,$80,$17,$d2,$bf + DATA BYTE $6b,$63,$00,$a7,$f3,$00,$03,$30 + DATA BYTE $e1,$f1,$e1,$18,$e1,$00,$fb,$e1 + DATA BYTE $09,$d0,$df,$d0,$04,$18,$48,$1e + DATA BYTE $fc,$e2,$92,$00,$02,$f3,$13,$e2 + DATA BYTE $83,$21,$c3,$09,$bb,$80,$c3,$e7 + DATA BYTE $c8,$03,$0c,$0f,$80,$04,$18,$31 + DATA BYTE $31,$11,$cf,$e2,$79,$00,$77,$00 + DATA BYTE $d2,$03,$c2,$30,$1f,$40,$8f,$8f + DATA BYTE $87,$9a,$06,$03,$02,$0d,$0f,$8c + DATA BYTE $03,$01,$5a,$63,$01,$2f,$18,$33 + DATA BYTE $2f,$67,$a3,$bf,$63,$b7,$f3,$03 + DATA BYTE $8b,$e3,$e2,$03,$40,$24,$00,$21 + DATA BYTE $00,$7c,$00,$00,$74,$74,$12,$ab + DATA BYTE $34,$00,$e6,$c3,$65,$e0,$b7,$23 + DATA BYTE $e2,$47,$0d,$60,$b4,$dd,$5f,$5f + DATA BYTE $09,$4f,$00,$17,$17,$db,$96,$47 + DATA BYTE $00,$31,$cf,$86,$08,$0a,$d3,$02 + DATA BYTE $eb,$73,$7e,$80,$b2,$03,$db,$ee + DATA BYTE $40,$03,$5e,$70,$3a,$a2,$00,$01 + DATA BYTE $01,$e2,$e4,$e2,$0a,$0e,$70,$00 + DATA BYTE $12,$2f,$70,$50,$2c,$11,$00,$0d + DATA BYTE $18,$bf,$a7,$bf,$2c,$fb,$fc,$ec + DATA BYTE $68,$fc,$97,$16,$51,$87,$cf,$dc + DATA BYTE $07,$e3,$48,$03,$07,$83,$01,$00 + DATA BYTE $c2,$c2,$c3,$01,$62,$62,$63,$01 + DATA BYTE $96,$db,$12,$89,$db,$06,$96,$cf + DATA BYTE $0e,$c0,$03,$02,$f9,$06,$06,$72 + DATA BYTE $f9,$eb,$f1,$f7,$53,$cc,$91,$dd + DATA BYTE $d5,$9d,$77,$61,$03,$13,$f7,$7f + DATA BYTE $47,$83,$a1,$0d,$ee,$82,$bb,$8b + DATA BYTE $a0,$c7,$c7,$e0,$13,$ad,$c3,$f3 + DATA BYTE $dd,$c3,$cf,$83,$d8,$07,$ff,$c0 + DATA BYTE $f0,$3c,$c3,$c3,$fc,$c8,$97,$64 + DATA BYTE $78,$27,$72,$7e,$83,$cb,$88,$cf + DATA BYTE $d8,$27,$3b,$27,$f8,$4b,$15,$bf + DATA BYTE $08,$dd,$17,$03,$84,$cf,$02,$0c + DATA BYTE $06,$0b,$09,$06,$f7,$22,$0e,$88 + DATA BYTE $ee,$10,$8c,$8c,$73,$73,$63,$8c + DATA BYTE $17,$03,$4a,$03,$b6,$b6,$03,$1a + DATA BYTE $fb,$fb,$0b,$46,$03,$6b,$07,$18 + DATA BYTE $70,$03,$cf,$31,$1e,$03,$17,$8f + DATA BYTE $03,$05,$08,$03,$24,$c8,$00,$04 + DATA BYTE $da,$89,$00,$04,$db,$00,$c0,$84 + DATA BYTE $e3,$80,$00,$39,$3d,$39,$84,$3a + DATA BYTE $3e,$3a,$08,$c1,$ef,$e6,$03,$10 + DATA BYTE $f5,$b3,$04,$71,$71,$01,$08,$03 + DATA BYTE $09,$53,$00,$af,$08,$8c,$ba,$ba + DATA BYTE $aa,$af,$5b,$00,$4a,$d3,$40,$2f + DATA BYTE $00,$02,$21,$23,$23,$02,$43,$01 + DATA BYTE $84,$61,$7c,$90,$20,$c1,$cc,$e1 + DATA BYTE $bb,$22,$38,$fc,$00,$1d,$fc,$b0 + DATA BYTE $0e,$0b,$de,$03,$7c,$40,$8b,$58 + DATA BYTE $87,$05,$f9,$7c,$23,$91,$bb,$42 + DATA BYTE $bc,$4e,$00,$b0,$ac,$82,$80,$2e + DATA BYTE $01,$90,$00,$9c,$2d,$08,$a0,$26 + DATA BYTE $26,$b1,$22,$83,$d8,$38,$0a,$72 + DATA BYTE $05,$07,$05,$06,$e0,$06,$00,$ce + DATA BYTE $16,$bf,$b2,$dc,$03,$63,$7f,$03 + DATA BYTE $3f,$7c,$e6,$27,$c0,$3f,$b7,$8c + DATA BYTE $27,$0f,$f2,$67,$07,$46,$c7,$31 + DATA BYTE $03,$5b,$03,$1b,$8f,$03,$1f,$3b + DATA BYTE $1b,$03,$03,$b2,$3e,$70,$96,$39 + DATA BYTE $00,$20,$f6,$44,$47,$9b,$71,$03 + DATA BYTE $c3,$73,$83,$61,$a3,$32,$3f,$f7 + DATA BYTE $8a,$1f,$0e,$87,$c9,$0f,$06,$a7 + DATA BYTE $80,$07,$03,$0c,$0c,$03,$41,$41 + DATA BYTE $02,$f5,$c5,$c3,$85,$97,$e9,$f7 + DATA BYTE $5f,$57,$fb,$76,$b7,$68,$63,$03 + DATA BYTE $67,$bb,$a3,$4b,$f3,$ef,$2f,$b2 + DATA BYTE $03,$c3,$d8,$ff,$c7,$4d,$88,$3f + DATA BYTE $8f,$ec,$29,$c3,$47,$01,$60,$03 + DATA BYTE $9a,$f7,$d3,$2b,$38,$77,$d6,$a5 + DATA BYTE $f7,$09,$03,$7d,$83,$82,$03,$03 + DATA BYTE $1b,$fb,$fd,$ce,$03,$97,$50,$e1 + DATA BYTE $1f,$1e,$1f,$e2,$c3,$60,$00,$03 + DATA BYTE $80,$db,$5b,$85,$03,$fb,$7b,$fb + DATA BYTE $bb,$b7,$77,$d9,$03,$4f,$ba,$3c + DATA BYTE $03,$01,$03,$6b,$1f,$8c,$1b,$40 + DATA BYTE $03,$ee,$cf,$78,$f0,$03,$1c,$ce + DATA BYTE $cb,$23,$3f,$fe,$07,$7e,$ff,$67 + DATA BYTE $03,$7f,$99,$03,$12,$46,$d3,$22 + DATA BYTE $00,$b8,$c3,$5d,$7c,$03,$07,$30 + DATA BYTE $03,$bc,$03,$3c,$7e,$98,$00,$3d + DATA BYTE $03,$3e,$c6,$00,$1e,$68,$03,$ca + DATA BYTE $32,$af,$d3,$ee,$15,$cb,$03,$11 + DATA BYTE $07,$04,$c2,$cb,$00,$07,$c1,$2f + DATA BYTE $2e,$2f,$c2,$23,$03,$21,$22,$c3 + DATA BYTE $23,$20,$23,$89,$8b,$07,$bd,$03 + DATA BYTE $46,$e7,$b4,$0b,$b2,$7c,$a7,$5b + DATA BYTE $a3,$03,$7f,$ef,$17,$f1,$03,$01 + DATA BYTE $e3,$07,$fe,$c6,$03,$fc,$26,$03 + DATA BYTE $ee,$fd,$cb,$a7,$8e,$bd,$e9,$58 + DATA BYTE $a6,$78,$e4,$b9,$e8,$bd,$67,$b3 + DATA BYTE $7a,$01,$31,$0e,$04,$01,$02,$96 + DATA BYTE $01,$15,$ca,$17,$60,$f3,$01,$7f + DATA BYTE $12,$ed,$ed,$1e,$1c,$d4,$8a,$5f + DATA BYTE $d5,$3a,$57,$01,$94,$e3,$e0,$c1 + DATA BYTE $d7,$d8,$df,$a4,$c2,$f6,$20,$aa + DATA BYTE $e3,$4d,$2c,$f0,$f1,$16,$f2,$7e + DATA BYTE $ef,$0c,$d3,$bd,$44,$ab,$52,$05 + DATA BYTE $67,$0b,$20,$83,$56,$61,$13,$e3 + DATA BYTE $01,$14,$03,$80,$5f,$ae,$78,$e2 + DATA BYTE $ac,$f1,$03,$66,$d0,$97,$31,$f0 + DATA BYTE $23,$e1,$81,$83,$c5,$e7,$12,$b3 + DATA BYTE $bf,$eb,$3f,$4d,$03,$89,$c7,$60 + DATA BYTE $e1,$e3,$74,$03,$89,$9b,$b1,$00 + DATA BYTE $fc,$fe,$8f,$00,$ff,$59,$00,$1e + DATA BYTE $84,$cb,$1e,$c7,$07,$3c,$9d,$03 + DATA BYTE $0b,$bc,$9f,$e0,$41,$33,$32,$23 + DATA BYTE $00,$4c,$30,$00,$01,$03,$48,$05 + DATA BYTE $02,$20,$b3,$2e,$00,$bf,$05,$06 + DATA BYTE $83,$fc,$03,$10,$63,$02,$e7,$31 + DATA BYTE $73,$0f,$d2,$8f,$03,$d0,$18,$03 + DATA BYTE $d3,$03,$d8,$c6,$03,$49,$6f,$2b + DATA BYTE $13,$cf,$1f,$ab,$97,$c6,$03,$bf + DATA BYTE $b8,$cb,$4d,$3f,$70,$f7,$99,$fc + DATA BYTE $05,$cc,$03,$e0,$03,$68,$60,$11 + DATA BYTE $be,$c6,$03,$d7,$31,$03,$d6,$03 + DATA BYTE $db,$c5,$85,$f9,$03,$f4,$81,$7d + DATA BYTE $0f,$ac,$00,$10,$f1,$07,$02,$e1 + DATA BYTE $83,$7c,$f9,$4c,$20,$01,$a6,$1b + DATA BYTE $01,$18,$2e,$01,$0c,$01,$ff,$2d + DATA BYTE $6f,$34,$9b,$e1,$a8,$03,$ee,$f4 + DATA BYTE $4f,$71,$20,$c7,$00,$62,$67,$02 + DATA BYTE $04,$c3,$c7,$03,$f4,$03,$21,$83 + DATA BYTE $87,$5e,$87,$8f,$07,$15,$e0,$ca + DATA BYTE $dd,$a7,$1d,$b1,$8c,$30,$9b,$91 + DATA BYTE $70,$80,$c0,$4d,$b7,$88,$d6,$af + DATA BYTE $e7,$87,$45,$e0,$46,$00,$9b,$f8 + DATA BYTE $11,$f0,$a1,$7f,$e0,$14,$01,$3f + DATA BYTE $82,$5d,$f0,$31,$00,$01,$03,$8b + DATA BYTE $8c,$03,$8f,$03,$79,$af,$03,$bc + DATA BYTE $ab,$56,$2a,$ac,$00,$fe,$f9,$ab + DATA BYTE $b1,$03,$f8,$e3,$03,$fc,$ef,$03 + DATA BYTE $f1,$9f,$f9,$03,$06,$94,$93,$02 + DATA BYTE $ce,$03,$07,$22,$00,$98,$00,$00 + DATA BYTE $f9,$00,$d2,$df,$30,$03,$90,$ff + DATA BYTE $b1,$ee,$4d,$84,$c3,$0f,$c2,$fb + DATA BYTE $e6,$03,$0c,$34,$03,$06,$b7,$0b + DATA BYTE $00,$8b,$07,$00,$f1,$00,$5e,$b7 + DATA BYTE $66,$0d,$31,$03,$29,$03,$55,$ae + DATA BYTE $13,$e3,$fe,$c3,$ab,$63,$f6,$03 + DATA BYTE $88,$3f,$03,$ff,$ff,$ff,$f0 + + ' Width = 16, height = 12 +image_pattern: + DATA BYTE $40,$00,$41,$00,$42,$00,$43,$00,$44,$00,$45,$00,$46,$00,$47,$00,$48,$00,$48,$00,$48,$00,$49,$00,$4a,$00,$4b,$00,$4c,$00,$4d,$00 + DATA BYTE $4e,$00,$4f,$00,$50,$00,$51,$00,$52,$00,$53,$00,$54,$00,$55,$00,$56,$00,$48,$00,$48,$00,$57,$00,$58,$00,$59,$00,$5a,$00,$5b,$00 + DATA BYTE $5c,$00,$5d,$00,$5e,$00,$5f,$00,$60,$00,$61,$00,$62,$00,$63,$00,$64,$00,$65,$00,$66,$00,$67,$00,$68,$00,$69,$00,$6a,$00,$6b,$00 + DATA BYTE $6c,$00,$6d,$00,$6e,$00,$6f,$00,$70,$00,$71,$00,$72,$00,$73,$00,$74,$00,$75,$00,$76,$00,$77,$00,$78,$00,$79,$00,$7a,$00,$7b,$00 + DATA BYTE $7c,$00,$7d,$00,$7e,$00,$7f,$00,$80,$00,$81,$00,$82,$00,$83,$00,$84,$00,$85,$00,$86,$00,$87,$00,$88,$00,$89,$00,$8a,$00,$8b,$00 + DATA BYTE $8c,$00,$8d,$00,$8e,$00,$8f,$00,$90,$00,$91,$00,$92,$00,$93,$00,$94,$00,$95,$00,$96,$00,$97,$00,$98,$00,$99,$00,$9a,$00,$9b,$00 + DATA BYTE $9c,$00,$9d,$00,$9e,$00,$9f,$00,$a0,$00,$a1,$00,$a2,$00,$a3,$00,$a4,$00,$a5,$00,$a6,$00,$a7,$00,$a8,$00,$a9,$00,$aa,$00,$ab,$00 + DATA BYTE $ac,$00,$ad,$00,$ae,$00,$af,$00,$b0,$00,$b1,$00,$b2,$00,$b3,$00,$b4,$00,$b5,$00,$b6,$00,$b7,$00,$b8,$00,$b9,$00,$ba,$00,$bb,$00 + DATA BYTE $bc,$00,$bd,$00,$be,$00,$bf,$00,$c0,$00,$c1,$00,$c2,$00,$c3,$00,$c4,$00,$c5,$00,$c6,$00,$c7,$00,$c8,$00,$c9,$00,$ca,$00,$cb,$00 + DATA BYTE $6d,$00,$cc,$00,$cd,$00,$ce,$00,$cf,$00,$d0,$00,$d1,$00,$d2,$00,$d3,$00,$d4,$00,$d5,$00,$d6,$00,$d7,$00,$d8,$00,$d9,$00,$da,$00 + DATA BYTE $db,$00,$dc,$00,$dd,$00,$de,$00,$df,$00,$e0,$00,$e1,$00,$e2,$00,$e3,$00,$48,$00,$e4,$00,$e5,$00,$e6,$00,$e7,$00,$e8,$00,$e9,$00 + DATA BYTE $ea,$00,$eb,$00,$ec,$00,$ed,$00,$ee,$00,$ef,$00,$f0,$00,$f1,$00,$f2,$00,$48,$00,$f3,$00,$f4,$00,$f5,$00,$f6,$00,$f7,$00,$f8,$00 diff --git a/examples/oscar_sms.bas b/examples/oscar_sms.bas new file mode 100644 index 0000000..213c3bf --- /dev/null +++ b/examples/oscar_sms.bas @@ -0,0 +1,772 @@ + ' TMSColor 3.0 Apr/27/2025 + ' Command: ../tmscolor/tmscolor -sms -p2 -b -t64 oscar_sms.bmp ../cvbasic/examples/oscar_sms.bas + ' Created: Sun Apr 27 11:43:16 2025 + + ' Sega Master System lacks VRAM to show a full screen picture. + + ' Display image. + MODE 4 + DEFINE CHAR 64,185,image_char + PALETTE 9,$0B + PALETTE 11,$1B + PALETTE 14,$2B + SCREEN image_pattern,0,200,16,12,16 + WHILE 1: WEND + + ' Start tile = 64. Total_tiles = 185 +image_char: + DATA BYTE $b4,$ff,$ff,$ff,$24,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$7f,$7f,$7f,$00,$1f,$1f,$1f + DATA BYTE $01,$ff,$fe,$ff,$01,$ff,$fe,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$00,$00,$00,$80,$80,$00,$80 + DATA BYTE $c0,$c0,$00,$c0,$40,$f0,$b0,$f0 + DATA BYTE $00,$f0,$f0,$f0,$00,$f0,$f0,$f0 + DATA BYTE $04,$f0,$f4,$f4,$00,$f4,$f4,$f4 + DATA BYTE $79,$ff,$ff,$ff,$79,$ff,$ff,$ff + DATA BYTE $79,$ff,$ff,$ff,$79,$ff,$ff,$ff + DATA BYTE $79,$ff,$ff,$ff,$79,$ff,$ff,$ff + DATA BYTE $79,$ff,$ff,$ff,$79,$ff,$ff,$ff + DATA BYTE $80,$f9,$f9,$f9,$80,$ff,$ff,$ff + DATA BYTE $80,$ff,$ff,$ff,$80,$ff,$ff,$ff + DATA BYTE $80,$ff,$ff,$ff,$80,$f7,$f7,$f7 + DATA BYTE $80,$f3,$f3,$f3,$80,$fb,$fb,$fb + DATA BYTE $34,$ff,$ff,$ff,$34,$ff,$ff,$ff + DATA BYTE $34,$7f,$7f,$7f,$34,$7f,$7f,$7f + DATA BYTE $34,$bf,$bf,$bf,$34,$ff,$ff,$ff + DATA BYTE $34,$ff,$ff,$ff,$04,$ff,$ff,$ff + DATA BYTE $2a,$ff,$ff,$ff,$2a,$ff,$ff,$ff + DATA BYTE $2a,$ff,$ff,$ff,$2a,$ff,$ff,$ff + DATA BYTE $ab,$ff,$ff,$ff,$ab,$ff,$ff,$ff + DATA BYTE $ab,$ff,$ff,$ff,$ab,$ff,$ff,$ff + DATA BYTE $2f,$ff,$ff,$ff,$2f,$ff,$ff,$ff + DATA BYTE $2f,$ff,$ff,$ff,$4f,$ff,$ff,$ff + DATA BYTE $4f,$ff,$ff,$ff,$4f,$ff,$ff,$ff + DATA BYTE $4f,$ff,$ff,$ff,$4f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$fe,$fe,$fe,$fe + DATA BYTE $fc,$fe,$fe,$fe,$fc,$fe,$fe,$fe + DATA BYTE $fc,$fe,$fe,$fe,$f8,$fd,$fd,$fd + DATA BYTE $00,$3f,$3f,$3f,$00,$3f,$3f,$3f + DATA BYTE $04,$3b,$3f,$3f,$00,$7f,$7f,$7f + DATA BYTE $00,$7b,$7b,$7b,$00,$fd,$fd,$fd + DATA BYTE $00,$fd,$fd,$fd,$00,$fd,$fd,$fd + DATA BYTE $0f,$b3,$b3,$bf,$07,$3f,$3b,$3f + DATA BYTE $03,$7f,$7f,$7f,$03,$7f,$7f,$7f + DATA BYTE $03,$7f,$7d,$7f,$03,$ff,$fd,$ff + DATA BYTE $c0,$3f,$3f,$f9,$a0,$70,$70,$f0 + DATA BYTE $00,$f4,$f4,$f0,$00,$ee,$ee,$e8 + DATA BYTE $00,$e2,$e2,$e0,$80,$e2,$e2,$e0 + DATA BYTE $80,$ec,$ec,$ec,$80,$cc,$cc,$cc + DATA BYTE $00,$f9,$f9,$f8,$00,$f1,$f1,$f1 + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$fe,$fe,$fe + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$0f,$0f,$0f,$00,$07,$07,$07 + DATA BYTE $80,$0f,$8f,$0f,$80,$0f,$8f,$0f + DATA BYTE $a0,$1f,$bf,$3f,$b0,$0f,$bf,$3f + DATA BYTE $a0,$0f,$af,$2f,$a0,$0f,$af,$2f + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$cf,$cf,$cf,$00,$c7,$c7,$c7 + DATA BYTE $10,$c1,$c1,$c1,$04,$c0,$c0,$c0 + DATA BYTE $00,$f5,$f5,$f5,$00,$fc,$fc,$fc + DATA BYTE $00,$f5,$f5,$f5,$00,$f1,$f1,$f1 + DATA BYTE $00,$f5,$f5,$f5,$00,$f4,$f4,$f4 + DATA BYTE $00,$f1,$f1,$f1,$00,$f1,$f1,$f1 + DATA BYTE $79,$ff,$ff,$ff,$79,$ff,$ff,$ff + DATA BYTE $69,$ff,$ff,$ff,$63,$e7,$e7,$e7 + DATA BYTE $61,$f3,$f3,$f3,$60,$f1,$f1,$f1 + DATA BYTE $44,$e8,$ec,$ec,$06,$ec,$ee,$ee + DATA BYTE $80,$ff,$ff,$ff,$80,$ff,$ff,$ff + DATA BYTE $e8,$97,$ff,$ff,$80,$ff,$ff,$ff + DATA BYTE $80,$ff,$ff,$ff,$cc,$83,$cf,$cf + DATA BYTE $66,$99,$ff,$ff,$02,$1d,$1f,$1f + DATA BYTE $24,$f7,$f7,$f7,$30,$f7,$f7,$f7 + DATA BYTE $30,$7f,$7f,$7f,$34,$ff,$ff,$ff + DATA BYTE $34,$ff,$ff,$ff,$34,$ff,$ff,$ff + DATA BYTE $24,$ff,$ff,$ff,$74,$ff,$ff,$ff + DATA BYTE $ab,$ff,$ff,$ff,$aa,$ff,$ff,$ff + DATA BYTE $2a,$ff,$ff,$ff,$aa,$ff,$ff,$ff + DATA BYTE $ae,$ff,$ff,$ff,$ae,$ff,$ff,$ff + DATA BYTE $ae,$ff,$ff,$ff,$ae,$ff,$ff,$ff + DATA BYTE $4f,$ff,$ff,$ff,$6f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ef,$ff,$ff,$ff + DATA BYTE $6f,$ff,$ff,$ff,$68,$ff,$ff,$ff + DATA BYTE $48,$ff,$ff,$ff,$68,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $7f,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $f8,$fd,$fd,$fd,$f8,$fd,$fd,$fd + DATA BYTE $f4,$ff,$ff,$ff,$e0,$ff,$ff,$ff + DATA BYTE $e4,$ff,$ff,$ff,$e4,$ff,$ff,$ff + DATA BYTE $f4,$ff,$ff,$ff,$f2,$ff,$ff,$ff + DATA BYTE $00,$eb,$eb,$eb,$00,$fb,$fb,$fb + DATA BYTE $00,$ef,$ef,$ef,$00,$ed,$ed,$ed + DATA BYTE $00,$ed,$ed,$ed,$00,$af,$af,$af + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $20,$f0,$d0,$f0,$20,$e1,$c1,$e0 + DATA BYTE $20,$e1,$c1,$e0,$20,$f0,$d0,$f0 + DATA BYTE $20,$f0,$d0,$f0,$00,$e8,$e8,$e8 + DATA BYTE $00,$80,$80,$80,$00,$c0,$c0,$c0 + DATA BYTE $40,$e3,$e3,$e3,$00,$e7,$e7,$e7 + DATA BYTE $80,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$fd,$02,$7d,$7d,$7b + DATA BYTE $07,$fb,$f9,$7f,$07,$ff,$fa,$ef + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$df,$df,$df + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$fe,$00,$fd,$fd,$f9 + DATA BYTE $a0,$0f,$af,$2f,$a0,$0f,$af,$2f + DATA BYTE $a0,$1f,$bf,$3f,$80,$2f,$af,$2f + DATA BYTE $30,$0f,$3f,$3f,$00,$07,$07,$07 + DATA BYTE $00,$03,$23,$23,$00,$00,$00,$00 + DATA BYTE $02,$c0,$c0,$c0,$00,$c0,$c0,$c0 + DATA BYTE $00,$c0,$c0,$c0,$00,$c0,$c0,$c0 + DATA BYTE $00,$c1,$c1,$c1,$20,$c1,$e1,$e1 + DATA BYTE $60,$80,$e0,$e0,$40,$08,$48,$48 + DATA BYTE $00,$78,$78,$78,$00,$79,$79,$79 + DATA BYTE $80,$79,$f9,$f9,$00,$78,$78,$78 + DATA BYTE $00,$7d,$7d,$7d,$00,$7f,$7f,$7f + DATA BYTE $00,$7e,$7e,$7e,$00,$7d,$7d,$7d + DATA BYTE $00,$fe,$fe,$fe,$00,$ee,$ee,$ee + DATA BYTE $00,$e3,$e3,$e3,$41,$a7,$e7,$e7 + DATA BYTE $27,$97,$b3,$b7,$17,$af,$a8,$b7 + DATA BYTE $27,$ff,$f9,$f7,$34,$ff,$fb,$ff + DATA BYTE $0b,$0c,$0f,$0f,$0c,$ff,$ff,$ff + DATA BYTE $06,$8f,$8f,$8f,$00,$87,$87,$87 + DATA BYTE $c0,$fb,$bb,$d3,$f0,$fe,$0e,$f0 + DATA BYTE $00,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $74,$ff,$ff,$ff,$64,$ff,$ff,$ff + DATA BYTE $40,$ff,$ff,$ff,$40,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$3f,$3f,$3f + DATA BYTE $00,$ef,$ef,$ef,$f0,$ff,$ff,$ff + DATA BYTE $a8,$ff,$ff,$ff,$aa,$ff,$ff,$ff + DATA BYTE $aa,$ff,$ff,$ff,$aa,$ff,$ff,$ff + DATA BYTE $aa,$ff,$ff,$ff,$aa,$ff,$ff,$ff + DATA BYTE $2a,$ff,$ff,$ff,$2a,$ff,$ff,$ff + DATA BYTE $78,$ff,$ff,$ff,$78,$ff,$ff,$ff + DATA BYTE $7a,$fd,$ff,$ff,$b8,$ff,$ff,$ff + DATA BYTE $bc,$ff,$ff,$ff,$b8,$ff,$ff,$ff + DATA BYTE $b8,$fd,$fd,$fd,$98,$fd,$fd,$fd + DATA BYTE $7f,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $7f,$ff,$ff,$ff,$3e,$ff,$ff,$ff + DATA BYTE $1e,$ff,$ff,$ff,$5f,$ff,$ff,$ff + DATA BYTE $1c,$ff,$ff,$ff,$1c,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $e0,$ff,$ff,$ff,$c0,$ff,$ff,$ff + DATA BYTE $88,$ff,$ff,$ff,$08,$fb,$fb,$fb + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $12,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$bf,$bf,$bf,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$fe,$fe,$fe + DATA BYTE $00,$fe,$fe,$fe,$00,$fa,$fa,$fa + DATA BYTE $00,$fa,$fa,$fa,$00,$fc,$fc,$fc + DATA BYTE $00,$81,$81,$81,$00,$89,$89,$89 + DATA BYTE $00,$ad,$ad,$ad,$00,$ff,$ff,$ce + DATA BYTE $01,$de,$de,$df,$01,$ff,$fe,$ff + DATA BYTE $01,$ff,$fe,$ff,$01,$ff,$fe,$ff + DATA BYTE $07,$ff,$fa,$ff,$03,$ff,$fe,$ff + DATA BYTE $03,$ff,$fe,$ff,$83,$7f,$7c,$ff + DATA BYTE $c2,$fb,$f9,$fb,$c0,$f1,$b1,$f0 + DATA BYTE $c0,$f8,$b8,$f8,$c0,$f0,$b0,$f0 + DATA BYTE $00,$e3,$e3,$e3,$00,$c7,$c7,$c4 + DATA BYTE $00,$d8,$d8,$18,$00,$f8,$f8,$20 + DATA BYTE $00,$f0,$f0,$40,$00,$fe,$fe,$e0 + DATA BYTE $0c,$3f,$31,$2f,$0c,$6f,$61,$6f + DATA BYTE $00,$01,$01,$01,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$40,$70,$70 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$7d,$7d,$7d,$00,$7d,$7d,$7d + DATA BYTE $00,$78,$78,$78,$00,$30,$30,$30 + DATA BYTE $00,$01,$01,$01,$00,$03,$03,$03 + DATA BYTE $01,$03,$02,$03,$05,$03,$02,$07 + DATA BYTE $31,$ff,$ff,$ff,$21,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $e0,$ff,$1f,$ff,$e0,$ff,$1f,$ff + DATA BYTE $e0,$ff,$1f,$ff,$e0,$ff,$1f,$ff + DATA BYTE $f8,$ff,$ff,$ff,$e0,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $3c,$ff,$ff,$ff,$0e,$ff,$ff,$ff + DATA BYTE $03,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$07,$f8,$f8,$ff + DATA BYTE $2a,$ff,$ff,$ff,$0a,$ff,$ff,$ff + DATA BYTE $02,$ff,$ff,$ff,$82,$ff,$ff,$ff + DATA BYTE $40,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$80,$7f,$7f,$ff + DATA BYTE $b8,$fe,$fe,$fe,$9c,$ff,$ff,$ff + DATA BYTE $9c,$ff,$ff,$ff,$9c,$ff,$ff,$ff + DATA BYTE $9c,$ff,$ff,$ff,$9c,$ff,$ff,$ff + DATA BYTE $9c,$ff,$ff,$ff,$9c,$ff,$ff,$ff + DATA BYTE $1f,$ff,$ff,$ff,$9f,$7f,$ff,$ff + DATA BYTE $1f,$ff,$ff,$ff,$0f,$ff,$ff,$ff + DATA BYTE $0f,$ff,$ff,$ff,$0f,$ff,$ff,$ff + DATA BYTE $07,$ff,$ff,$ff,$03,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$f8,$ff,$ff,$ff + DATA BYTE $f0,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$fc,$fe,$fe,$fe + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$fe,$fe,$fe + DATA BYTE $00,$e8,$e8,$e8,$00,$e1,$e1,$e1 + DATA BYTE $01,$f7,$f7,$f5,$03,$03,$01,$03 + DATA BYTE $01,$67,$66,$67,$00,$07,$07,$07 + DATA BYTE $00,$03,$03,$03,$00,$1f,$1f,$1f + DATA BYTE $10,$6f,$6f,$7f,$18,$ff,$ef,$ff + DATA BYTE $80,$ff,$fe,$ff,$80,$fe,$fe,$fe + DATA BYTE $18,$fe,$e6,$fc,$08,$fe,$f6,$fe + DATA BYTE $08,$e6,$e6,$ee,$00,$ce,$ce,$ce + DATA BYTE $c0,$f0,$b0,$f0,$c0,$f0,$b0,$f0 + DATA BYTE $00,$b8,$b8,$38,$00,$18,$18,$18 + DATA BYTE $00,$18,$18,$18,$00,$18,$18,$18 + DATA BYTE $00,$18,$18,$18,$00,$18,$18,$18 + DATA BYTE $0e,$2f,$21,$2f,$00,$2f,$2f,$2f + DATA BYTE $00,$2f,$2f,$27,$00,$37,$37,$37 + DATA BYTE $00,$b7,$b7,$b7,$00,$37,$37,$37 + DATA BYTE $00,$27,$27,$27,$00,$0f,$0f,$0f + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$80,$00,$80 + DATA BYTE $e0,$f3,$01,$f3,$f1,$ff,$08,$f7 + DATA BYTE $97,$ff,$00,$ff,$c0,$ff,$3f,$ff + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$e0,$e0,$e0,$60,$f0,$c0,$f0 + DATA BYTE $f0,$f8,$e0,$f8,$70,$fe,$ee,$fe + DATA BYTE $03,$07,$04,$07,$07,$0f,$08,$07 + DATA BYTE $05,$0f,$0a,$0f,$0f,$0f,$00,$0f + DATA BYTE $07,$1f,$18,$0f,$05,$1f,$1a,$0f + DATA BYTE $0d,$17,$12,$0f,$0d,$17,$12,$1f + DATA BYTE $e0,$ff,$1f,$ff,$e0,$ff,$1f,$ff + DATA BYTE $e0,$ff,$1f,$ff,$e0,$ff,$1f,$ff + DATA BYTE $c0,$ff,$3f,$ff,$c0,$ff,$3f,$ff + DATA BYTE $c0,$ff,$3f,$ff,$40,$ff,$bf,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $07,$f8,$f8,$ff,$0f,$f0,$f0,$ff + DATA BYTE $0f,$f0,$f0,$ff,$0f,$f0,$f0,$ff + DATA BYTE $0f,$f0,$f0,$ff,$05,$fa,$fa,$ff + DATA BYTE $00,$ff,$ff,$ff,$01,$fe,$fe,$ff + DATA BYTE $c0,$3b,$3b,$fb,$f0,$0d,$0d,$f9 + DATA BYTE $f0,$0d,$0d,$fd,$f8,$04,$04,$fc + DATA BYTE $f0,$0c,$0c,$f0,$f0,$0c,$0c,$f0 + DATA BYTE $20,$dc,$dc,$e0,$e0,$1c,$1c,$e0 + DATA BYTE $9c,$ff,$ff,$ff,$9c,$ff,$ff,$ff + DATA BYTE $bc,$ff,$ff,$ff,$9c,$ff,$ff,$ff + DATA BYTE $1a,$fd,$ff,$ff,$18,$fe,$fe,$fe + DATA BYTE $10,$ff,$ff,$ff,$18,$ff,$ff,$ff + DATA BYTE $03,$ff,$ff,$ff,$01,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $08,$f7,$ff,$ff,$88,$77,$ff,$ff + DATA BYTE $98,$67,$ff,$ff,$10,$ef,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$3f,$ff,$ff,$ff + DATA BYTE $f4,$fe,$fe,$fe,$f4,$ff,$ff,$ff + DATA BYTE $fc,$ff,$ff,$ff,$f4,$ff,$ff,$ff + DATA BYTE $f4,$ff,$ff,$ff,$f4,$ff,$ff,$ff + DATA BYTE $f0,$ff,$ff,$ff,$e0,$fe,$fe,$fe + DATA BYTE $00,$fe,$fe,$fe,$00,$fe,$fe,$fe + DATA BYTE $00,$ff,$ff,$ff,$00,$fe,$fe,$fe + DATA BYTE $02,$ff,$ff,$ff,$02,$3f,$3f,$3f + DATA BYTE $00,$7f,$7f,$7f,$00,$7f,$7f,$7f + DATA BYTE $00,$3f,$3f,$3f,$00,$bf,$bf,$bf + DATA BYTE $00,$bc,$bc,$bc,$00,$b8,$b8,$b8 + DATA BYTE $00,$a0,$a0,$a0,$00,$e0,$e0,$e0 + DATA BYTE $00,$c0,$c0,$c0,$00,$46,$46,$46 + DATA BYTE $00,$ce,$ce,$ce,$00,$ee,$ee,$e6 + DATA BYTE $00,$66,$66,$66,$00,$66,$66,$66 + DATA BYTE $00,$2e,$2e,$2e,$00,$3e,$3e,$3e + DATA BYTE $00,$0f,$0f,$0f,$01,$1f,$1f,$1f + DATA BYTE $00,$08,$08,$08,$00,$18,$18,$18 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$60,$60,$60,$00,$e1,$e1,$e1 + DATA BYTE $c7,$ef,$e8,$ef,$ff,$ff,$c0,$ff + DATA BYTE $0c,$1f,$13,$0f,$00,$1f,$1f,$0f + DATA BYTE $00,$0f,$0f,$0f,$04,$0f,$0b,$0f + DATA BYTE $24,$7e,$5a,$2e,$e4,$fe,$1a,$e6 + DATA BYTE $e4,$fe,$1a,$e6,$e0,$f6,$16,$e6 + DATA BYTE $f4,$ff,$3f,$ff,$b7,$fc,$7f,$fc + DATA BYTE $97,$fc,$7f,$fe,$82,$ff,$7f,$ff + DATA BYTE $df,$ff,$3f,$ff,$cf,$ff,$3f,$ff + DATA BYTE $c0,$ff,$3f,$ff,$c0,$c0,$00,$c0 + DATA BYTE $10,$fe,$ee,$fe,$11,$fe,$ee,$fe + DATA BYTE $05,$f8,$f8,$e4,$11,$ec,$ec,$f0 + DATA BYTE $19,$64,$64,$18,$03,$1c,$1c,$18 + DATA BYTE $03,$08,$08,$08,$02,$18,$18,$00 + DATA BYTE $12,$2f,$2d,$1f,$b1,$0e,$0e,$3f + DATA BYTE $a7,$18,$18,$3f,$b6,$19,$09,$3e + DATA BYTE $9f,$70,$60,$3f,$3f,$60,$40,$7f + DATA BYTE $3c,$63,$43,$7c,$70,$ce,$8e,$70 + DATA BYTE $40,$bf,$bf,$ff,$80,$7f,$7f,$80 + DATA BYTE $00,$c0,$c0,$00,$00,$80,$80,$00 + DATA BYTE $cc,$33,$33,$fc,$80,$7f,$7f,$80 + DATA BYTE $00,$c5,$c5,$00,$28,$00,$00,$00 + DATA BYTE $00,$ff,$ff,$ff,$24,$db,$db,$ff + DATA BYTE $3d,$42,$42,$3f,$1d,$e2,$e2,$1f + DATA BYTE $1f,$e0,$e0,$1f,$1a,$e5,$e5,$1e + DATA BYTE $32,$cd,$cd,$3e,$32,$cd,$cd,$3e + DATA BYTE $00,$ff,$ff,$ff,$c0,$3f,$3f,$ff + DATA BYTE $e0,$1f,$1f,$e0,$80,$60,$60,$80 + DATA BYTE $00,$e0,$e0,$00,$00,$ff,$ff,$00 + DATA BYTE $18,$e7,$e7,$1f,$03,$fc,$fc,$07 + DATA BYTE $20,$dc,$dc,$e0,$60,$98,$98,$e0 + DATA BYTE $01,$f8,$f8,$00,$03,$38,$38,$00 + DATA BYTE $03,$18,$18,$00,$02,$08,$08,$00 + DATA BYTE $02,$f8,$f8,$00,$82,$7c,$7c,$80 + DATA BYTE $20,$7f,$7f,$7f,$04,$7f,$7f,$7f + DATA BYTE $0c,$7f,$7f,$7f,$00,$7f,$7f,$7f + DATA BYTE $00,$7f,$7f,$7f,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ef,$ef,$ef + DATA BYTE $10,$ef,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $08,$f7,$ff,$ff,$04,$f3,$f7,$f7 + DATA BYTE $10,$e3,$f3,$f3,$18,$e7,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$08,$f7,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$3b,$ff,$ff,$ff + DATA BYTE $1b,$ff,$ff,$ff,$0f,$ff,$ff,$ff + DATA BYTE $1f,$7f,$7f,$7f,$0f,$ff,$ff,$ff + DATA BYTE $07,$ff,$ff,$ff,$03,$ff,$ff,$ff + DATA BYTE $e4,$fe,$fe,$fe,$e0,$ff,$ff,$ff + DATA BYTE $80,$ff,$ff,$ff,$80,$ff,$ff,$ff + DATA BYTE $80,$ff,$ff,$ff,$80,$fe,$fe,$fe + DATA BYTE $80,$ed,$ed,$ed,$80,$ef,$ef,$ef + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $10,$ef,$ff,$ff,$10,$0f,$1f,$1f + DATA BYTE $00,$3f,$3f,$3f,$00,$ff,$ff,$ff + DATA BYTE $06,$4f,$4f,$4f,$0e,$df,$df,$df + DATA BYTE $02,$cf,$cf,$cf,$80,$ff,$ff,$df + DATA BYTE $00,$ff,$ff,$ff,$80,$ff,$ff,$fd + DATA BYTE $00,$ff,$ff,$ff,$40,$ff,$bf,$f7 + DATA BYTE $01,$3f,$3f,$0f,$0f,$ff,$f0,$ff + DATA BYTE $1d,$ff,$e2,$ff,$0d,$b3,$b2,$af + DATA BYTE $10,$ee,$ee,$f0,$e0,$c7,$07,$e3 + DATA BYTE $80,$e1,$61,$a1,$c0,$e3,$23,$e1 + DATA BYTE $3f,$ff,$c0,$ff,$ff,$ff,$00,$ff + DATA BYTE $fe,$ff,$01,$ff,$e0,$e0,$00,$e0 + DATA BYTE $10,$00,$00,$00,$86,$01,$01,$07 + DATA BYTE $00,$3f,$3f,$3f,$00,$ff,$ff,$ff + DATA BYTE $e0,$ff,$1f,$f7,$e0,$ff,$1f,$e7 + DATA BYTE $00,$87,$87,$07,$90,$4f,$4f,$97 + DATA BYTE $78,$87,$87,$ff,$03,$fc,$fc,$ff + DATA BYTE $07,$f8,$f8,$ff,$80,$60,$60,$80 + DATA BYTE $c0,$e0,$00,$e0,$c0,$dc,$00,$dc + DATA BYTE $c7,$ff,$00,$ff,$9f,$ff,$00,$ff + DATA BYTE $c7,$ff,$00,$ff,$ff,$ff,$00,$ff + DATA BYTE $c7,$ff,$10,$ff,$2f,$ff,$d0,$3f + DATA BYTE $02,$18,$18,$00,$08,$14,$14,$08 + DATA BYTE $0c,$f1,$f1,$ac,$1c,$e1,$e1,$fd + DATA BYTE $1c,$e1,$e1,$fd,$1c,$e3,$e3,$fd + DATA BYTE $1f,$e0,$e0,$bf,$3f,$e0,$c0,$ff + DATA BYTE $48,$f7,$b7,$f8,$71,$ff,$8e,$ff + DATA BYTE $60,$ff,$9f,$ff,$20,$ff,$df,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$80,$7f,$7f,$ff + DATA BYTE $00,$04,$04,$04,$01,$fe,$fe,$e1 + DATA BYTE $e4,$1b,$1b,$e7,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$01,$fe,$fe,$ff + DATA BYTE $03,$fc,$fc,$ff,$03,$fc,$fc,$ff + DATA BYTE $30,$cf,$cf,$3c,$32,$cd,$cd,$be + DATA BYTE $f2,$0d,$0d,$fe,$e2,$1d,$1d,$fe + DATA BYTE $c2,$3d,$3d,$fe,$c2,$3d,$3d,$fe + DATA BYTE $82,$7d,$7d,$fe,$83,$7c,$7c,$ff + DATA BYTE $00,$f7,$f7,$00,$02,$d0,$d0,$10 + DATA BYTE $50,$a0,$a0,$50,$64,$9b,$9b,$64 + DATA BYTE $7c,$83,$83,$7c,$3f,$c0,$c0,$3f + DATA BYTE $3f,$c0,$c0,$3f,$3f,$c0,$c0,$3f + DATA BYTE $00,$fc,$fc,$00,$00,$1c,$1c,$00 + DATA BYTE $00,$0d,$0d,$00,$00,$9c,$9c,$00 + DATA BYTE $00,$fc,$fc,$00,$fc,$02,$02,$fc + DATA BYTE $fc,$03,$03,$fc,$f8,$07,$07,$f8 + DATA BYTE $00,$ff,$ff,$ff,$00,$bf,$bf,$3f + DATA BYTE $20,$b3,$b3,$33,$20,$bd,$bd,$bc + DATA BYTE $00,$a7,$a7,$27,$00,$bf,$bf,$3f + DATA BYTE $00,$a3,$a3,$22,$00,$a1,$a1,$a0 + DATA BYTE $00,$f9,$f9,$f9,$08,$f7,$ff,$ff + DATA BYTE $00,$9f,$9f,$9f,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$fa,$fa,$f2 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $03,$ff,$ff,$ff,$02,$bf,$bf,$bf + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$84,$84,$84,$00,$44,$44,$44 + DATA BYTE $00,$c0,$c0,$c0,$00,$c0,$c0,$c0 + DATA BYTE $00,$ff,$ff,$ff,$00,$f7,$f7,$f7 + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$41,$41,$41,$00,$10,$10,$00 + DATA BYTE $00,$f6,$f6,$e0,$68,$7e,$76,$78 + DATA BYTE $08,$f7,$f7,$ff,$00,$af,$af,$af + DATA BYTE $02,$bf,$bd,$bf,$02,$d7,$d5,$d7 + DATA BYTE $00,$83,$83,$83,$40,$0a,$6a,$0a + DATA BYTE $40,$02,$42,$00,$01,$40,$40,$40 + DATA BYTE $ca,$ff,$75,$ff,$ce,$ff,$71,$ff + DATA BYTE $cf,$ff,$30,$ff,$c2,$ff,$3d,$ff + DATA BYTE $1c,$eb,$e3,$fe,$0c,$00,$00,$0c + DATA BYTE $43,$04,$04,$00,$f3,$00,$00,$00 + DATA BYTE $e0,$e7,$07,$e3,$e0,$e0,$00,$e0 + DATA BYTE $e0,$e1,$01,$e1,$00,$f0,$f0,$20 + DATA BYTE $00,$10,$10,$10,$03,$08,$08,$08 + DATA BYTE $e3,$08,$08,$08,$e1,$00,$08,$00 + DATA BYTE $c0,$3c,$3c,$f8,$00,$c0,$c0,$00 + DATA BYTE $00,$80,$80,$80,$3e,$00,$00,$00 + DATA BYTE $3e,$00,$00,$00,$9e,$00,$00,$00 + DATA BYTE $00,$38,$38,$30,$78,$7c,$04,$78 + DATA BYTE $00,$0e,$0e,$00,$00,$68,$68,$40 + DATA BYTE $00,$f0,$f0,$70,$00,$60,$60,$60 + DATA BYTE $00,$e0,$e0,$60,$00,$e0,$e0,$60 + DATA BYTE $00,$60,$60,$40,$00,$68,$68,$00 + DATA BYTE $ef,$ff,$10,$ff,$21,$27,$06,$27 + DATA BYTE $00,$00,$00,$00,$00,$01,$01,$01 + DATA BYTE $0c,$01,$01,$01,$de,$01,$01,$01 + DATA BYTE $de,$00,$00,$00,$1e,$01,$01,$01 + DATA BYTE $17,$88,$88,$1f,$03,$3c,$3c,$1f + DATA BYTE $43,$fc,$fc,$ff,$03,$fc,$fc,$ff + DATA BYTE $03,$9c,$9c,$9f,$13,$2c,$2c,$3f + DATA BYTE $0f,$00,$00,$0f,$03,$00,$00,$03 + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$bd,$42,$42,$ff + DATA BYTE $ff,$00,$00,$ff,$fe,$01,$01,$fe + DATA BYTE $f8,$07,$07,$f8,$f1,$0e,$0e,$f1 + DATA BYTE $27,$d8,$d8,$ff,$7e,$81,$81,$ff + DATA BYTE $fc,$03,$03,$ff,$df,$20,$20,$df + DATA BYTE $26,$d9,$d9,$3e,$44,$bb,$bb,$7c + DATA BYTE $03,$fc,$fc,$ff,$20,$df,$df,$ff + DATA BYTE $83,$7c,$7c,$ff,$03,$fc,$fc,$ff + DATA BYTE $83,$7c,$7c,$ff,$c6,$39,$39,$fe + DATA BYTE $7c,$83,$83,$7c,$38,$c6,$c6,$38 + DATA BYTE $80,$78,$78,$80,$40,$a3,$a3,$c0 + DATA BYTE $3f,$c0,$c0,$3f,$1b,$e4,$e4,$1f + DATA BYTE $5f,$a0,$a0,$5f,$0f,$f0,$f0,$0f + DATA BYTE $0f,$f0,$f0,$0f,$07,$38,$38,$07 + DATA BYTE $1f,$60,$60,$1f,$0a,$f5,$f5,$0a + DATA BYTE $f0,$0f,$0f,$f0,$f0,$0f,$0f,$f0 + DATA BYTE $f0,$0f,$0f,$f1,$e0,$1f,$1f,$e1 + DATA BYTE $e0,$1f,$1f,$e1,$c0,$3f,$3f,$c1 + DATA BYTE $c0,$3f,$3f,$c1,$02,$fd,$fd,$03 + DATA BYTE $04,$c1,$c5,$c5,$0c,$91,$9d,$9d + DATA BYTE $7c,$81,$fd,$fd,$2d,$90,$bd,$bd + DATA BYTE $3c,$81,$bd,$bd,$3e,$81,$bf,$bf + DATA BYTE $3f,$80,$bf,$bf,$1d,$80,$9d,$9d + DATA BYTE $00,$08,$08,$08,$00,$c0,$c0,$c0 + DATA BYTE $c0,$e0,$e0,$e0,$00,$e0,$e0,$e0 + DATA BYTE $30,$e1,$f1,$e1,$18,$e1,$fb,$e1 + DATA BYTE $09,$d0,$df,$d0,$04,$18,$1e,$18 + DATA BYTE $00,$e2,$e2,$e2,$02,$e1,$e1,$e2 + DATA BYTE $83,$c0,$c0,$c3,$00,$83,$83,$80 + DATA BYTE $00,$80,$80,$80,$00,$80,$80,$80 + DATA BYTE $0c,$c0,$c0,$80,$04,$31,$31,$11 + DATA BYTE $00,$7f,$7f,$79,$00,$77,$77,$77 + DATA BYTE $00,$77,$77,$77,$00,$9f,$9f,$1f + DATA BYTE $40,$8f,$8f,$0f,$00,$8f,$8f,$0f + DATA BYTE $02,$0d,$0f,$0f,$02,$0d,$0f,$0f + DATA BYTE $01,$c0,$c0,$c0,$01,$80,$80,$80 + DATA BYTE $18,$c0,$c0,$80,$00,$c0,$c0,$80 + DATA BYTE $00,$e0,$e0,$c0,$00,$c0,$c0,$c0 + DATA BYTE $00,$c0,$c0,$c0,$00,$c0,$c0,$c0 + DATA BYTE $f3,$00,$00,$00,$f3,$00,$00,$00 + DATA BYTE $f3,$00,$00,$00,$40,$24,$24,$24 + DATA BYTE $00,$7c,$7c,$7c,$00,$74,$74,$70 + DATA BYTE $00,$34,$34,$34,$00,$3f,$3f,$3f + DATA BYTE $e0,$0f,$0f,$0f,$e2,$0d,$0f,$0d + DATA BYTE $60,$0f,$0f,$0f,$00,$5f,$5f,$4f + DATA BYTE $00,$17,$17,$07,$00,$47,$47,$47 + DATA BYTE $00,$87,$87,$86,$08,$03,$03,$02 + DATA BYTE $80,$fe,$7e,$80,$80,$fe,$7e,$80 + DATA BYTE $00,$fe,$fe,$00,$00,$fe,$fe,$00 + DATA BYTE $00,$70,$70,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$01,$00,$01 + DATA BYTE $00,$00,$01,$01,$00,$00,$00,$00 + DATA BYTE $0e,$70,$70,$70,$2f,$70,$50,$70 + DATA BYTE $00,$11,$11,$11,$18,$bf,$a7,$bf + DATA BYTE $00,$b8,$b8,$b8,$00,$fc,$ec,$fc + DATA BYTE $00,$c0,$c0,$c0,$00,$80,$80,$00 + DATA BYTE $00,$80,$80,$80,$00,$80,$80,$00 + DATA BYTE $03,$00,$00,$03,$03,$80,$80,$83 + DATA BYTE $01,$c2,$c2,$c3,$01,$62,$62,$63 + DATA BYTE $01,$02,$02,$03,$00,$07,$07,$06 + DATA BYTE $00,$0f,$0f,$0e,$00,$0f,$0f,$02 + DATA BYTE $f9,$06,$06,$f9,$fc,$03,$03,$fc + DATA BYTE $ff,$00,$00,$ff,$ef,$10,$10,$ef + DATA BYTE $ff,$00,$00,$ff,$ff,$01,$00,$ff + DATA BYTE $ff,$01,$00,$ff,$7e,$81,$81,$7f + DATA BYTE $80,$7f,$7f,$ff,$00,$ff,$ff,$3f + DATA BYTE $80,$5f,$5f,$80,$20,$c7,$c7,$e0 + DATA BYTE $13,$ec,$ec,$f3,$0f,$f0,$f0,$ff + DATA BYTE $01,$fe,$fe,$ff,$0f,$f0,$f0,$ff + DATA BYTE $30,$cf,$cf,$f0,$3c,$c3,$c3,$fc + DATA BYTE $78,$87,$87,$78,$00,$ff,$ff,$00 + DATA BYTE $80,$7e,$7e,$80,$f0,$0f,$0f,$f0 + DATA BYTE $d8,$27,$27,$f8,$ff,$00,$00,$ff + DATA BYTE $08,$f7,$f7,$08,$00,$ff,$ff,$00 + DATA BYTE $00,$ff,$ff,$00,$02,$fd,$fd,$02 + DATA BYTE $06,$0b,$09,$06,$0a,$f5,$f5,$0e + DATA BYTE $88,$77,$77,$8c,$8c,$73,$73,$8c + DATA BYTE $00,$ff,$ff,$03,$00,$ff,$ff,$03 + DATA BYTE $00,$f3,$f3,$03,$00,$f3,$f3,$03 + DATA BYTE $00,$fb,$fb,$0b,$00,$fb,$fb,$0b + DATA BYTE $00,$c7,$c7,$07,$18,$c7,$c7,$07 + DATA BYTE $00,$c0,$c0,$c0,$1e,$c0,$c0,$c0 + DATA BYTE $17,$c0,$c0,$c0,$05,$c0,$c0,$c0 + DATA BYTE $05,$c0,$c0,$c0,$24,$c8,$c8,$c8 + DATA BYTE $04,$da,$da,$da,$04,$db,$db,$db + DATA BYTE $c0,$18,$1e,$18,$80,$39,$3d,$39 + DATA BYTE $84,$3a,$3e,$3a,$08,$3f,$3f,$3f + DATA BYTE $08,$3f,$3f,$3f,$10,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$71,$71,$01,$08,$71,$71,$09 + DATA BYTE $00,$f8,$f8,$80,$00,$ba,$ba,$aa + DATA BYTE $00,$fb,$fb,$fb,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$2f,$2f,$2f,$02,$21,$23,$23 + DATA BYTE $02,$01,$03,$03,$03,$00,$03,$03 + DATA BYTE $02,$c1,$c3,$c3,$00,$80,$80,$80 + DATA BYTE $38,$fc,$fc,$fc,$1d,$fc,$fd,$fd + DATA BYTE $00,$80,$80,$80,$00,$80,$80,$80 + DATA BYTE $00,$80,$80,$80,$00,$80,$80,$80 + DATA BYTE $40,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$c0,$c0,$c0,$f9,$7c,$fc,$fc + DATA BYTE $00,$1c,$1c,$1c,$00,$4e,$4e,$4e + DATA BYTE $00,$82,$82,$80,$01,$90,$90,$90 + DATA BYTE $01,$00,$00,$00,$01,$00,$00,$00 + DATA BYTE $00,$26,$26,$00,$c0,$04,$04,$00 + DATA BYTE $38,$00,$00,$00,$72,$07,$05,$06 + DATA BYTE $e0,$06,$06,$06,$00,$00,$00,$00 + DATA BYTE $bf,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $7f,$00,$00,$00,$3f,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$c0,$00,$00,$00 + DATA BYTE $e0,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $0f,$60,$60,$00,$07,$00,$00,$00 + DATA BYTE $03,$00,$00,$00,$5b,$00,$00,$00 + DATA BYTE $1b,$00,$00,$00,$1f,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $00,$03,$03,$00,$00,$01,$01,$00 + DATA BYTE $00,$01,$01,$00,$00,$00,$00,$00 + DATA BYTE $20,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$40,$40,$40,$00,$40,$40,$40 + DATA BYTE $7e,$81,$81,$7f,$3f,$c0,$c0,$3f + DATA BYTE $3c,$c3,$c3,$3f,$1c,$e3,$e3,$1f + DATA BYTE $0e,$f1,$f1,$0f,$06,$39,$39,$07 + DATA BYTE $03,$0c,$0c,$03,$41,$02,$02,$01 + DATA BYTE $0f,$f0,$f0,$ff,$02,$fd,$fd,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $80,$7f,$7f,$ff,$c0,$3f,$3f,$ff + DATA BYTE $ff,$00,$00,$ff,$ff,$00,$00,$ff + DATA BYTE $67,$98,$98,$ff,$07,$f8,$f8,$ff + DATA BYTE $0f,$f0,$f0,$ff,$0f,$f0,$f0,$ff + DATA BYTE $0f,$f0,$f0,$ff,$1f,$e0,$e0,$ff + DATA BYTE $88,$77,$77,$88,$80,$7f,$7f,$80 + DATA BYTE $00,$ff,$ff,$00,$00,$ff,$ff,$00 + DATA BYTE $00,$fe,$fe,$00,$01,$fe,$fe,$00 + DATA BYTE $01,$fc,$fc,$00,$01,$f8,$f8,$00 + DATA BYTE $38,$c3,$c3,$03,$38,$83,$83,$03 + DATA BYTE $7d,$83,$82,$03,$7d,$03,$02,$03 + DATA BYTE $fd,$03,$02,$03,$fd,$03,$02,$03 + DATA BYTE $e0,$0f,$0f,$0f,$e1,$1f,$1e,$1f + DATA BYTE $04,$db,$db,$db,$00,$db,$db,$db + DATA BYTE $80,$db,$5b,$db,$80,$fb,$7b,$fb + DATA BYTE $80,$ff,$7f,$ff,$80,$ff,$7f,$ff + DATA BYTE $80,$ff,$7f,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$01,$ff,$ff,$ff + DATA BYTE $01,$ff,$ff,$ff,$1f,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $40,$ff,$ff,$ff,$e0,$ff,$ff,$ff + DATA BYTE $f0,$ff,$ff,$ff,$f0,$ff,$ff,$ff + DATA BYTE $1c,$fe,$fe,$fe,$3f,$fe,$ff,$ff + DATA BYTE $7e,$ff,$ff,$ff,$7e,$ff,$ff,$ff + DATA BYTE $7f,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$fc,$fc,$fc,$fc + DATA BYTE $b8,$7c,$fc,$7c,$b8,$7c,$fc,$fc + DATA BYTE $b8,$7c,$fc,$fc,$bc,$7c,$fc,$fc + DATA BYTE $3c,$7e,$7e,$7e,$3d,$7e,$7e,$7e + DATA BYTE $3e,$3e,$3e,$3e,$1e,$3e,$3e,$3e + DATA BYTE $00,$00,$00,$00,$40,$07,$07,$00 + DATA BYTE $60,$04,$04,$00,$60,$07,$07,$04 + DATA BYTE $c2,$07,$05,$07,$c1,$2f,$2e,$2f + DATA BYTE $c2,$23,$21,$22,$c3,$23,$20,$23 + DATA BYTE $1f,$00,$00,$00,$07,$00,$00,$00 + DATA BYTE $07,$00,$00,$00,$07,$00,$00,$00 + DATA BYTE $07,$a0,$a0,$00,$07,$00,$00,$00 + DATA BYTE $07,$00,$00,$00,$07,$80,$80,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $7f,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $01,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $fe,$00,$00,$00,$fe,$00,$00,$00 + DATA BYTE $fc,$00,$00,$00,$ee,$00,$0e,$00 + DATA BYTE $3e,$00,$3f,$00,$7e,$80,$ff,$80 + DATA BYTE $40,$00,$40,$40,$80,$00,$80,$80 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$01,$01,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $04,$00,$04,$00,$02,$00,$02,$00 + DATA BYTE $01,$00,$01,$00,$00,$00,$00,$00 + DATA BYTE $60,$9f,$9f,$7f,$12,$ed,$ed,$1e + DATA BYTE $00,$1f,$1f,$04,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$80,$00,$80,$00 + DATA BYTE $20,$df,$df,$e0,$00,$ff,$ff,$80 + DATA BYTE $00,$ff,$ff,$00,$00,$06,$06,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$00,$78,$78,$00 + DATA BYTE $04,$f0,$f1,$00,$06,$c0,$c0,$00 + DATA BYTE $07,$00,$00,$00,$0f,$00,$00,$00 + DATA BYTE $07,$00,$00,$00,$03,$00,$00,$00 + DATA BYTE $05,$00,$04,$00,$07,$20,$26,$00 + DATA BYTE $61,$1f,$1e,$1f,$01,$1f,$1e,$1f + DATA BYTE $80,$1f,$1f,$1f,$e0,$03,$03,$03 + DATA BYTE $f1,$03,$03,$03,$d0,$01,$01,$01 + DATA BYTE $f0,$00,$00,$00,$e1,$00,$01,$00 + DATA BYTE $80,$ff,$7f,$ff,$40,$ff,$bf,$ff + DATA BYTE $c0,$ff,$bf,$ff,$c0,$ff,$bf,$ff + DATA BYTE $c0,$ff,$bf,$ff,$c0,$ff,$ff,$ff + DATA BYTE $40,$ff,$ff,$ff,$60,$ff,$ff,$ff + DATA BYTE $1f,$ff,$ff,$ff,$1f,$ff,$ff,$ff + DATA BYTE $3f,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $fc,$fe,$fe,$fe,$fe,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $1e,$7e,$7e,$7e,$1e,$ff,$ff,$ff + DATA BYTE $3c,$ff,$ff,$ff,$3c,$ff,$ff,$ff + DATA BYTE $1e,$ff,$ff,$ff,$10,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $41,$33,$32,$23,$00,$30,$30,$30 + DATA BYTE $01,$30,$30,$30,$05,$30,$30,$20 + DATA BYTE $07,$20,$20,$20,$03,$00,$00,$00 + DATA BYTE $06,$10,$10,$00,$06,$10,$10,$10 + DATA BYTE $02,$c0,$c0,$c0,$73,$00,$00,$00 + DATA BYTE $d2,$00,$00,$00,$d0,$00,$00,$00 + DATA BYTE $d0,$00,$00,$00,$d3,$00,$00,$00 + DATA BYTE $d8,$00,$00,$00,$49,$20,$20,$20 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $7f,$00,$00,$00,$1f,$00,$00,$00 + DATA BYTE $0e,$00,$00,$00,$0e,$00,$00,$00 + DATA BYTE $bf,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$3f,$00,$00,$00 + DATA BYTE $7f,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $fc,$00,$ff,$00,$fc,$00,$ff,$00 + DATA BYTE $e0,$00,$ff,$00,$60,$00,$ff,$00 + DATA BYTE $00,$00,$be,$00,$00,$00,$d7,$00 + DATA BYTE $00,$00,$d6,$00,$00,$00,$db,$00 + DATA BYTE $00,$00,$80,$00,$00,$00,$80,$00 + DATA BYTE $00,$00,$80,$00,$00,$00,$80,$00 + DATA BYTE $00,$00,$40,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$80,$00,$00,$00,$80,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$10,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$02,$00,$00,$00 + DATA BYTE $03,$00,$00,$00,$01,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$20,$00,$20,$00 + DATA BYTE $10,$00,$10,$00,$18,$00,$18,$00 + DATA BYTE $0c,$00,$0c,$00,$02,$00,$02,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$ff,$ff,$00,$00,$ff,$ff,$00 + DATA BYTE $00,$ff,$ff,$00,$00,$fd,$fd,$00 + DATA BYTE $00,$00,$00,$00,$00,$00,$00,$00 + DATA BYTE $00,$00,$00,$00,$20,$00,$00,$00 + DATA BYTE $05,$62,$67,$02,$04,$c3,$c7,$03 + DATA BYTE $04,$c3,$c7,$03,$04,$c3,$c7,$03 + DATA BYTE $04,$c3,$c7,$03,$04,$83,$87,$03 + DATA BYTE $00,$87,$8f,$07,$00,$07,$0f,$07 + DATA BYTE $e0,$00,$00,$00,$70,$00,$00,$00 + DATA BYTE $30,$80,$80,$80,$70,$80,$c0,$80 + DATA BYTE $38,$c0,$e0,$c0,$01,$e0,$e0,$e0 + DATA BYTE $01,$f0,$f0,$f0,$04,$f0,$f8,$f0 + DATA BYTE $a1,$7f,$ff,$7f,$01,$3f,$7f,$3f + DATA BYTE $07,$1f,$1f,$1f,$01,$1f,$1f,$1f + DATA BYTE $8b,$1f,$1f,$1f,$8f,$1f,$1f,$1f + DATA BYTE $af,$1f,$1f,$1f,$af,$1f,$1f,$1f + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$7f,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + DATA BYTE $fe,$ff,$ff,$ff,$fe,$ff,$ff,$ff + DATA BYTE $fc,$ff,$ff,$ff,$f8,$ff,$ff,$ff + DATA BYTE $f8,$ff,$ff,$ff,$fc,$ff,$ff,$ff + DATA BYTE $fc,$ff,$ff,$ff,$fc,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$00,$ff,$ff,$ff + DATA BYTE $00,$ff,$ff,$ff,$01,$ff,$ff,$ff + DATA BYTE $01,$ff,$ff,$ff,$01,$ff,$ff,$ff + DATA BYTE $06,$90,$90,$90,$02,$90,$90,$90 + DATA BYTE $06,$90,$90,$90,$00,$98,$98,$98 + DATA BYTE $00,$f9,$f9,$f9,$00,$ff,$ff,$ff + DATA BYTE $80,$ff,$ff,$ff,$90,$ff,$ef,$ff + DATA BYTE $4d,$20,$20,$20,$0f,$30,$30,$30 + DATA BYTE $0f,$30,$30,$30,$0c,$30,$30,$30 + DATA BYTE $06,$f0,$f0,$f0,$04,$f0,$f0,$f0 + DATA BYTE $06,$f0,$f0,$f0,$00,$f1,$f1,$f1 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $7f,$00,$00,$00,$0d,$00,$00,$00 + DATA BYTE $29,$00,$00,$00,$55,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $ff,$00,$00,$00,$ff,$00,$00,$00 + DATA BYTE $fe,$00,$00,$00,$d2,$00,$00,$00 + DATA BYTE $f6,$00,$00,$00,$88,$00,$00,$00 + + ' Width = 16, height = 12 +image_pattern: + DATA BYTE $40,$00,$41,$00,$42,$00,$43,$00,$44,$00,$45,$00,$46,$00,$47,$00,$48,$00,$48,$00,$48,$00,$49,$00,$4a,$00,$4b,$00,$4c,$00,$4d,$00 + DATA BYTE $4e,$00,$4f,$00,$50,$00,$51,$00,$52,$00,$53,$00,$54,$00,$55,$00,$56,$00,$48,$00,$48,$00,$57,$00,$58,$00,$59,$00,$5a,$00,$5b,$00 + DATA BYTE $5c,$00,$5d,$00,$5e,$00,$5f,$00,$60,$00,$61,$00,$62,$00,$63,$00,$64,$00,$65,$00,$66,$00,$67,$00,$68,$00,$69,$00,$6a,$00,$6b,$00 + DATA BYTE $6c,$00,$6d,$00,$6e,$00,$6f,$00,$70,$00,$71,$00,$72,$00,$73,$00,$74,$00,$75,$00,$76,$00,$77,$00,$78,$00,$79,$00,$7a,$00,$7b,$00 + DATA BYTE $7c,$00,$7d,$00,$7e,$00,$7f,$00,$80,$00,$81,$00,$82,$00,$83,$00,$84,$00,$85,$00,$86,$00,$87,$00,$88,$00,$89,$00,$8a,$00,$8b,$00 + DATA BYTE $8c,$00,$8d,$00,$8e,$00,$8f,$00,$90,$00,$91,$00,$92,$00,$93,$00,$94,$00,$95,$00,$96,$00,$97,$00,$98,$00,$99,$00,$9a,$00,$9b,$00 + DATA BYTE $9c,$00,$9d,$00,$9e,$00,$9f,$00,$a0,$00,$a1,$00,$a2,$00,$a3,$00,$a4,$00,$a5,$00,$a6,$00,$a7,$00,$a8,$00,$a9,$00,$aa,$00,$ab,$00 + DATA BYTE $ac,$00,$ad,$00,$ae,$00,$af,$00,$b0,$00,$b1,$00,$b2,$00,$b3,$00,$b4,$00,$b5,$00,$b6,$00,$b7,$00,$b8,$00,$b9,$00,$ba,$00,$bb,$00 + DATA BYTE $bc,$00,$bd,$00,$be,$00,$bf,$00,$c0,$00,$c1,$00,$c2,$00,$c3,$00,$c4,$00,$c5,$00,$c6,$00,$c7,$00,$c8,$00,$c9,$00,$ca,$00,$cb,$00 + DATA BYTE $6d,$00,$cc,$00,$cd,$00,$ce,$00,$cf,$00,$d0,$00,$d1,$00,$d2,$00,$d3,$00,$d4,$00,$d5,$00,$d6,$00,$d7,$00,$d8,$00,$d9,$00,$da,$00 + DATA BYTE $db,$00,$dc,$00,$dd,$00,$de,$00,$df,$00,$e0,$00,$e1,$00,$e2,$00,$e3,$00,$48,$00,$e4,$00,$e5,$00,$e6,$00,$e7,$00,$e8,$00,$e9,$00 + DATA BYTE $ea,$00,$eb,$00,$ec,$00,$ed,$00,$ee,$00,$ef,$00,$f0,$00,$f1,$00,$f2,$00,$48,$00,$f3,$00,$f4,$00,$f5,$00,$f6,$00,$f7,$00,$f8,$00 From 6f05ca6bcc944dbb391af47f6c4ce080a6c7aa9c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 27 Apr 2025 13:37:32 -0600 Subject: [PATCH 030/155] Small corrections and added cats_sms.bas --- README.md | 1 + cvbasic.c | 4 + cvbasic_prologue.asm | 6 +- examples/cats_sms.bas | 348 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 356 insertions(+), 3 deletions(-) create mode 100644 examples/cats_sms.bas diff --git a/README.md b/README.md index a4fe606..9ba8259 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ The following files compose the compiler: examples/brinquitos.bas Jumping game. examples/brinquitos_sms.bas Jumping game (Sega Master System) examples/controller.bas Controller test. + examples/cats_sms.bas Cats example (Sega Master System) examples/demo.bas Demo of graphics. examples/demo_sms.bas Demo of graphics (Sega Master System) examples/face_joystick.bas Moving face with joystick. diff --git a/cvbasic.c b/cvbasic.c index fd01a9e..0b5a946 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -90,6 +90,10 @@ struct console consoles[TOTAL_TARGETS] = { {"nabu", "-cpm", "NABU PC (64K RAM)", "Nabu PC", 0, 0xe000, 0, 0xa0, 0xa0, 0, 1, CPU_Z80}, + /* + ** For Sega Master System the stack cannot start at $e000, because + ** when using Bank Switching writing to $fffd-$ffff destroys $dffd-$dfff + */ {"sms", "", "Sega Master System (8K RAM)", "Sega Master System", 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 8d9adff..7028e23 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -3834,13 +3834,13 @@ Z80_CTC: equ $28 ld (de),a inc de if PV2000 - bit 7,d + bit 7,d ; 2.5K of RAM endif if PENCIL - bit 3,d + bit 3,d ; 2K of RAM endif if COLECO+SG1000+SORD - bit 2,d + bit 2,d ; 1K of RAM endif jp z,$-4 ld (lfsr),hl diff --git a/examples/cats_sms.bas b/examples/cats_sms.bas new file mode 100644 index 0000000..4f08a4e --- /dev/null +++ b/examples/cats_sms.bas @@ -0,0 +1,348 @@ + ' + ' Animation of cats + ' by Oscar Toledo G. + ' Example for CVBasic + ' + ' Creation date: Apr/27/2025. For Sega Master System. + ' + + DIM x(8),y(8),f(8) + + FOR c = 0 TO 7 + x(c) = RANDOM(176) + 32 + y(c) = RANDOM(112) + 32 + IF c AND 1 THEN f(c) = 4 ELSE f(c) = 0 + NEXT c + + DEFINE SPRITE 0,16,cat_sprites + +main_loop: + WAIT + FOR c = 0 TO 7 + SPRITE c * 2 + 0, y(c), x(c), f(c) * 4 + SPRITE c * 2 + 1, y(c), x(c) + 8, f(c) * 4 + 2 + NEXT c + + IF (FRAME AND 7) = 0 THEN + FOR c = 0 TO 7 + f(c) = f(c) + 1 + IF f(c) = 4 THEN f(c) = 0 + IF f(c) = 8 THEN f(c) = 4 + NEXT c + END IF + + GOTO main_loop + + ' TMSColor 3.0 Apr/27/2025 + ' Command: ../tmscolor/tmscolor -sms -sb -b -i cats_sprites.bmp cats_sprites_sms.bas cat_sprites + ' Created: Sun Apr 27 13:34:22 2025 + + ' + ' Sample code: + ' DEFINE SPRITE 0,16,cat_sprites + ' +cat_sprites: + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "EE0000EE" + BITMAP "EE00000E" + BITMAP "EE00000F" + + BITMAP "EE00000E" + BITMAP "0EE00000" + BITMAP "0EE0EEEE" + BITMAP "00EEEEEE" + BITMAP "00EEEEEE" + BITMAP "0EEEEEEE" + BITMAP "0E555EE0" + BITMAP "EEEEE0E0" + + + BITMAP "00000000" + BITMAP "E000E000" + BITMAP "E500E000" + BITMAP "EE5EE000" + BITMAP "EE555000" + BITMAP "52252EE0" + BITMAP "52252E00" + BITMAP "FFE5EFFF" + + BITMAP "5EEEEE00" + BITMAP "FFEEFFF0" + BITMAP "E5EEE000" + BITMAP "EEE0E500" + BITMAP "EEE0E500" + BITMAP "05E0E500" + BITMAP "05E0E500" + BITMAP "0EE0EE00" + + + BITMAP "00000000" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "EE000EE5" + BITMAP "EE0000E5" + BITMAP "EE0000FF" + + BITMAP "EE0000E5" + BITMAP "0EE0000F" + BITMAP "0EE0EEEE" + BITMAP "00EEEEEE" + BITMAP "00EEEEEE" + BITMAP "0EEEEEEE" + BITMAP "0E555EE0" + BITMAP "EEEEE0E0" + + + BITMAP "00000000" + BITMAP "000E0000" + BITMAP "500E0000" + BITMAP "E5EE0000" + BITMAP "E5550000" + BITMAP "2522EE00" + BITMAP "2522E000" + BITMAP "FE5EFFF0" + + BITMAP "EEEEE000" + BITMAP "FEEFFF00" + BITMAP "5EEE0000" + BITMAP "EEE0E500" + BITMAP "EEE0E500" + BITMAP "05E0E500" + BITMAP "05E0E500" + BITMAP "0EE0EE00" + + + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "00000EE5" + BITMAP "EE0000E5" + BITMAP "EE0000FF" + BITMAP "EE0000E5" + + BITMAP "EE00000F" + BITMAP "0EE00EEE" + BITMAP "0EE0EEEE" + BITMAP "00EEEEEE" + BITMAP "00EEEEEE" + BITMAP "0EEEEEEE" + BITMAP "0E555EE0" + BITMAP "EEEEE0E0" + + + BITMAP "00000000" + BITMAP "5000E000" + BITMAP "E5EEE000" + BITMAP "E5EE0000" + BITMAP "2555EE00" + BITMAP "2522E000" + BITMAP "FE22FFF0" + BITMAP "EEEEE000" + + BITMAP "FEEFFF00" + BITMAP "5EEE0000" + BITMAP "5EEE0000" + BITMAP "EEE0E500" + BITMAP "EEE0E500" + BITMAP "05E0E500" + BITMAP "05E0E500" + BITMAP "0EE0EE00" + + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "0000000E" + BITMAP "EE000EE5" + BITMAP "EE0000E5" + BITMAP "EE0000E5" + + BITMAP "EE0000FF" + BITMAP "0EE0000E" + BITMAP "0EE0EEEF" + BITMAP "00EEEEEE" + BITMAP "00EEEEEE" + BITMAP "0EEEEEEE" + BITMAP "0E555EE0" + BITMAP "EEEEE0E0" + + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "000E0000" + BITMAP "55EE0000" + BITMAP "E5550000" + BITMAP "5555EE00" + BITMAP "2522E000" + BITMAP "2E22E000" + + BITMAP "EEEEFFF0" + BITMAP "EEEEE000" + BITMAP "FEEFFF00" + BITMAP "EEE0E500" + BITMAP "EEE0E500" + BITMAP "05E0E500" + BITMAP "05E0E500" + BITMAP "0EE0EE00" + + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00008000" + BITMAP "00008855" + BITMAP "00005558" + BITMAP "00885555" + BITMAP "00082252" + BITMAP "00082282" + + BITMAP "0FFF8888" + BITMAP "00088888" + BITMAP "00FFF88F" + BITMAP "00580888" + BITMAP "00580888" + BITMAP "00580850" + BITMAP "00580850" + BITMAP "00880880" + + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "58800088" + BITMAP "58000088" + BITMAP "58000088" + + BITMAP "FF000088" + BITMAP "80000880" + BITMAP "F8880880" + BITMAP "88888800" + BITMAP "88888800" + BITMAP "88888880" + BITMAP "08855580" + BITMAP "08088888" + + + BITMAP "00000000" + BITMAP "00080005" + BITMAP "00088858" + BITMAP "00008858" + BITMAP "00885552" + BITMAP "00082252" + BITMAP "0FFF228F" + BITMAP "00088888" + + BITMAP "00FFF88F" + BITMAP "00008885" + BITMAP "00008885" + BITMAP "00580888" + BITMAP "00580888" + BITMAP "00580850" + BITMAP "00580850" + BITMAP "00880880" + + + BITMAP "80000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "58800000" + BITMAP "58000088" + BITMAP "FF000088" + BITMAP "58000088" + + BITMAP "F0000088" + BITMAP "88800880" + BITMAP "88880880" + BITMAP "88888800" + BITMAP "88888800" + BITMAP "88888880" + BITMAP "08855580" + BITMAP "08088888" + + + BITMAP "00000000" + BITMAP "00008000" + BITMAP "00008005" + BITMAP "00008858" + BITMAP "00005558" + BITMAP "00882252" + BITMAP "00082252" + BITMAP "0FFF858F" + + BITMAP "00088888" + BITMAP "00FFF88F" + BITMAP "00008885" + BITMAP "00580888" + BITMAP "00580888" + BITMAP "00580850" + BITMAP "00580850" + BITMAP "00880880" + + + BITMAP "00000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "80000000" + BITMAP "58800088" + BITMAP "58000088" + BITMAP "FF000088" + + BITMAP "58000088" + BITMAP "F0000880" + BITMAP "88880880" + BITMAP "88888800" + BITMAP "88888800" + BITMAP "88888880" + BITMAP "08855580" + BITMAP "08088888" + + + BITMAP "00000000" + BITMAP "00080008" + BITMAP "00080058" + BITMAP "00088588" + BITMAP "00055588" + BITMAP "08825225" + BITMAP "00825225" + BITMAP "FFF858FF" + + BITMAP "00888885" + BITMAP "0FFF88FF" + BITMAP "00088858" + BITMAP "00580888" + BITMAP "00580888" + BITMAP "00580850" + BITMAP "00580850" + BITMAP "00880880" + + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "88000088" + BITMAP "80000088" + BITMAP "F0000088" + + BITMAP "80000088" + BITMAP "00000880" + BITMAP "88880880" + BITMAP "88888800" + BITMAP "88888800" + BITMAP "88888880" + BITMAP "08855580" + BITMAP "08088888" + + From 3e6c910cd668432d28913abde200bc28dfe64bce Mon Sep 17 00:00:00 2001 From: visrealm Date: Tue, 29 Apr 2025 20:26:05 +0930 Subject: [PATCH 031/155] Added support for multiple passed-in constants. Syntax: 'cvbasic -DMYCONST=123 input.bas output.asm' which injects CONST MYCONST=123 --- cvbasic.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 0b5a946..f79bff2 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5976,11 +5976,11 @@ int main(int argc, char *argv[]) machine = COLECOVISION; while (machine < TOTAL_TARGETS) { if (machine == COLECOVISION) - fprintf(stderr, " cvbasic input.bas output.asm [library_path]\n"); + fprintf(stderr, " cvbasic [-DMYCONST=123] input.bas output.asm [library_path]\n"); else - fprintf(stderr, " cvbasic --%s input.bas output.asm [library_path]\n", consoles[machine].name); + fprintf(stderr, " cvbasic --%s [-DMYCONST=123] input.bas output.asm [library_path]\n", consoles[machine].name); if (consoles[machine].options[0]) - fprintf(stderr, " cvbasic --%s %s input.bas output.asm [library_path]\n", consoles[machine].name, consoles[machine].options); + fprintf(stderr, " cvbasic --%s %s [-DMYCONST=123] input.bas output.asm [library_path]\n", consoles[machine].name, consoles[machine].options); fprintf(stderr, " %s\n", consoles[machine].description); machine++; @@ -6078,6 +6078,28 @@ int main(int argc, char *argv[]) exit(2); } } + if (argv[c][0] == '-' && argv[c][1] == 'D') { + int i = 1; + char ch = 0; + struct constant *d = NULL; + while (ch = argv[c][++i]) { + if (!isalnum(ch) && ch != '_' && ch != '#' && ch != '=') { + fprintf(stderr, "%s name includes invalid characters.\n", argv[c]); + exit(2); + } + if (ch == '=') { + argv[c][i] = '\0'; + d = constant_add(&argv[c][2]); + d->value = atoi(&argv[c][i + 1]); + break; + } + } + if (d == NULL) { + fprintf(stderr, "%s missing assignment. Syntax: -DMYCONSTANT=123\n", argv[c]); + exit(2); + } + c++; + } strcpy(current_file, argv[c]); err_code = 0; input = fopen(current_file, "r"); From ed890cdff51c661837932004fdb10cde3b72e765 Mon Sep 17 00:00:00 2001 From: visrealm Date: Tue, 29 Apr 2025 20:39:35 +0930 Subject: [PATCH 032/155] updated manual.txt CONST section to show passed-in constants --- manual.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/manual.txt b/manual.txt index 4e44596..ae54293 100644 --- a/manual.txt +++ b/manual.txt @@ -206,6 +206,11 @@ The following statements are available: Constants that start with the # prefix are treated as 16-bit numbers, and if this isn't present then the constant will be treated as an 8-bit number. + + Constants can be passed-in to CVBasic via the command-line: + + cvbasic -DMYCONST=123 in.bas output.asm + cvbasic -D#MYBIGCONST=12345 in.bas output.asm GOTO label From f8f8a5c60b59e5fb33b99b4c0b04b5ff25982652 Mon Sep 17 00:00:00 2001 From: visrealm Date: Wed, 30 Apr 2025 14:47:54 +0930 Subject: [PATCH 033/155] Allow multiple -D command-line arguments --- cvbasic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index f79bff2..c9f0b21 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -6078,7 +6078,11 @@ int main(int argc, char *argv[]) exit(2); } } - if (argv[c][0] == '-' && argv[c][1] == 'D') { + + /* + ** passed-in constants + */ + while (argv[c][0] == '-' && argv[c][1] == 'D') { int i = 1; char ch = 0; struct constant *d = NULL; @@ -6095,11 +6099,12 @@ int main(int argc, char *argv[]) } } if (d == NULL) { - fprintf(stderr, "%s missing assignment. Syntax: -DMYCONSTANT=123\n", argv[c]); + fprintf(stderr, "%s missing assignment. Syntax: -DMYCONSTANT=123 -D#MYBIGCONSTANT=12345\n", argv[c]); exit(2); } c++; } + strcpy(current_file, argv[c]); err_code = 0; input = fopen(current_file, "r"); From 0348d6315c78314081c163fb9bc1fefcdb7361dd Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 1 May 2025 22:54:54 -0600 Subject: [PATCH 034/155] Command-line constants now supported in lowercase, detects redefinition. CHR$ corrected for TI-99/4A --- cvbasic.c | 33 +- test1.asm | 4163 +++++++++++++++++++++++++++++++++++++++++++++++++++++ test1.bas | 2 + 3 files changed, 4189 insertions(+), 9 deletions(-) create mode 100644 test1.asm create mode 100644 test1.bas diff --git a/cvbasic.c b/cvbasic.c index c9f0b21..ad09815 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3481,10 +3481,12 @@ void compile_statement(int check_for_else) emit_error("syntax error in CHR$"); else get_lex(); - if (target == CPU_6502) + if (target == CPU_6502) { cpu6502_noop("TAX"); - else if (target == CPU_9900) + } else if (target == CPU_9900) { cpu9900_2op("mov", "r0", "r2"); + cpu9900_1op("swpb", "r2"); + } generic_call("print_char"); } else { type = evaluate_expression(1, TYPE_16, 0); @@ -6080,22 +6082,35 @@ int main(int argc, char *argv[]) } /* - ** passed-in constants + ** Passed-in constants */ - while (argv[c][0] == '-' && argv[c][1] == 'D') { + while (argv[c][0] == '-' && tolower(argv[c][1]) == 'd') { int i = 1; char ch = 0; + char *p = name; struct constant *d = NULL; - while (ch = argv[c][++i]) { + + while (1) { + ch = argv[c][++i]; + if (ch == '\0') + break; if (!isalnum(ch) && ch != '_' && ch != '#' && ch != '=') { fprintf(stderr, "%s name includes invalid characters.\n", argv[c]); exit(2); - } + } if (ch == '=') { - argv[c][i] = '\0'; - d = constant_add(&argv[c][2]); - d->value = atoi(&argv[c][i + 1]); + *p = '\0'; + d = constant_search(name); + if (d != NULL) { + fprintf(stderr, "constant redefined %s\n", argv[c]); + } else { + d = constant_add(name); + d->value = atoi(&argv[c][i + 1]); + } break; + } else { + if (p < name + sizeof(name) - 1) + *p++ = toupper(ch); } } if (d == NULL) { diff --git a/test1.asm b/test1.asm new file mode 100644 index 0000000..ac95b4c --- /dev/null +++ b/test1.asm @@ -0,0 +1,4163 @@ + ; CVBasic compiler v0.8.0 Apr/26/2025 + ; Command: ./cvbasic -Dmyconst=7 test1.bas test1.asm + ; Created: Thu May 1 22:53:44 2025 + +COLECO: equ 1 +SG1000: equ 0 +MSX: equ 0 +SGM: equ 0 +SVI: equ 0 +SORD: equ 0 +MEMOTECH: equ 0 +EINSTEIN: equ 0 +CPM: equ 0 +PENCIL: equ 0 +PV2000: equ 0 +TI99: equ 0 +NABU: equ 0 +SMS: equ 0 + +CVBASIC_MUSIC_PLAYER: equ 0 +CVBASIC_COMPRESSION: equ 0 +CVBASIC_BANK_SWITCHING: equ 0 +CVBASIC_BANK_ROM_SIZE: equ 0 + +BASE_RAM: equ $7000 ; Base of RAM +RAM_SIZE: equ $0400 ; Base of RAM +STACK: equ $7400 ; Base stack pointer +VDP: equ $be ; VDP port (write) +VDPR: equ $be ; VDP port (read) +PSG: equ $ff ; PSG port (write) + + ; + ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. + ; Added 16-bit multiply, division, modulo, and abs. + ; Added random generator. Added sound routines. + ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. + ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/14/2024. Added _sgn16. + ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. + ; Revision date: Apr/11/2024. Added support for formatting numbers. Added + ; support for Super Game Module. + ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. + ; Shorter mode setting subroutines. + ; Revision date: Apr/26/2024. Interruption handler saves current bank. + ; Revision date: Apr/27/2024. Music player now supports bank switching. + ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller + ; support with keyboard (code by SiRioKD) + ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. + ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. + ; Revision date: Jun/17/2024. Added SVI-328 support. + ; Revision date: Aug/01/2024. Added Sord M5 support. + ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech + ; support. + ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support + ; for Casio PV-2000. + ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, + ; and Casio PV-2000. + ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision + ; with flicker flag). + ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number + ; keys values were inverted. + ; Revision date: Nov/12/2024. Saves the VDP status. + ; + +JOYSEL: equ $c0 +KEYSEL: equ $80 + +JOY1: equ $fc-$20*(SG1000+SMS) +JOY2: equ $ff-$22*(SG1000+SMS) + + if COLECO + org $8000 + if PENCIL + db "COPYRIGHT SOUNDIC" + jp START + jp nmi_handler + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + db "CVBASIC!POWERED BY!2024!" + else + db $55,$aa + dw 0 + dw 0 + dw 0 + dw 0 + dw START + + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + + jp nmi_handler + endif + endif + if SG1000+SMS+SVI + org $0000 + di + ld sp,STACK + jp START + db $ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp nmi_handler ; It should be called int_handler. + endif + if MSX + ORG $4000 + db "AB" + dw START + dw $0000 + dw $0000 + dw $0000 + dw $0000 + +WRTPSG: equ $0093 +RDPSG: equ $0096 + + endif + if SORD + ORG $2000 + db $02 ; Avoid checking $4000 + dw START ; Start address. + dw $002e ; Prestart address (just point to RET in BIOS). + endif + if PV2000 + ORG $C000 + jp START + endif + + if MEMOTECH + if CPM + org $0100 + else + org $40fc + dw rom_start + dw rom_end-rom_start + endif +rom_start: + jp START + db 0,0,0,0,0 + dw nmi_handler + dw null_vector + dw null_vector + dw rom_start + +null_vector: + ei + reti + endif + if EINSTEIN + org $0100 +rom_start: + jp START + db 0,0,0,0,0 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + endif + if NABU + if CPM + org $0100 + else + org $140d + endif + nop + nop + nop + jp START + times $100-($&255) db $ff +nabu_int: + dw null_vector + dw null_vector + dw keyboard_handler + dw nmi_handler + dw null_vector + dw null_vector + dw null_vector + dw null_vector + +null_vector: + ei + reti + endif + + if SVI +WRTPSG: + out ($88),a + push af + ld a,e + out ($8c),a + pop af + ret + +RDPSG: + out ($88),a + push af + pop af + in a,($90) + ret + endif + + if EINSTEIN +WRTPSG: + out ($02),a + push af + ld a,e + out ($03),a + pop af + ret + +RDPSG: + out ($02),a + push af + pop af + in a,($02) + ret + endif + + if NABU +WRTPSG: + out ($41),a + push af + ld a,e + out ($40),a + pop af + ret + +RDPSG: + out ($41),a + push af + pop af + in a,($40) + ret + endif + + if PV2000 + ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) +WRTVDP: + ld a,b + ld (VDP+1),a + ld a,c + or $80 + ld (VDP+1),a + ret + +SETWRT: + ld a,l + ld (VDP+1),a + ld a,h + or $40 + ld (VDP+1),a + ret + +SETRD: + ld a,l + ld (VDP+1),a + ld a,h + and $3f + ld (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + ld (VDP),a + ret + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + ld a,(VDP) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: ld (VDP),a ; 13 14 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 37 42 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + ld a,(VDP) + ld (de),a + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + EX DE,HL + CALL SETWRT + EX DE,HL + DEC BC + INC C + LD A,B + LD B,C + INC A + LD C,A +.1: + LD A,(HL) ; 7 8 + LD (VDP),A ; 13 14 + INC HL ; 6 7 + DJNZ .1 ; 13 14 + DEC C ; 4 5 + JP NZ,.1 ; 10 11 + RET + else + ; Normal platforms with VDP connected via ports (IORQ) +WRTVDP: + ld a,b + out (VDP+1),a + ld a,c + or $80 + out (VDP+1),a + ret + +SETWRT: + ld a,l + out (VDP+1),a + ld a,h + or $40 + out (VDP+1),a + ret + +SETRD: + ld a,l + out (VDP+1),a + ld a,h + and $3f + out (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + out (VDP),a + ret + + if SG1000+SMS + db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Located at $0066 + ei ; NMI handler (pause button) + retn + endif + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + in a,(VDPR) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) +.1: out (VDP),a ; 11 12 + dec bc ; 6 7 + bit 7,b ; 8 10 + jp z,.1 ; 10 11 + ; -- -- + ; 35 40 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + in a,(VDP) + ld (de),a + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + ex de,hl + call SETWRT + ex de,hl + dec bc + inc c + ld a,b + ld b,c + inc a + ld c,VDP +.1: + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + outi + jp nz,.1 + dec a + jp nz,.1 + ret + endif + + if SMS + else +LDIRVM3: + call .1 + call .1 +.1: push hl + push de + push bc + call LDIRVM + pop bc + pop de + ld a,d + add a,8 + ld d,a + pop hl + ret + endif + +DISSCR: + call nmi_off + ld bc,$a201 + call WRTVDP + jp nmi_on + +ENASCR: + call nmi_off + ld bc,$e201 + call WRTVDP + jp nmi_on + +CPYBLK: + pop hl + ex af,af' + pop af + ld b,a + pop af + ld c,a + pop de + ex (sp),hl + call nmi_off +.1: push bc + push hl + push de + ld b,0 + call LDIRVM + pop hl + if SMS + ld bc,$0040 + else + ld bc,$0020 + endif + add hl,bc + ex de,hl + pop hl + ex af,af' + ld c,a + ld b,0 + add hl,bc + ex af,af' + pop bc + djnz .1 + jp nmi_on + +nmi_off: + if COLECO+PV2000 + push hl + ld hl,mode + set 0,(hl) + pop hl + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + di + endif + ret + +nmi_on: + if COLECO+PV2000 + push af + push hl + ld hl,mode + res 0,(hl) + nop + bit 1,(hl) + jp nz,nmi_handler.0 + pop hl + pop af + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + ei + endif + ret + + if COLECO +keypad_table: + db $0f,$08,$04,$05,$0c,$07,$0b,$02 + db $0d,$0a,$00,$09,$03,$01,$06,$0f + endif + +cls: + if SMS + ld hl,$3800 + ld (cursor),hl + di + call SETWRT +.1: ld a,$20 ; 7 + out (VDP),a ; 11 + inc hl ; 6 + inc hl ; 6 + ld a,$00 ; 7 + out (VDP),a ; 11 + ld a,h ; 4 + cp $3e ; 7 + jp nz,.1 ; 10 + ei + ret + else + ld hl,$1800 + ld (cursor),hl + ld bc,$0300 + ld a,$20 + call nmi_off + call FILVRM + jp nmi_on + endif + +print_string: + ld c,a + ld b,0 + ld de,(cursor) + if SMS + ld a,d + and $07 + or $38 + ld d,a + else + ld a,d + and $07 + or $18 + ld d,a + endif + push de + push bc + call nmi_off + if SMS + ex de,hl +.1: ld a,(de) + call WRTVRM + inc de + inc hl + xor a + call WRTVRM + inc hl + dec bc + ld a,b + or c + jp nz,.1 + else + call LDIRVM + endif + call nmi_on + pop bc + pop hl + add hl,bc + if SMS + add hl,bc + endif + ld (cursor),hl + ret + +print_number: + ld b,0 + call nmi_off +print_number5: + ld de,10000 + call print_digit +print_number4: + ld de,1000 + call print_digit +print_number3: + ld de,100 + call print_digit +print_number2: + ld de,10 + call print_digit +print_number1: + ld de,1 + ld b,e + call print_digit + jp nmi_on + +print_digit: + ld a,$2f + or a +.2: inc a + sbc hl,de + jp nc,.2 + add hl,de + cp $30 + jr nz,.3 + ld a,b + or a + ret z + dec a + jr z,.4 + ld a,c + jr print_char +.4: + ld a,$30 +.3: ld b,1 + +print_char: + push hl + ld hl,(cursor) + ex af,af' + ld a,h + and $07 + if SMS + or $38 + else + or $18 + endif + ld h,a + ex af,af' + call WRTVRM + inc hl + if SMS + xor a + call WRTVRM + inc hl + endif + ld (cursor),hl + pop hl + ret + +define_char: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + di + call LDIRVM + ei + ret + else + call nmi_off + ld a,(mode) + and 8 + jr nz,.1 + call LDIRVM3 + jp nmi_on + +.1: call LDIRVM + jp nmi_on + endif + +define_color: + if SMS + ret + else + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d + call nmi_off + call LDIRVM3 + jp nmi_on + endif + +define_sprite: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + if SMS + set 1,h + else + ld h,$07 + endif + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ex de,hl + call nmi_off + call LDIRVM + jp nmi_on + endif + +update_sprite: + if SMS + pop bc ; Pop return address. + pop de ; 3th. argument in D (Y-coordinate) + ld e,a ; 4th. argument in E (frame) + pop af ; 2nd. argument in A (X-coordinate) + pop hl ; 1st. argument in H (sprite number) + push bc ; Push return address. + ld l,h + res 7,l + res 6,l + ld h,sprites>>8 + ld (hl),a + sla l + set 7,l + ld (hl),d + inc l + ld (hl),e + else + pop bc + ld (sprite_data+3),a + pop af + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + ld de,sprites + add a,a + add a,a + if SORD + or $80 + endif + ld e,a + ld hl,sprite_data + ld bc,4 + ldir + endif + ret + + ; Fast 16-bit multiplication. +_mul16: + ld b,h + ld c,l + ld a,16 + ld hl,0 +.1: + srl d + rr e + jr nc,.2 + add hl,bc +.2: sla c + rl b + dec a + jp nz,.1 + ret + + ; 16-bit signed modulo. + ; hl = hl % de +_mod16s: + ld a,h + or a + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _mod16 + pop af + ret p + jp _neg16 + + ; 16-bit signed division. + ; hl = hl / de +_div16s: + ld a,h + xor d + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _div16 + pop af + ret p + jp _neg16 + +_abs16: + bit 7,h + ret z +_neg16: + ld a,h + cpl + ld h,a + ld a,l + cpl + ld l,a + inc hl + ret + + ; Fast 16-bit division. + ; hl = hl / de +_div16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + rl c + rl b + ld h,b + ld l,c + ret + + ; Fast 16-bit modulo. +_mod16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + ret + +_sgn16: + ld a,h + or l + ret z + bit 7,h + ld hl,$ffff + ret nz + inc hl + inc hl + ret + + ; Random number generator. + ; From my game Mecha Eight. +random: + ld hl,(lfsr) + ld a,h + or l + jr nz,.0 + ld hl,$7811 +.0: ld a,h + and $80 + ld b,a + ld a,h + and $02 + rrca + rrca + xor b + ld b,a + ld a,h + and $01 + rrca + xor b + ld b,a + ld a,l + and $20 + rlca + rlca + xor b + rlca + rr h + rr l + ld (lfsr),hl + ret + +sn76489_freq: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld b,a + ld a,l + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + and $3f + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_vol: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + cpl + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_control: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + and $0f + or $e0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +ay3_reg: + if COLECO + push af + ld a,b + out ($50),a + pop af + out ($51),a + ret + endif + if SG1000+SORD+SMS+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,a + ld a,b + jp WRTPSG + endif + +ay3_freq: + if COLECO + out ($50),a + push af + ld a,l + out ($51),a + pop af + inc a + out ($50),a + push af + ld a,h + and $0f + out ($51),a + pop af + ret + endif + if SG1000+SMS+SORD+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,l + call WRTPSG + ld e,h + inc a + jp WRTPSG + endif + + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ; Required for SG1000 and Sega Master System as both don't have a BIOS + ; Required for SVI because we don't have access to BIOS in cartridge. + ; Required for Sord M5 because it doesn't provide an ASCII charset. + ; Required for Memotech/Einstein because CP/M uses the memory. + ; My personal font for TMS9928. + ; + ; Patterned after the TMS9928 programming manual 6x8 letters + ; with better lowercase letters, also I made a proper + ; AT sign. + ; +font_bitmaps: + db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space + db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! + db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " + db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # + db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ + db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % + db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & + db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' + db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( + db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) + db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * + db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + + db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , + db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - + db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . + db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / + db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 + db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 + db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 + db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 + db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 + db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 + db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 + db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 + db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 + db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 + db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : + db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; + db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < + db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = + db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > + db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? + db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ + db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A + db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B + db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C + db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D + db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E + db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F + db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G + db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H + db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I + db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J + db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K + db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L + db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M + db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N + db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O + db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P + db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q + db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R + db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S + db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T + db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U + db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V + db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W + db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X + db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y + db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z + db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ + db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ + db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] + db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E + db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ + db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 + db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a + db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b + db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c + db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d + db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e + db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f + db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g + db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h + db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i + db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j + db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k + db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l + db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m + db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n + db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o + db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p + db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q + db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r + db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s + db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t + db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u + db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v + db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w + db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x + db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y + db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z + db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { + db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | + db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } + db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e + db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f + endif + + if SMS +palette_load: + push hl + di + ld hl,$c000 + call SETWRT + pop hl + ld bc,32*256+VDP + outi + jp nz,$-2 + ei + ret + +mode_4: + di + ld bc,$0400 + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) + call WRTVDP + ld bc,$ff03 ; Not used (required value for SMS1) + call WRTVDP + ld bc,$0704 ; Not used (required value for SMS1) + call WRTVDP + ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) + call WRTVDP + ld bc,$0706 ; $2000 for sprites bitmaps (or $03 for $0000) + call WRTVDP + ld bc,$0007 + call WRTVDP + ld bc,$0008 ; Background X scroll + call WRTVDP + ld bc,$0009 ; Background Y scroll + call WRTVDP + ld hl,$20*32 ; Point to space character bitmap + call SETWRT + ld hl,font_bitmaps + ld c,96 +.1: ld b,8 +.2: ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + inc hl + djnz .2 + dec c + jp nz,.1 + ei + call cls + di + ld hl,$3f00 + ld bc,$0040 + ld a,$e0 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,63 + ld (hl),$e0 + ldir + ei + ld hl,.3 + call palette_load + jp ENASCR + + ; TMS9118-alike palette +.3: + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + + else +vdp_generic_mode: + call nmi_off + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0602 ; $1800 for pattern table. + call WRTVDP + ld b,d + ld c,$03 ; for color table. + call WRTVDP + ld b,e + ld c,$04 ; for bitmap table. + call WRTVDP + ld bc,$3605 ; $1b00 for sprite attribute table. + call WRTVDP + ld bc,$0706 ; $3800 for sprites bitmaps. + call WRTVDP + ld bc,$0107 + jp WRTVDP + +mode_0: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls +vdp_generic_sprites: + call nmi_off + ld hl,$1b00 + ld bc,$0080 + ld a,$d1 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,127 + ld (hl),$d1 + ldir + call nmi_on + jp ENASCR + +mode_1: + ld hl,mode + res 3,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld hl,$0000 + ld bc,$1800 + xor a + call FILVRM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + ld hl,$1800 +.1: call nmi_off + ld b,32 +.2: ld a,l + call WRTVRM + inc hl + djnz .2 + call nmi_on + ld a,h + cp $1b + jp nz,.1 + jp vdp_generic_sprites + +mode_2: + ld hl,mode + set 3,(hl) + ld bc,$0000 + ld de,$8000 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$0020 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites + endif + + if MSX +ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) +RSLREG: EQU $0138 ; Read slot status in A + + ; + ; Get slot mapping + ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) + ; A = Current slot selection status (CALL RSLREG) + ; +get_slot_mapping: + call rotate_slot + ld c,a + add a,$C1 ; EXPTBL + ld l,a + ld h,$FC + ld a,(hl) + and $80 ; Get expanded flag + or c + ld c,a + inc hl + inc hl + inc hl + inc hl + ld a,(hl) ; SLTTBL + call rotate_slot + rlca + rlca + or c ; A contains bit 7 = Marks expanded + ; bit 6 - 4 = Doesn't care + ; bit 3 - 2 = Secondary mapper + ; bit 1 - 0 = Primary mapper + ret + +rotate_slot: + push bc + dec b + inc b + jr z,.1 +.0: rrca + rrca + djnz .0 +.1: and 3 + pop bc + ret + + endif + +nmi_handler: + push af + push hl + ld hl,mode + bit 0,(hl) + jr z,.1 + set 1,(hl) + pop hl + pop af + retn + +.0: res 1,(hl) + +.1: push bc + push de + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fbf) + endif + if MSX + ld a,($bfff) + endif + push af + endif + if SORD+MEMOTECH + call ctc_reti + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + in a,(VDPR+1) + ld (vdp_status),a + endif + + ; + ; Update of sprite attribute table + ; + if SMS + bit 2,(hl) + jr z,.4 + ld hl,$3f00 + call SETWRT + ld hl,sprites + ld bc,$4000+VDP + outi + jp nz,$-2 + ld hl,$3f80 + call SETWRT + ld hl,sprites + ld bc,$8000+VDP + outi + jp nz,$-2 + jr .5 + +.4: ld hl,$3f00 + call SETWRT + ld a,(flicker) + inc a + and $3f + ld (flicker),a + ld l,a + ld h,sprites>>8 + ld bc,$4000+VDP + ld de,6 + outi + add hl,de + res 6,l + jp nz,$-5 + ld hl,$3f80 + call SETWRT + ld a,(flicker) + add a,a + or $80 + ld l,a + ld bc,$8000+VDP + ld de,12 + ld h,sprites>>8 + outi + nop + nop + nop + outi + add hl,de + set 7,l + jp nz,$-12 +.5: + else + ld bc,$8000+VDP + bit 2,(hl) + jr z,.4 + + ld hl,$1b00 + call SETWRT + ld hl,sprites +.7: + if PV2000 + ld a,(hl) + ld (VDP),a + inc hl + djnz .7 + else + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp nz,.7 + endif + jr .5 + +.4: + ld hl,$1b00 + call SETWRT + ld a,(flicker) + add a,$04 + ld (flicker),a + ld de,24 + ld b,128 + ld l,a + if SORD + else + ld h,sprites>>8 + endif +.6: + if SORD + set 7,l + ld h,sprites>>8 + else + res 7,l + endif + if PV2000 + ld a,(hl) ; 7 8 + ld (VDP),a ; 13 14 + inc hl ; 6 7 + dec b ; 4 5 + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + else + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + endif + add hl,de + jp nz,.6 +.5: + endif + + if COLECO + out (JOYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + or $b0 + ld b,a + in a,(JOY2) + or $b0 + ld c,a + + out (KEYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + ld d,a + in a,(JOY2) + ld e,a + + ld a,d + rlca + or $7f + and b + cpl + ld (joy1_data),a + + ld a,e + rlca + or $7f + and c + cpl + ld (joy2_data),a + + ld a,d + and $0f + ld c,a + ld b,0 + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key1_data),a + + ld a,e + and $0f + ld c,a + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key2_data),a + endif + if SG1000+SMS + ld a,$07 + out ($de),a + ld b,$ff + in a,(JOY1) + ld h,a + in a,(JOY2) + ld l,a + in a,($de) + cp 7 + jp nz,.sg1000 + + ld a,$00 + out ($de),a + in a,($dc) + rra + ld c,1 + jr nc,.sg1 + in a,($dd) + rra + ld c,8 + jr nc,.sg1 + ld a,$01 + out ($de),a + in a,($dc) + rra + ld c,2 + jr nc,.sg1 + in a,($dd) + rra + ld c,9 + jr nc,.sg1 + ld a,$02 + out ($de),a + in a,($dc) + rra + ld c,3 + jr nc,.sg1 + in a,($dd) + rra + ld c,0 + jr nc,.sg1 + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a + ld c,10 + jr z,.sg1 + rra + ld c,4 + jr nc,.sg1 + ld a,$04 + out ($de),a + in a,($dc) + rra + ld c,5 + jr nc,.sg1 + ld a,$05 + out ($de),a + in a,($dc) + bit 6,a + ld c,11 + jr z,.sg1 + rra + ld c,6 + jr nc,.sg1 + ld a,$06 + out ($de),a + in a,($dc) + rra + ld c,7 + jr nc,.sg1 + ld c,15 +.sg1: ld a,c + ld (key1_data),a + + ld a,$04 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard down. + jr nz,$+4 + res 1,h + ld a,$05 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard left. + jr nz,$+4 + res 2,h + ld a,$06 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard right. + jr nz,$+4 + res 3,h + bit 6,a ; Keyboard up. + jr nz,$+4 + res 0,h + ld a,$02 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Ins + jr nz,$+4 + res 4,h + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Del + jr nz,$+4 + res 5,h +.sg1000: + bit 0,h + jr nz,$+4 + res 0,b + bit 1,h + jr nz,$+4 + res 2,b + bit 2,h + jr nz,$+4 + res 3,b + bit 3,h + jr nz,$+4 + res 1,b + bit 4,h + jr nz,$+4 + res 6,b + bit 5,h + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + + ld a,$ff + bit 6,h + jr nz,$+4 + res 0,a + bit 7,h + jr nz,$+4 + res 2,a + + bit 0,l + jr nz,$+4 + res 3,a + bit 1,l + jr nz,$+4 + res 1,a + bit 2,l + jr nz,$+4 + res 4,a + bit 3,l + jr nz,$+4 + res 5,a + cpl + ld (joy2_data),a + + endif + if MSX + ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php + ld a,15 + call RDPSG + and $b0 + or $4f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + ld b,$ff + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy2_data),a + + in a,($aa) + and $f0 + or $00 + out ($aa),a + in a,($a9) + cp $ff + ld c,$ff + jr nz,.key1 + in a,($aa) + and $f0 + or $01 + out ($aa),a + in a,($a9) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + in a,($aa) + and $f0 + or $07 + out ($aa),a + in a,($a9) + bit 5,a ; BS + ld c,$0a + jr z,.key2 + bit 7,a ; RET + ld c,$0b + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + in a,($aa) + and $f0 + or $08 + out ($aa),a + in a,($a9) + bit 5,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 6,a + jr nz,$+4 + res 2,b + bit 4,a + jr nz,$+4 + res 3,b + bit 0,a + jr nz,$+4 + res 6,b + in a,($aa) + and $f0 + or $04 + out ($aa),a + in a,($a9) + bit 2,a + jr nz,$+4 + res 7,b + + ld a,15 + call RDPSG + and $b0 + or $0f + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + + ld a,b + cpl + ld (joy1_data),a + endif + if SVI + ld a,14 + call RDPSG + ld b,$ff + bit 4,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 5,a + jr nz,$+4 + res 2,b + bit 6,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 5,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy2_data),a + + ld a,$10 + out ($96),a + in a,($99) + cp $ff + ld c,$ff + jr nz,.key1 + ld a,$11 + out ($96),a + in a,($99) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + ld a,$16 + out ($96),a + in a,($99) + bit 6,a + ld c,$0b + jr z,.key2 + ld a,$15 + out ($96),a + in a,($99) + bit 6,a + ld c,$0a + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + ld a,$15 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 0,b + ld a,$18 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 1,b + ld a,$17 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 2,b + ld a,$16 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 3,b + ld a,$18 + out ($96),a + in a,($99) + bit 0,a + jr nz,$+4 + res 6,b + ld a,$13 + out ($96),a + in a,($99) + bit 5,a + jr nz,$+4 + res 7,b + + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 4,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy1_data),a + endif + if SORD + ld bc,$ffff + in a,($37) ; Read joystick + rra + jr nc,$+4 + res 1,b + rra + jr nc,$+4 + res 0,b + rra + jr nc,$+4 + res 3,b + rra + jr nc,$+4 + res 2,b + rra + jr nc,$+4 + res 1,c + rra + jr nc,$+4 + res 0,c + rra + jr nc,$+4 + res 3,c + rra + jr nc,$+4 + res 2,c + in a,($31) + rra + jr nc,$+4 + res 6,b + rra + jr nc,$+4 + res 7,b + rra + rra + rra + jr nc,$+4 + res 6,c + rra + jr nc,$+4 + res 7,c + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + in a,($31) ; Keyboard 1-8 + or a + ld c,$00 + jr nz,.key3 + in a,($35) + bit 0,a ; 9 + ld c,$09 + jr nz,.key5 + bit 1,a ; 0 + ld c,$00 + jr nz,.key5 + bit 7,a ; Backspace + ld c,$0a + jr nz,.key5 + in a,($30) + bit 7,a ; Enter + ld c,$0b + jr nz,.key5 + ld c,$0f + jr .key5 + +.key3: rra + inc c + jr nc,.key3 +.key5: + ld a,c + ld (key1_data),a + + endif + if MEMOTECH + ld bc,$ffff + + ld a,$fb + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 0,b ; Up direction. + bit 3,a ; Y + jr nz,$+4 + res 0,c ; Up direction. + + ld a,$ef + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 1,b ; Right key. + ld a,$bf + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 2,b ; Down key. + ld a,$f7 + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 3,b ; Left key. + ld a,$df + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a ; Home key. + jr nz,$+4 + res 6,b ; Button 1 + + ld a,$7F + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 2,a ; B + jr nz,$+4 + res 0,c ; Up key. + bit 1,a ; C + jr nz,$+4 + res 1,c ; Right key. + bit 3,a ; M + jr nz,$+4 + res 2,c ; Down key. + bit 0,a ; Z + jr nz,$+4 + res 3,c ; Left key. + bit 5,a ; - + jr nz,$+4 + res 7,c ; Button 2 for player 2. + bit 7,a ; - + jr nz,$+4 + res 7,b ; Button 2 for player 1. + in a,($06) ; Read keyboard data. + bit 0,a ; Space + jr nz,$+4 + res 6,c ; Button 1. + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$fe + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + ld b,1 + jr nc,.mt1 + rra + ld b,3 + jr nc,.mt1 + rra + ld b,5 + jr nc,.mt1 + rra + ld b,7 + jr nc,.mt1 + rra + ld b,9 + jr nc,.mt1 + ld a,$df + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + bit 6,a + ld b,11 + jr z,.mt1 + ld a,$fd + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + rra + ld b,2 + jr nc,.mt1 + rra + ld b,4 + jr nc,.mt1 + rra + ld b,6 + jr nc,.mt1 + rra + ld b,8 + jr nc,.mt1 + rra + ld b,0 + jr nc,.mt1 + in a,($06) + rra + ld b,10 + jr nc,.mt1 + ld b,15 +.mt1: + ld a,b + ld (key1_data),a + endif + if EINSTEIN + ld bc,$ffff + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 0,b ; Up + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 4,a + jr nz,$+4 + res 1,b ; Right + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + jr nz,$+4 + res 2,b ; Down + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + jr nz,$+4 + res 3,b ; Left + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 6,b ; Fire + ld a,$0e + out ($02),a + ld a,$7f + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 0,a + jr nz,$+4 + res 7,b ; 2nd fire + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$0e + out ($02),a + ld a,$ef + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + rra + ld b,7 + jr nc,.te1 + rra + ld b,6 + jr nc,.te1 + rra + ld b,5 + jr nc,.te1 + rra + ld b,4 + jr nc,.te1 + rra + ld b,3 + jr nc,.te1 + rra + ld b,2 + jr nc,.te1 + rra + ld b,1 + jr nc,.te1 + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + ld b,8 + jr z,.te1 + bit 4,a + ld b,10 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + ld b,9 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + ld b,11 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 7,a + ld b,0 + jr z,.te1 + ld b,15 +.te1: + ld a,b + ld (key1_data),a + endif + if PV2000 + ld bc,$ffff + ld a,7 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 0,b + bit 0,a + jr z,$+4 + res 3,b + ld a,6 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 1,b + bit 0,a + jr z,$+4 + res 2,b + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 0,a + jr z,$+4 + res 6,b + bit 1,a + jr z,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + ld a,0 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + and $0f + ld b,$04 + jr nz,.pv1 + in a,($10) + and $0f + ld b,$08 + jr nz,.pv1 + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($10) + ld b,11 + bit 0,a + jr nz,.pv2 + ld a,4 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + ld b,10 + bit 3,a + jr nz,.pv2 + in a,($10) + ld b,9 + bit 0,a + jr nz,.pv2 + ld b,0 + bit 3,a + jr nz,.pv2 + ld b,15 + jr .pv2 + +.pv1: rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b +.pv2: ld a,b + ld (key1_data),a + endif + if NABU + ld a,(nabu_data0) + and $cf + ld (joy1_data),a + ld a,(nabu_data1) + and $cf + ld (joy2_data),a + ld a,(nabu_data2) + ld (key1_data),a + ld a,$0f + ld (nabu_data2),a + endif + + if CVBASIC_MUSIC_PLAYER + ld a,(music_mode) + or a + call nz,music_hardware + endif + + ld hl,(frame) + inc hl + ld (frame),hl + + ld hl,lfsr ; Make LFSR more random + inc (hl) + inc (hl) + inc (hl) + + if CVBASIC_MUSIC_PLAYER + ; + ; Music is played with a 50hz clock. + ; + ld a,(ntsc) + or a + jr z,.2 + ld a,(music_tick) + inc a + cp 6 + jr nz,$+3 + xor a + ld (music_tick),a + jr z,.3 +.2: + ld a,(music_mode) + or a + call nz,music_generate +.3: + endif + + if CVBASIC_BANK_SWITCHING + pop af + if COLECO + ld l,a + ld h,$ff + ld a,(hl) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + pop de + pop bc + pop hl + if COLECO + in a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + if SG1000+SMS+SVI+NABU + pop af + ei + reti + endif + if MSX + pop af + ret + endif + if SORD+MEMOTECH + pop af + ei + ret + +ctc_reti: + reti + endif + if EINSTEIN + pop af + ret + endif + if PV2000 + ld a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + + if NABU +keyboard_handler: + push af + push bc + push hl + in a,($90) + ld c,a + cp $0d ; Enter + ld a,11 + jr z,.8 + ld a,c + cp $7f ; Del + ld a,10 + jr z,.8 + ld a,c + cp $30 + jr c,.7 + cp $3a + jr nc,.7 + sub $30 +.8: ld (nabu_data2),a + jr .1 +.7: + cp $a0 + jr c,.2 + cp $c0 + jr c,.joystick +.2: + ld hl,nabu_data0 + cp $80 + jr nz,.3 + res 4,(hl) + jr .1 +.3: + cp $81 + jr nz,.4 + set 4,(hl) + jr .1 +.4: + cp $e0 + jr c,.1 + and $0f + ld b,2 + jr z,.5 + dec a + ld b,8 + jr z,.5 + dec a + ld b,1 + jr z,.5 + dec a + ld b,4 + jr z,.5 + dec a + ld b,$80 + jr z,.5 + dec a + ld b,$40 + jr nz,.1 +.5: bit 4,c + jr nz,.6 + ld a,(hl) + or b + ld (hl),a + jr .1 + +.6: + ld a,b + cpl + and (hl) + ld (hl),a + jr .1 + +.joystick: + ld hl,nabu_data0 + bit 4,(hl) + jr z,$+5 + ld hl,nabu_data1 + ld b,$00 + bit 3,c + jr z,$+4 + set 0,b + bit 2,c + jr z,$+4 + set 1,b + bit 1,c + jr z,$+4 + set 2,b + bit 0,c + jr z,$+4 + set 3,b + bit 4,c + jr z,$+4 + set 6,b + ld (hl),b +.1: + pop hl + pop bc + pop af + ei + reti + endif + if SORD +wait: + ld de,(frame) +.1: + ld hl,(frame) + or a + sbc hl,de + jr z,.1 + ret + endif + if EINSTEIN +wait: + in a,(VDP+1) + nop + in a,(VDP+1) + bit 7,a + jr z,$-4 + ld (vdp_status),a + jp nmi_handler + endif + + ; + ; The music player code comes from my + ; game Princess Quest for Colecovision (2012) + ; + + ; + ; Init music player. + ; +music_init: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$9f + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$bf + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$df + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ff + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ec + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 +MIX_BASE: equ $b8 + endif + if EINSTEIN+NABU +MIX_BASE: equ $78 + endif + if MSX+SVI+EINSTEIN+NABU + ld a,$08 + ld e,$00 + call WRTPSG + ld a,$09 + ld e,$00 + call WRTPSG + ld a,$0a + ld e,$00 + call WRTPSG + ld a,$07 + ld e,MIX_BASE + call WRTPSG + endif + if SGM + ld b,$08 + xor a + call ay3_reg + ld b,$09 + call ay3_reg + ld b,$0a + call ay3_reg + ld b,$07 + ld a,$b8 + call ay3_reg + endif + if CVBASIC_MUSIC_PLAYER + else + ret + endif + + if CVBASIC_MUSIC_PLAYER + ld a,$ff + ld (audio_vol4hw),a + ld a,$ec + ld (audio_control),a + ld a,MIX_BASE + ld (audio_mix),a + ld hl,music_silence + ; + ; Play a music. + ; HL = Pointer to music. + ; +music_play: + call nmi_off + ld a,(hl) + ld (music_timing),a + inc hl + ld (music_start),hl + ld (music_pointer),hl + xor a + ld (music_note_counter),a + inc a + ld (music_playing),a + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fbf) + endif + if MSX + ld a,($bfff) + endif + ld (music_bank),a + endif + jp nmi_on + + ; + ; Generates music. + ; +music_generate: + ld a,(audio_mix) + and $c0 + or $38 + ld (audio_mix),a + xor a ; Turn off all the sound channels. + ld l,a + ld h,a + ld (audio_vol1),hl ; audio_vol1/audio_vol2 + ld (audio_vol3),a + ld a,$ff + ld (audio_vol4hw),a + + ld a,(music_note_counter) + or a + jp nz,.6 + ld hl,(music_pointer) +.15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if COLECO + ld e,a + ld d,$ff + ld a,(de) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + ld ($7000),a + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.16 + ld e,d + ld d,0 + jr .17 + +.16: rlca + jr nc,.17 + ld e,0 +.17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.19: cp -3 ; Repeat music? + jp nz,.0 + ld hl,(music_start) + jr .15 + +.0: ld a,(music_timing) + and $3f ; Restart note time. + ld (music_note_counter),a + ld a,b + cp $3f ; Sustain? + jr z,.1 + rlca + rlca + and 3 + ld (music_instrument_1),a + ld a,b + and $3f + ld (music_note_1),a + xor a + ld (music_counter_1),a +.1: ld a,c + cp $3f + jr z,.2 + rlca + rlca + and 3 + ld (music_instrument_2),a + ld a,c + and $3f + ld (music_note_2),a + xor a + ld (music_counter_2),a +.2: ld a,d + cp $3f + jr z,.3 + rlca + rlca + and 3 + ld (music_instrument_3),a + ld a,d + and $3f + ld (music_note_3),a + xor a + ld (music_counter_3),a +.3: ld a,e + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + +.6: ld a,(music_note_1) + or a + jr z,.7 + ld bc,(music_instrument_1) + call music_note2freq + ld (audio_freq1),hl + ld (audio_vol1),a + +.7: ld a,(music_note_2) + or a + jr z,.8 + ld bc,(music_instrument_2) + call music_note2freq + ld (audio_freq2),hl + ld (audio_vol2),a + +.8: ld a,(music_note_3) + or a + jr z,.9 + ld bc,(music_instrument_3) + call music_note2freq + ld (audio_freq3),hl + ld (audio_vol3),a + +.9: ld a,(music_drum) + or a + jr z,.4 + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + cp 3 + jp nc,.4 +.10: ld a,5 + ld (audio_noise),a + call enable_drum + jr .4 + +.5: dec a ; 2 - Short durm. + jr nz,.11 + ld a,(music_counter_4) + or a + jp nz,.4 + ld a,8 + ld (audio_noise),a + call enable_drum + jr .4 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + cp 2 + jp c,.10 + cp b + jp c,.4 + dec a + dec a + cp b + jp c,.10 +.4: + ld a,(music_counter_1) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_1),a + + ld a,(music_counter_2) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_2),a + + ld a,(music_counter_3) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_3),a + + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + + ; + ; Converts note to frequency. + ; Input: + ; A = Note (1-62). + ; B = Instrument counter. + ; C = Instrument. + ; Output: + ; HL = Frequency. + ; A = Volume. + ; +music_note2freq: + add a,a + ld e,a + ld d,0 + ld hl,music_notes_table + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ld a,c + or a + jp z,music_piano + dec a + jp z,music_clarinet + dec a + jp z,music_flute + ; + ; Bass instrument. + ; +music_bass: + add hl,hl + + ; + ; Piano instrument. + ; +music_piano: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ret + +.1: + db 12,11,11,10,10,9,9,8 + db 8,7,7,6,6,5,5,4 + db 4,4,5,5,4,4,3,3 + + ; + ; Clarinet instrument. + ; +music_clarinet: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + srl h + rr l + jp nc,.2 + inc hl +.2: ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + + db 13,14,14,13,13,12,12,12 + db 11,11,11,11,12,12,12,12 + db 11,11,11,11,12,12,12,12 + + ; + ; Flute instrument. + ; +music_flute: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + + db 10,12,13,13,12,12,12,12 + db 11,11,11,11,10,10,10,10 + db 11,11,11,11,10,10,10,10 + + ; + ; Emit sound. + ; +music_hardware: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.7 ; Yes, jump. + ld a,(audio_vol2) + or a + jp nz,.7 + ld a,(audio_vol3) + or a + jp z,.7 + ld (audio_vol2),a + xor a + ld (audio_vol3),a + ld hl,(audio_freq3) + ld (audio_freq2),hl +.7: + ld hl,(audio_freq1) + ld a,h + cp 4 + ld a,$9f + jp nc,.1 + ld a,l + and $0f + or $80 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol1) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $90 +.1: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld hl,(audio_freq2) + ld a,h + cp 4 + ld a,$bf + jp nc,.2 + ld a,l + and $0f + or $a0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol2) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $b0 +.2: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.6 ; Yes, jump. + + ld hl,(audio_freq3) + ld a,h + cp 4 + ld a,$df + jp nc,.3 + ld a,l + and $0f + or $c0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol3) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $d0 +.3: out (PSG),a + if MEMOTECH + in a,($03) + endif + +.6: + ld a,(music_mode) + and 1 ; NO DRUMS? + ret z ; Yes, return. + + ld a,(audio_vol4hw) + inc a + jr z,.4 + ld a,(audio_noise) + cp 16 + ld b,$ec + jp c,.5 + ld b,$ed +; ld b,$ee +.5: ld a,(audio_control) + cp b + jr z,.4 + ld a,b + ld (audio_control),a + out (PSG),a + if MEMOTECH + in a,($03) + endif +.4: ld a,(audio_vol4hw) + out (PSG),a + if MEMOTECH + in a,($03) + endif + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.8 ; Yes, jump. + ld hl,audio_freq1 + ld bc,$0b00 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret +.8: + ld hl,audio_freq1 + ld bc,$0400 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + inc hl + inc hl + inc c + inc c + ld a,(music_mode) + and 1 + jr z,.9 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + jr .10 +.9: inc hl + inc c + inc hl + inc c +.10: ld b,$02 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret + endif + + ; + ; Enable drum. + ; +enable_drum: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$f5 + ld (audio_vol4hw),a + else + ld hl,audio_mix + ld a,(audio_vol2) + or a + jr nz,.1 + ld a,10 + ld (audio_vol2),a + set 1,(hl) +.1: res 4,(hl) + endif + ret + + ; + ; Musical notes table. + ; +music_notes_table: + ; Silence - 0 + dw 0 + if MEMOTECH+EINSTEIN + ; Values for 4.00 mhz. + ; 2nd octave - Index 1 + dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 + ; 3rd octave - Index 13 + dw 956,902,851,804,758,716,676,638,602,568,536,506 + ; 4th octave - Index 25 + dw 478,451,426,402,379,358,338,319,301,284,268,253 + ; 5th octave - Index 37 + dw 239,225,213,201,190,179,169,159,150,142,134,127 + ; 6th octave - Index 49 + dw 119,113,106,100,95,89,84,80,75,71,67,63 + ; 7th octave - Index 61 + dw 60,56,53 + else + ; Values for 3.58 mhz. + ; 2nd octave - Index 1 + dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 + ; 3rd octave - Index 13 + dw 855,807,762,719,679,641,605,571,539,508,480,453 + ; 4th octave - Index 25 + dw 428,404,381,360,339,320,302,285,269,254,240,226 + ; 5th octave - Index 37 + dw 214,202,190,180,170,160,151,143,135,127,120,113 + ; 6th octave - Index 49 + dw 107,101,95,90,85,80,76,71,67,64,60,57 + ; 7th octave - Index 61 + dw 53,50,48 + endif + + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ; + ; Converts AY-3-8910 volume to SN76489 + ; +ay2sn: + db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 + endif + +music_silence: + db 8 + db 0,0,0,0 + db -2 + endif + + if CVBASIC_COMPRESSION +define_char_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + else + ld a,(mode) + and 8 + jp z,unpack3 + endif + jp unpack + + if SMS + else +define_color_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d +unpack3: + call .1 + call .1 +.1: + push de + push hl + call unpack + pop hl + pop de + ld a,d + add a,8 + ld d,a + ret + endif + + ; + ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) + ; +unpack: +; Initialization + ld a,(hl) + inc hl + exx + ld de,0 + add a,a + inc a + rl e + add a,a + rl e + add a,a + rl e + rl e + ld hl,.modes + add hl,de + ld c,(hl) + inc hl + ld b,(hl) + push bc + pop ix + ld e,1 + exx + ld iy,.loop + +; Main depack loop +.literal: + ex af,af' + call nmi_off + ld a,(hl) + ex de,hl + call WRTVRM + ex de,hl + inc hl + inc de + call nmi_on + ex af,af' +.loop: add a,a + call z,.getbit + jr nc,.literal + +; Compressed data + exx + ld h,d + ld l,e +.getlen: add a,a + call z,.getbitexx + jr nc,.lenok +.lus: add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr nc,.lenok + add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr c,.lus +.lenok: inc hl + exx + ld c,(hl) + inc hl + ld b,0 + bit 7,c + jr z,.offsok + jp (ix) + +.mode6: add a,a + call z,.getbit + rl b +.mode5: add a,a + call z,.getbit + rl b +.mode4: add a,a + call z,.getbit + rl b +.mode3: add a,a + call z,.getbit + rl b +.mode2: add a,a + call z,.getbit + rl b + add a,a + call z,.getbit + jr nc,.offsok + or a + inc b + res 7,c +.offsok: inc bc + push hl + exx + push hl + exx + ld l,e + ld h,d + sbc hl,bc + pop bc + ex af,af' +.loop2: + call nmi_off + call RDVRM ; unpack + ex de,hl + call WRTVRM + ex de,hl ; 4 + call nmi_on + inc hl ; 6 + inc de ; 6 + dec bc ; 6 + ld a,b ; 4 + or c ; 4 + jr nz,.loop2 ; 10 + ex af,af' + pop hl + jp (iy) + +.getbit: ld a,(hl) + inc hl + rla + ret + +.getbitexx: + exx + ld a,(hl) + inc hl + exx + rla + ret + +.modes: + dw .offsok + dw .mode2 + dw .mode3 + dw .mode4 + dw .mode5 + dw .mode6 + + endif + +START: + if SVI+SG1000+SMS + im 1 + endif + if MEMOTECH +Z80_CTC: equ $08 + endif + if EINSTEIN +Z80_CTC: equ $28 + endif + + if EINSTEIN+MEMOTECH + di + im 2 + ld a,rom_start>>8 + ld i,a + ld a,$03 ; Reset Z80 CTC + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + ld a,$08 ; Interrupt vector offset + out (Z80_CTC+0),a + endif + if MEMOTECH + ld a,$25 ; Disable channel 2 interrupt. + out (Z80_CTC+2),a + ld a,$9c + out (Z80_CTC+2),a + ld a,$25 ; Disable channel 1 interrupt. + out (Z80_CTC+1),a + ld a,$9c + out (Z80_CTC+1),a + ld a,$c5 ; Enable channel 0 interrupt (VDP). + out (Z80_CTC+0),a + ld a,$01 + out (Z80_CTC+0),a + endif + if SORD + ld hl,$186c ; Disable handling of CTC Channel 1 interruption. + ld ($7002),hl + ld hl,$7040 + set 0,(hl) ; Avoid BIOS VDP handling. + endif + if SVI + ld e,$00 + ld a,$08 + call WRTPSG + ld a,$09 + call WRTPSG + ld a,$0A + call WRTPSG + ld a,$07 + ld e,$b8 + call WRTPSG + ld a,$92 ; Setup 8255 for keyboard/joystick reading. + out ($97),a + endif + if SG1000+SMS + ; Contributed by SiRioKD + ld a,$9F ; Turn off PSG + out (PSG),a + ld a,$BF + out (PSG),a + ld a,$DF + out (PSG),a + ld a,$FF + out (PSG),a + ld a,$92 ; Setup 8255 for SC3000. + out ($df),a + endif + if SG1000+SMS+SVI + ; Wait for VDP ready (around 1000 ms) + ld b,11 + ld de,$FFFF +.delay1: + ld hl,$39DE +.delay2: + add hl,de + jr c,.delay2 + djnz .delay1 + else + di + ld sp,STACK + endif + if NABU + im 2 + ld a,nabu_int>>8 + ld i,a + ld a,$03 ; Disable ROM + out ($00),a + ld a,$07 + out ($41),a + ld a,$78 ; Setup output ports and mixer. + out ($40),a + ld a,$0e + out ($41),a + ld a,$30 ; Enable video and keyboard. + out ($40),a + endif + if PV2000 + ld hl,nmi_handler + ld ($7499),hl + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + else + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + endif + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffc0) ; Megacart + endif + if SG1000+SMS + ld a,1 ; Sega mapper + ld ($fffe),a + endif + if MSX + ld a,1 ; ASCII 16K + ld ($7000),a + endif + endif + if MEMOTECH+EINSTEIN+NABU + ld ix,(lfsr) + ld hl,ram_start + ld de,ram_start+1 + ld bc,ram_end-ram_start-1 + ld (hl),0 + ldir + ld (lfsr),ix + endif + if MSX+SVI+SMS + ld ix,(lfsr) + ld hl,BASE_RAM + ld de,BASE_RAM+1 + ld bc,RAM_SIZE-1 + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO+SG1000+SORD+PENCIL+PV2000 + ld hl,(lfsr) ; Save RAM trash for random generator. + ld de,BASE_RAM + xor a + ld (de),a + inc de + if PV2000 + bit 7,d ; 2.5K of RAM + endif + if PENCIL + bit 3,d ; 2K of RAM + endif + if COLECO+SG1000+SORD + bit 2,d ; 1K of RAM + endif + jp z,$-4 + ld (lfsr),hl + endif + + if SGM +WRITE_REGISTER: equ $1fd9 +FILL_VRAM: equ $1f82 +WRITE_VRAM: equ $1fdf + + ld b,$00 ; First step. +.0: ld hl,$2000 ; RAM at $2000. +.1: ld (hl),h ; Try to write a byte. + inc h + jp p,.1 ; Repeat until reaching $8000. + ld h,$20 ; Go back at $2000. +.2: ld a,(hl) ; Read back byte. + cp h ; Is it correct? + jr nz,.3 ; No, jump. + inc h + jp p,.2 ; Repeat until reaching $8000. + jp .4 ; Memory valid! + +.3: ld a,$01 ; Enable SGM + out ($53),a + inc b + bit 1,b ; Already enabled? + jr z,.0 ; No, test RAM again. + + ld bc,$0000 + call WRITE_REGISTER + ld bc,$0180 + call WRITE_REGISTER + ld bc,$0206 + call WRITE_REGISTER + ld bc,$0380 + call WRITE_REGISTER + ld bc,$0400 + call WRITE_REGISTER + ld bc,$0536 + call WRITE_REGISTER + ld bc,$0607 + call WRITE_REGISTER + ld bc,$070D + call WRITE_REGISTER + ld bc,$03F0 + ld de,$00E8 + ld hl,$158B ; Note! direct access to Colecovision ROM + call WRITE_VRAM + ld hl,$2000 + ld de,32 + ld a,$FD + call FILL_VRAM + ld hl,$1B00 + ld de,128 + ld a,$D1 + call FILL_VRAM + ld hl,$1800 + ld de,769 + ld a,$20 + call FILL_VRAM + ld bc,$0020 + ld de,$1980 + ld hl,.5 + call WRITE_VRAM + ld bc,$01C0 + call WRITE_REGISTER + jr $ + +.5: db " SUPER GAME MODULE NOT DETECTED " + +.4: + ld ix,(lfsr) + ld hl,$2000 + ld de,$2001 + ld bc,$5FFF + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO + ld a,($0069) + cp 50 + ld a,1 + jr nz,$+3 + dec a + endif + if SG1000+SMS+SVI+SORD+PV2000+NABU + ld a,1 ; Always NTSC. + endif + if MEMOTECH+EINSTEIN + ld a,0 ; Always PAL. + endif + if MSX + call RSLREG + ld b,1 ; $4000-$7fff + call get_slot_mapping + ld h,$80 + call ENASLT ; Map into $8000-$BFFF + + ld a,($002b) + cpl + rlca + and $01 + endif + ld (ntsc),a + + call music_init + + xor a + ld (mode),a + if SMS + call mode_4 + else + call mode_0 + endif + + xor a + ld (joy1_data),a + ld (joy2_data),a + if NABU + ld (nabu_data0),a + ld (nabu_data1),a + endif + ld a,$0f + ld (key1_data),a + ld (key2_data),a + if NABU + ld (nabu_data2),a + endif + + if MSX + ld hl,nmi_handler + ld ($fd9b),hl + ld a,$c3 + ld ($fd9a),a + endif + if SORD + ld hl,nmi_handler + ld ($7006),hl + endif + + ; CVBasic program start. + ; PRINT "The constant is ",myconst + LD HL,cv1 + LD A,16 + CALL print_string + JP cv2 +cv1: + DB $54,$68,$65,$20,$63,$6f,$6e,$73 + DB $74,$61,$6e,$74,$20,$69,$73,$20 +cv2: + LD HL,7 + CALL print_number + ; + ; + ; CVBasic epilogue (BASIC compiler for Colecovision) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and + ; read_pointer variables. + ; Revision date: Mar/04/2024. Added music player. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/13/2024. Added Pletter decompressor. + ; Revision date: Mar/19/2024. Added support for sprite flicker. + ; Revision date: Apr/11/2024. Added support for Super Game Module. + ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. + ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it + ; can remain accessible in bank 0 (bank switching). + ; Revision date: Aug/02/2024. Added rom_end label for Memotech. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. + ; Revision date: Nov/12/2024. Added vdp_status. + ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. + ; + +rom_end: + + ; ROM final size rounding + if MSX+COLECO+SG1000+SMS+SVI+SORD + TIMES (($+$1FFF)&$1e000)-$ DB $ff + endif + if MEMOTECH+EINSTEIN+NABU + ; Align following data to a 256-byte page. + TIMES $100-($&$ff) DB $4f + endif + if PV2000 + TIMES $10000-$ DB $ff + endif + if SG1000+SMS + if CVBASIC_BANK_SWITCHING + forg CVBASIC_BANK_ROM_SIZE*1024-1 ; Force final ROM size + db $ff + endif + forg $7FF0 + org $7FF0 + db "TMR SEGA" + db 0,0 + db 0,0 ; Checksum + db $11,$78 ; Product code + db $00 ; Version + db $4c ; SMS Export + 32KB for checksum + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 + org BASE_RAM + endif +ram_start: + +sprites: + if SMS + rb 256 + else + rb 128 + endif +sprite_data: + rb 4 +frame: + rb 2 +read_pointer: + rb 2 +cursor: + rb 2 +lfsr: + rb 2 +mode: + rb 1 +flicker: + rb 1 +joy1_data: + rb 1 +joy2_data: + rb 1 +key1_data: + rb 1 +key2_data: + rb 1 +ntsc: + rb 1 +vdp_status: + rb 1 + if NABU +nabu_data0: rb 1 +nabu_data1: rb 1 +nabu_data2: rb 1 + endif + + if CVBASIC_MUSIC_PLAYER +music_tick: rb 1 +music_mode: rb 1 + + if CVBASIC_BANK_SWITCHING +music_bank: rb 1 + endif +music_start: rb 2 +music_pointer: rb 2 +music_playing: rb 1 +music_timing: rb 1 +music_note_counter: rb 1 +music_instrument_1: rb 1 +music_counter_1: rb 1 +music_note_1: rb 1 +music_instrument_2: rb 1 +music_counter_2: rb 1 +music_note_2: rb 1 +music_instrument_3: rb 1 +music_counter_3: rb 1 +music_note_3: rb 1 +music_counter_4: rb 1 +music_drum: rb 1 + +audio_freq1: rb 2 +audio_freq2: rb 2 +audio_freq3: rb 2 +audio_noise: rb 1 +audio_mix: rb 1 +audio_vol1: rb 1 +audio_vol2: rb 1 +audio_vol3: rb 1 + +audio_control: rb 1 +audio_vol4hw: rb 1 + endif + + if SGM + org $2000 ; Start for variables. + endif +ram_end: diff --git a/test1.bas b/test1.bas new file mode 100644 index 0000000..6b8c654 --- /dev/null +++ b/test1.bas @@ -0,0 +1,2 @@ + PRINT "The constant is ",myconst + From 1711bd71df8a13df268691396705b3be717cbac0 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 3 May 2025 00:12:07 -0600 Subject: [PATCH 035/155] Added note about SMS real hardware --- README.md | 3 +- test1.asm | 4163 ----------------------------------------------------- test1.bas | 2 - 3 files changed, 2 insertions(+), 4166 deletions(-) delete mode 100644 test1.asm delete mode 100644 test1.bas diff --git a/README.md b/README.md index 9ba8259..49d62f0 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ I don't have tested the COM files for NABU CP/M yet. Using CVBasic to compile a Sega Master System program: cvbasic --sms game.bas game.asm - gasm80 game.asm -o game.rom -sms + gasm80 game.asm -o game.sms -sms The -sms option of gasm80 will generate automatically a valid checksum so the game can run on a real console. @@ -193,6 +193,7 @@ All platforms have been tested in emulation. * Spectravideo SVI-318/328 tested in real hardware by Tony Cruise. * Creativision / Dick Smith's Wizzard tested in real hardware by Scouter3d. * NABU tested in real hardware by Sektor. +* Sega Master System tested in real hardware and Sega Genesis/Megadrive by myself. Untested: diff --git a/test1.asm b/test1.asm deleted file mode 100644 index ac95b4c..0000000 --- a/test1.asm +++ /dev/null @@ -1,4163 +0,0 @@ - ; CVBasic compiler v0.8.0 Apr/26/2025 - ; Command: ./cvbasic -Dmyconst=7 test1.bas test1.asm - ; Created: Thu May 1 22:53:44 2025 - -COLECO: equ 1 -SG1000: equ 0 -MSX: equ 0 -SGM: equ 0 -SVI: equ 0 -SORD: equ 0 -MEMOTECH: equ 0 -EINSTEIN: equ 0 -CPM: equ 0 -PENCIL: equ 0 -PV2000: equ 0 -TI99: equ 0 -NABU: equ 0 -SMS: equ 0 - -CVBASIC_MUSIC_PLAYER: equ 0 -CVBASIC_COMPRESSION: equ 0 -CVBASIC_BANK_SWITCHING: equ 0 -CVBASIC_BANK_ROM_SIZE: equ 0 - -BASE_RAM: equ $7000 ; Base of RAM -RAM_SIZE: equ $0400 ; Base of RAM -STACK: equ $7400 ; Base stack pointer -VDP: equ $be ; VDP port (write) -VDPR: equ $be ; VDP port (read) -PSG: equ $ff ; PSG port (write) - - ; - ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. - ; Added 16-bit multiply, division, modulo, and abs. - ; Added random generator. Added sound routines. - ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. - ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/14/2024. Added _sgn16. - ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. - ; Revision date: Apr/11/2024. Added support for formatting numbers. Added - ; support for Super Game Module. - ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. - ; Shorter mode setting subroutines. - ; Revision date: Apr/26/2024. Interruption handler saves current bank. - ; Revision date: Apr/27/2024. Music player now supports bank switching. - ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller - ; support with keyboard (code by SiRioKD) - ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. - ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. - ; Revision date: Jun/17/2024. Added SVI-328 support. - ; Revision date: Aug/01/2024. Added Sord M5 support. - ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech - ; support. - ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support - ; for Casio PV-2000. - ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, - ; and Casio PV-2000. - ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision - ; with flicker flag). - ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number - ; keys values were inverted. - ; Revision date: Nov/12/2024. Saves the VDP status. - ; - -JOYSEL: equ $c0 -KEYSEL: equ $80 - -JOY1: equ $fc-$20*(SG1000+SMS) -JOY2: equ $ff-$22*(SG1000+SMS) - - if COLECO - org $8000 - if PENCIL - db "COPYRIGHT SOUNDIC" - jp START - jp nmi_handler - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - db "CVBASIC!POWERED BY!2024!" - else - db $55,$aa - dw 0 - dw 0 - dw 0 - dw 0 - dw START - - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - - jp nmi_handler - endif - endif - if SG1000+SMS+SVI - org $0000 - di - ld sp,STACK - jp START - db $ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp nmi_handler ; It should be called int_handler. - endif - if MSX - ORG $4000 - db "AB" - dw START - dw $0000 - dw $0000 - dw $0000 - dw $0000 - -WRTPSG: equ $0093 -RDPSG: equ $0096 - - endif - if SORD - ORG $2000 - db $02 ; Avoid checking $4000 - dw START ; Start address. - dw $002e ; Prestart address (just point to RET in BIOS). - endif - if PV2000 - ORG $C000 - jp START - endif - - if MEMOTECH - if CPM - org $0100 - else - org $40fc - dw rom_start - dw rom_end-rom_start - endif -rom_start: - jp START - db 0,0,0,0,0 - dw nmi_handler - dw null_vector - dw null_vector - dw rom_start - -null_vector: - ei - reti - endif - if EINSTEIN - org $0100 -rom_start: - jp START - db 0,0,0,0,0 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - endif - if NABU - if CPM - org $0100 - else - org $140d - endif - nop - nop - nop - jp START - times $100-($&255) db $ff -nabu_int: - dw null_vector - dw null_vector - dw keyboard_handler - dw nmi_handler - dw null_vector - dw null_vector - dw null_vector - dw null_vector - -null_vector: - ei - reti - endif - - if SVI -WRTPSG: - out ($88),a - push af - ld a,e - out ($8c),a - pop af - ret - -RDPSG: - out ($88),a - push af - pop af - in a,($90) - ret - endif - - if EINSTEIN -WRTPSG: - out ($02),a - push af - ld a,e - out ($03),a - pop af - ret - -RDPSG: - out ($02),a - push af - pop af - in a,($02) - ret - endif - - if NABU -WRTPSG: - out ($41),a - push af - ld a,e - out ($40),a - pop af - ret - -RDPSG: - out ($41),a - push af - pop af - in a,($40) - ret - endif - - if PV2000 - ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) -WRTVDP: - ld a,b - ld (VDP+1),a - ld a,c - or $80 - ld (VDP+1),a - ret - -SETWRT: - ld a,l - ld (VDP+1),a - ld a,h - or $40 - ld (VDP+1),a - ret - -SETRD: - ld a,l - ld (VDP+1),a - ld a,h - and $3f - ld (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - ld (VDP),a - ret - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - ld a,(VDP) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: ld (VDP),a ; 13 14 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 37 42 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - ld a,(VDP) - ld (de),a - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - EX DE,HL - CALL SETWRT - EX DE,HL - DEC BC - INC C - LD A,B - LD B,C - INC A - LD C,A -.1: - LD A,(HL) ; 7 8 - LD (VDP),A ; 13 14 - INC HL ; 6 7 - DJNZ .1 ; 13 14 - DEC C ; 4 5 - JP NZ,.1 ; 10 11 - RET - else - ; Normal platforms with VDP connected via ports (IORQ) -WRTVDP: - ld a,b - out (VDP+1),a - ld a,c - or $80 - out (VDP+1),a - ret - -SETWRT: - ld a,l - out (VDP+1),a - ld a,h - or $40 - out (VDP+1),a - ret - -SETRD: - ld a,l - out (VDP+1),a - ld a,h - and $3f - out (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - out (VDP),a - ret - - if SG1000+SMS - db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff - - ; Located at $0066 - ei ; NMI handler (pause button) - retn - endif - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - in a,(VDPR) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) -.1: out (VDP),a ; 11 12 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 - ; -- -- - ; 35 40 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - in a,(VDP) - ld (de),a - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - ex de,hl - call SETWRT - ex de,hl - dec bc - inc c - ld a,b - ld b,c - inc a - ld c,VDP -.1: - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - outi - jp nz,.1 - dec a - jp nz,.1 - ret - endif - - if SMS - else -LDIRVM3: - call .1 - call .1 -.1: push hl - push de - push bc - call LDIRVM - pop bc - pop de - ld a,d - add a,8 - ld d,a - pop hl - ret - endif - -DISSCR: - call nmi_off - ld bc,$a201 - call WRTVDP - jp nmi_on - -ENASCR: - call nmi_off - ld bc,$e201 - call WRTVDP - jp nmi_on - -CPYBLK: - pop hl - ex af,af' - pop af - ld b,a - pop af - ld c,a - pop de - ex (sp),hl - call nmi_off -.1: push bc - push hl - push de - ld b,0 - call LDIRVM - pop hl - if SMS - ld bc,$0040 - else - ld bc,$0020 - endif - add hl,bc - ex de,hl - pop hl - ex af,af' - ld c,a - ld b,0 - add hl,bc - ex af,af' - pop bc - djnz .1 - jp nmi_on - -nmi_off: - if COLECO+PV2000 - push hl - ld hl,mode - set 0,(hl) - pop hl - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - di - endif - ret - -nmi_on: - if COLECO+PV2000 - push af - push hl - ld hl,mode - res 0,(hl) - nop - bit 1,(hl) - jp nz,nmi_handler.0 - pop hl - pop af - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - ei - endif - ret - - if COLECO -keypad_table: - db $0f,$08,$04,$05,$0c,$07,$0b,$02 - db $0d,$0a,$00,$09,$03,$01,$06,$0f - endif - -cls: - if SMS - ld hl,$3800 - ld (cursor),hl - di - call SETWRT -.1: ld a,$20 ; 7 - out (VDP),a ; 11 - inc hl ; 6 - inc hl ; 6 - ld a,$00 ; 7 - out (VDP),a ; 11 - ld a,h ; 4 - cp $3e ; 7 - jp nz,.1 ; 10 - ei - ret - else - ld hl,$1800 - ld (cursor),hl - ld bc,$0300 - ld a,$20 - call nmi_off - call FILVRM - jp nmi_on - endif - -print_string: - ld c,a - ld b,0 - ld de,(cursor) - if SMS - ld a,d - and $07 - or $38 - ld d,a - else - ld a,d - and $07 - or $18 - ld d,a - endif - push de - push bc - call nmi_off - if SMS - ex de,hl -.1: ld a,(de) - call WRTVRM - inc de - inc hl - xor a - call WRTVRM - inc hl - dec bc - ld a,b - or c - jp nz,.1 - else - call LDIRVM - endif - call nmi_on - pop bc - pop hl - add hl,bc - if SMS - add hl,bc - endif - ld (cursor),hl - ret - -print_number: - ld b,0 - call nmi_off -print_number5: - ld de,10000 - call print_digit -print_number4: - ld de,1000 - call print_digit -print_number3: - ld de,100 - call print_digit -print_number2: - ld de,10 - call print_digit -print_number1: - ld de,1 - ld b,e - call print_digit - jp nmi_on - -print_digit: - ld a,$2f - or a -.2: inc a - sbc hl,de - jp nc,.2 - add hl,de - cp $30 - jr nz,.3 - ld a,b - or a - ret z - dec a - jr z,.4 - ld a,c - jr print_char -.4: - ld a,$30 -.3: ld b,1 - -print_char: - push hl - ld hl,(cursor) - ex af,af' - ld a,h - and $07 - if SMS - or $38 - else - or $18 - endif - ld h,a - ex af,af' - call WRTVRM - inc hl - if SMS - xor a - call WRTVRM - inc hl - endif - ld (cursor),hl - pop hl - ret - -define_char: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - di - call LDIRVM - ei - ret - else - call nmi_off - ld a,(mode) - and 8 - jr nz,.1 - call LDIRVM3 - jp nmi_on - -.1: call LDIRVM - jp nmi_on - endif - -define_color: - if SMS - ret - else - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d - call nmi_off - call LDIRVM3 - jp nmi_on - endif - -define_sprite: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - if SMS - set 1,h - else - ld h,$07 - endif - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ex de,hl - call nmi_off - call LDIRVM - jp nmi_on - endif - -update_sprite: - if SMS - pop bc ; Pop return address. - pop de ; 3th. argument in D (Y-coordinate) - ld e,a ; 4th. argument in E (frame) - pop af ; 2nd. argument in A (X-coordinate) - pop hl ; 1st. argument in H (sprite number) - push bc ; Push return address. - ld l,h - res 7,l - res 6,l - ld h,sprites>>8 - ld (hl),a - sla l - set 7,l - ld (hl),d - inc l - ld (hl),e - else - pop bc - ld (sprite_data+3),a - pop af - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - ld de,sprites - add a,a - add a,a - if SORD - or $80 - endif - ld e,a - ld hl,sprite_data - ld bc,4 - ldir - endif - ret - - ; Fast 16-bit multiplication. -_mul16: - ld b,h - ld c,l - ld a,16 - ld hl,0 -.1: - srl d - rr e - jr nc,.2 - add hl,bc -.2: sla c - rl b - dec a - jp nz,.1 - ret - - ; 16-bit signed modulo. - ; hl = hl % de -_mod16s: - ld a,h - or a - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _mod16 - pop af - ret p - jp _neg16 - - ; 16-bit signed division. - ; hl = hl / de -_div16s: - ld a,h - xor d - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _div16 - pop af - ret p - jp _neg16 - -_abs16: - bit 7,h - ret z -_neg16: - ld a,h - cpl - ld h,a - ld a,l - cpl - ld l,a - inc hl - ret - - ; Fast 16-bit division. - ; hl = hl / de -_div16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - rl c - rl b - ld h,b - ld l,c - ret - - ; Fast 16-bit modulo. -_mod16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - ret - -_sgn16: - ld a,h - or l - ret z - bit 7,h - ld hl,$ffff - ret nz - inc hl - inc hl - ret - - ; Random number generator. - ; From my game Mecha Eight. -random: - ld hl,(lfsr) - ld a,h - or l - jr nz,.0 - ld hl,$7811 -.0: ld a,h - and $80 - ld b,a - ld a,h - and $02 - rrca - rrca - xor b - ld b,a - ld a,h - and $01 - rrca - xor b - ld b,a - ld a,l - and $20 - rlca - rlca - xor b - rlca - rr h - rr l - ld (lfsr),hl - ret - -sn76489_freq: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld b,a - ld a,l - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - and $3f - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_vol: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - cpl - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_control: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - and $0f - or $e0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -ay3_reg: - if COLECO - push af - ld a,b - out ($50),a - pop af - out ($51),a - ret - endif - if SG1000+SORD+SMS+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,a - ld a,b - jp WRTPSG - endif - -ay3_freq: - if COLECO - out ($50),a - push af - ld a,l - out ($51),a - pop af - inc a - out ($50),a - push af - ld a,h - and $0f - out ($51),a - pop af - ret - endif - if SG1000+SMS+SORD+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,l - call WRTPSG - ld e,h - inc a - jp WRTPSG - endif - - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ; Required for SG1000 and Sega Master System as both don't have a BIOS - ; Required for SVI because we don't have access to BIOS in cartridge. - ; Required for Sord M5 because it doesn't provide an ASCII charset. - ; Required for Memotech/Einstein because CP/M uses the memory. - ; My personal font for TMS9928. - ; - ; Patterned after the TMS9928 programming manual 6x8 letters - ; with better lowercase letters, also I made a proper - ; AT sign. - ; -font_bitmaps: - db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space - db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! - db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " - db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # - db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ - db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % - db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & - db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' - db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( - db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) - db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * - db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + - db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , - db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - - db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . - db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / - db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 - db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 - db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 - db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 - db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 - db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 - db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 - db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 - db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 - db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 - db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : - db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; - db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < - db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = - db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > - db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? - db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ - db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A - db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B - db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C - db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D - db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E - db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F - db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G - db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H - db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I - db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J - db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K - db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L - db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M - db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N - db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O - db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P - db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q - db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R - db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S - db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T - db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U - db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V - db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W - db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X - db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y - db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z - db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ - db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ - db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] - db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E - db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ - db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 - db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a - db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b - db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c - db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d - db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e - db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f - db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g - db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h - db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i - db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j - db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k - db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l - db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m - db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n - db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o - db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p - db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q - db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r - db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s - db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t - db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u - db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v - db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w - db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x - db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y - db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z - db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { - db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | - db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } - db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e - db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f - endif - - if SMS -palette_load: - push hl - di - ld hl,$c000 - call SETWRT - pop hl - ld bc,32*256+VDP - outi - jp nz,$-2 - ei - ret - -mode_4: - di - ld bc,$0400 - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) - call WRTVDP - ld bc,$ff03 ; Not used (required value for SMS1) - call WRTVDP - ld bc,$0704 ; Not used (required value for SMS1) - call WRTVDP - ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) - call WRTVDP - ld bc,$0706 ; $2000 for sprites bitmaps (or $03 for $0000) - call WRTVDP - ld bc,$0007 - call WRTVDP - ld bc,$0008 ; Background X scroll - call WRTVDP - ld bc,$0009 ; Background Y scroll - call WRTVDP - ld hl,$20*32 ; Point to space character bitmap - call SETWRT - ld hl,font_bitmaps - ld c,96 -.1: ld b,8 -.2: ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - inc hl - djnz .2 - dec c - jp nz,.1 - ei - call cls - di - ld hl,$3f00 - ld bc,$0040 - ld a,$e0 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,63 - ld (hl),$e0 - ldir - ei - ld hl,.3 - call palette_load - jp ENASCR - - ; TMS9118-alike palette -.3: - db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f - db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f - - else -vdp_generic_mode: - call nmi_off - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0602 ; $1800 for pattern table. - call WRTVDP - ld b,d - ld c,$03 ; for color table. - call WRTVDP - ld b,e - ld c,$04 ; for bitmap table. - call WRTVDP - ld bc,$3605 ; $1b00 for sprite attribute table. - call WRTVDP - ld bc,$0706 ; $3800 for sprites bitmaps. - call WRTVDP - ld bc,$0107 - jp WRTVDP - -mode_0: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM3 - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - call cls -vdp_generic_sprites: - call nmi_off - ld hl,$1b00 - ld bc,$0080 - ld a,$d1 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,127 - ld (hl),$d1 - ldir - call nmi_on - jp ENASCR - -mode_1: - ld hl,mode - res 3,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - ld hl,$0000 - ld bc,$1800 - xor a - call FILVRM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - ld hl,$1800 -.1: call nmi_off - ld b,32 -.2: ld a,l - call WRTVRM - inc hl - djnz .2 - call nmi_on - ld a,h - cp $1b - jp nz,.1 - jp vdp_generic_sprites - -mode_2: - ld hl,mode - set 3,(hl) - ld bc,$0000 - ld de,$8000 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$0020 - ld a,$f0 - call FILVRM - call nmi_on - call cls - jp vdp_generic_sprites - endif - - if MSX -ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) -RSLREG: EQU $0138 ; Read slot status in A - - ; - ; Get slot mapping - ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) - ; A = Current slot selection status (CALL RSLREG) - ; -get_slot_mapping: - call rotate_slot - ld c,a - add a,$C1 ; EXPTBL - ld l,a - ld h,$FC - ld a,(hl) - and $80 ; Get expanded flag - or c - ld c,a - inc hl - inc hl - inc hl - inc hl - ld a,(hl) ; SLTTBL - call rotate_slot - rlca - rlca - or c ; A contains bit 7 = Marks expanded - ; bit 6 - 4 = Doesn't care - ; bit 3 - 2 = Secondary mapper - ; bit 1 - 0 = Primary mapper - ret - -rotate_slot: - push bc - dec b - inc b - jr z,.1 -.0: rrca - rrca - djnz .0 -.1: and 3 - pop bc - ret - - endif - -nmi_handler: - push af - push hl - ld hl,mode - bit 0,(hl) - jr z,.1 - set 1,(hl) - pop hl - pop af - retn - -.0: res 1,(hl) - -.1: push bc - push de - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fbf) - endif - if MSX - ld a,($bfff) - endif - push af - endif - if SORD+MEMOTECH - call ctc_reti - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - in a,(VDPR+1) - ld (vdp_status),a - endif - - ; - ; Update of sprite attribute table - ; - if SMS - bit 2,(hl) - jr z,.4 - ld hl,$3f00 - call SETWRT - ld hl,sprites - ld bc,$4000+VDP - outi - jp nz,$-2 - ld hl,$3f80 - call SETWRT - ld hl,sprites - ld bc,$8000+VDP - outi - jp nz,$-2 - jr .5 - -.4: ld hl,$3f00 - call SETWRT - ld a,(flicker) - inc a - and $3f - ld (flicker),a - ld l,a - ld h,sprites>>8 - ld bc,$4000+VDP - ld de,6 - outi - add hl,de - res 6,l - jp nz,$-5 - ld hl,$3f80 - call SETWRT - ld a,(flicker) - add a,a - or $80 - ld l,a - ld bc,$8000+VDP - ld de,12 - ld h,sprites>>8 - outi - nop - nop - nop - outi - add hl,de - set 7,l - jp nz,$-12 -.5: - else - ld bc,$8000+VDP - bit 2,(hl) - jr z,.4 - - ld hl,$1b00 - call SETWRT - ld hl,sprites -.7: - if PV2000 - ld a,(hl) - ld (VDP),a - inc hl - djnz .7 - else - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp nz,.7 - endif - jr .5 - -.4: - ld hl,$1b00 - call SETWRT - ld a,(flicker) - add a,$04 - ld (flicker),a - ld de,24 - ld b,128 - ld l,a - if SORD - else - ld h,sprites>>8 - endif -.6: - if SORD - set 7,l - ld h,sprites>>8 - else - res 7,l - endif - if PV2000 - ld a,(hl) ; 7 8 - ld (VDP),a ; 13 14 - inc hl ; 6 7 - dec b ; 4 5 - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - else - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - endif - add hl,de - jp nz,.6 -.5: - endif - - if COLECO - out (JOYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - or $b0 - ld b,a - in a,(JOY2) - or $b0 - ld c,a - - out (KEYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - ld d,a - in a,(JOY2) - ld e,a - - ld a,d - rlca - or $7f - and b - cpl - ld (joy1_data),a - - ld a,e - rlca - or $7f - and c - cpl - ld (joy2_data),a - - ld a,d - and $0f - ld c,a - ld b,0 - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key1_data),a - - ld a,e - and $0f - ld c,a - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key2_data),a - endif - if SG1000+SMS - ld a,$07 - out ($de),a - ld b,$ff - in a,(JOY1) - ld h,a - in a,(JOY2) - ld l,a - in a,($de) - cp 7 - jp nz,.sg1000 - - ld a,$00 - out ($de),a - in a,($dc) - rra - ld c,1 - jr nc,.sg1 - in a,($dd) - rra - ld c,8 - jr nc,.sg1 - ld a,$01 - out ($de),a - in a,($dc) - rra - ld c,2 - jr nc,.sg1 - in a,($dd) - rra - ld c,9 - jr nc,.sg1 - ld a,$02 - out ($de),a - in a,($dc) - rra - ld c,3 - jr nc,.sg1 - in a,($dd) - rra - ld c,0 - jr nc,.sg1 - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a - ld c,10 - jr z,.sg1 - rra - ld c,4 - jr nc,.sg1 - ld a,$04 - out ($de),a - in a,($dc) - rra - ld c,5 - jr nc,.sg1 - ld a,$05 - out ($de),a - in a,($dc) - bit 6,a - ld c,11 - jr z,.sg1 - rra - ld c,6 - jr nc,.sg1 - ld a,$06 - out ($de),a - in a,($dc) - rra - ld c,7 - jr nc,.sg1 - ld c,15 -.sg1: ld a,c - ld (key1_data),a - - ld a,$04 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard down. - jr nz,$+4 - res 1,h - ld a,$05 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard left. - jr nz,$+4 - res 2,h - ld a,$06 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard right. - jr nz,$+4 - res 3,h - bit 6,a ; Keyboard up. - jr nz,$+4 - res 0,h - ld a,$02 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Ins - jr nz,$+4 - res 4,h - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Del - jr nz,$+4 - res 5,h -.sg1000: - bit 0,h - jr nz,$+4 - res 0,b - bit 1,h - jr nz,$+4 - res 2,b - bit 2,h - jr nz,$+4 - res 3,b - bit 3,h - jr nz,$+4 - res 1,b - bit 4,h - jr nz,$+4 - res 6,b - bit 5,h - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - - ld a,$ff - bit 6,h - jr nz,$+4 - res 0,a - bit 7,h - jr nz,$+4 - res 2,a - - bit 0,l - jr nz,$+4 - res 3,a - bit 1,l - jr nz,$+4 - res 1,a - bit 2,l - jr nz,$+4 - res 4,a - bit 3,l - jr nz,$+4 - res 5,a - cpl - ld (joy2_data),a - - endif - if MSX - ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php - ld a,15 - call RDPSG - and $b0 - or $4f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - ld b,$ff - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy2_data),a - - in a,($aa) - and $f0 - or $00 - out ($aa),a - in a,($a9) - cp $ff - ld c,$ff - jr nz,.key1 - in a,($aa) - and $f0 - or $01 - out ($aa),a - in a,($a9) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - in a,($aa) - and $f0 - or $07 - out ($aa),a - in a,($a9) - bit 5,a ; BS - ld c,$0a - jr z,.key2 - bit 7,a ; RET - ld c,$0b - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - in a,($aa) - and $f0 - or $08 - out ($aa),a - in a,($a9) - bit 5,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 6,a - jr nz,$+4 - res 2,b - bit 4,a - jr nz,$+4 - res 3,b - bit 0,a - jr nz,$+4 - res 6,b - in a,($aa) - and $f0 - or $04 - out ($aa),a - in a,($a9) - bit 2,a - jr nz,$+4 - res 7,b - - ld a,15 - call RDPSG - and $b0 - or $0f - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - - ld a,b - cpl - ld (joy1_data),a - endif - if SVI - ld a,14 - call RDPSG - ld b,$ff - bit 4,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 5,a - jr nz,$+4 - res 2,b - bit 6,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 5,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy2_data),a - - ld a,$10 - out ($96),a - in a,($99) - cp $ff - ld c,$ff - jr nz,.key1 - ld a,$11 - out ($96),a - in a,($99) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - ld a,$16 - out ($96),a - in a,($99) - bit 6,a - ld c,$0b - jr z,.key2 - ld a,$15 - out ($96),a - in a,($99) - bit 6,a - ld c,$0a - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - ld a,$15 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 0,b - ld a,$18 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 1,b - ld a,$17 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 2,b - ld a,$16 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 3,b - ld a,$18 - out ($96),a - in a,($99) - bit 0,a - jr nz,$+4 - res 6,b - ld a,$13 - out ($96),a - in a,($99) - bit 5,a - jr nz,$+4 - res 7,b - - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 4,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy1_data),a - endif - if SORD - ld bc,$ffff - in a,($37) ; Read joystick - rra - jr nc,$+4 - res 1,b - rra - jr nc,$+4 - res 0,b - rra - jr nc,$+4 - res 3,b - rra - jr nc,$+4 - res 2,b - rra - jr nc,$+4 - res 1,c - rra - jr nc,$+4 - res 0,c - rra - jr nc,$+4 - res 3,c - rra - jr nc,$+4 - res 2,c - in a,($31) - rra - jr nc,$+4 - res 6,b - rra - jr nc,$+4 - res 7,b - rra - rra - rra - jr nc,$+4 - res 6,c - rra - jr nc,$+4 - res 7,c - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - in a,($31) ; Keyboard 1-8 - or a - ld c,$00 - jr nz,.key3 - in a,($35) - bit 0,a ; 9 - ld c,$09 - jr nz,.key5 - bit 1,a ; 0 - ld c,$00 - jr nz,.key5 - bit 7,a ; Backspace - ld c,$0a - jr nz,.key5 - in a,($30) - bit 7,a ; Enter - ld c,$0b - jr nz,.key5 - ld c,$0f - jr .key5 - -.key3: rra - inc c - jr nc,.key3 -.key5: - ld a,c - ld (key1_data),a - - endif - if MEMOTECH - ld bc,$ffff - - ld a,$fb - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 0,b ; Up direction. - bit 3,a ; Y - jr nz,$+4 - res 0,c ; Up direction. - - ld a,$ef - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 1,b ; Right key. - ld a,$bf - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 2,b ; Down key. - ld a,$f7 - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 3,b ; Left key. - ld a,$df - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a ; Home key. - jr nz,$+4 - res 6,b ; Button 1 - - ld a,$7F - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 2,a ; B - jr nz,$+4 - res 0,c ; Up key. - bit 1,a ; C - jr nz,$+4 - res 1,c ; Right key. - bit 3,a ; M - jr nz,$+4 - res 2,c ; Down key. - bit 0,a ; Z - jr nz,$+4 - res 3,c ; Left key. - bit 5,a ; - - jr nz,$+4 - res 7,c ; Button 2 for player 2. - bit 7,a ; - - jr nz,$+4 - res 7,b ; Button 2 for player 1. - in a,($06) ; Read keyboard data. - bit 0,a ; Space - jr nz,$+4 - res 6,c ; Button 1. - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$fe - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - ld b,1 - jr nc,.mt1 - rra - ld b,3 - jr nc,.mt1 - rra - ld b,5 - jr nc,.mt1 - rra - ld b,7 - jr nc,.mt1 - rra - ld b,9 - jr nc,.mt1 - ld a,$df - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - bit 6,a - ld b,11 - jr z,.mt1 - ld a,$fd - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - rra - ld b,2 - jr nc,.mt1 - rra - ld b,4 - jr nc,.mt1 - rra - ld b,6 - jr nc,.mt1 - rra - ld b,8 - jr nc,.mt1 - rra - ld b,0 - jr nc,.mt1 - in a,($06) - rra - ld b,10 - jr nc,.mt1 - ld b,15 -.mt1: - ld a,b - ld (key1_data),a - endif - if EINSTEIN - ld bc,$ffff - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 0,b ; Up - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 4,a - jr nz,$+4 - res 1,b ; Right - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - jr nz,$+4 - res 2,b ; Down - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - jr nz,$+4 - res 3,b ; Left - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 6,b ; Fire - ld a,$0e - out ($02),a - ld a,$7f - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 0,a - jr nz,$+4 - res 7,b ; 2nd fire - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$0e - out ($02),a - ld a,$ef - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - rra - ld b,7 - jr nc,.te1 - rra - ld b,6 - jr nc,.te1 - rra - ld b,5 - jr nc,.te1 - rra - ld b,4 - jr nc,.te1 - rra - ld b,3 - jr nc,.te1 - rra - ld b,2 - jr nc,.te1 - rra - ld b,1 - jr nc,.te1 - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - ld b,8 - jr z,.te1 - bit 4,a - ld b,10 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - ld b,9 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - ld b,11 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 7,a - ld b,0 - jr z,.te1 - ld b,15 -.te1: - ld a,b - ld (key1_data),a - endif - if PV2000 - ld bc,$ffff - ld a,7 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 0,b - bit 0,a - jr z,$+4 - res 3,b - ld a,6 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 1,b - bit 0,a - jr z,$+4 - res 2,b - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 0,a - jr z,$+4 - res 6,b - bit 1,a - jr z,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - ld a,0 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - and $0f - ld b,$04 - jr nz,.pv1 - in a,($10) - and $0f - ld b,$08 - jr nz,.pv1 - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($10) - ld b,11 - bit 0,a - jr nz,.pv2 - ld a,4 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - ld b,10 - bit 3,a - jr nz,.pv2 - in a,($10) - ld b,9 - bit 0,a - jr nz,.pv2 - ld b,0 - bit 3,a - jr nz,.pv2 - ld b,15 - jr .pv2 - -.pv1: rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b -.pv2: ld a,b - ld (key1_data),a - endif - if NABU - ld a,(nabu_data0) - and $cf - ld (joy1_data),a - ld a,(nabu_data1) - and $cf - ld (joy2_data),a - ld a,(nabu_data2) - ld (key1_data),a - ld a,$0f - ld (nabu_data2),a - endif - - if CVBASIC_MUSIC_PLAYER - ld a,(music_mode) - or a - call nz,music_hardware - endif - - ld hl,(frame) - inc hl - ld (frame),hl - - ld hl,lfsr ; Make LFSR more random - inc (hl) - inc (hl) - inc (hl) - - if CVBASIC_MUSIC_PLAYER - ; - ; Music is played with a 50hz clock. - ; - ld a,(ntsc) - or a - jr z,.2 - ld a,(music_tick) - inc a - cp 6 - jr nz,$+3 - xor a - ld (music_tick),a - jr z,.3 -.2: - ld a,(music_mode) - or a - call nz,music_generate -.3: - endif - - if CVBASIC_BANK_SWITCHING - pop af - if COLECO - ld l,a - ld h,$ff - ld a,(hl) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - pop de - pop bc - pop hl - if COLECO - in a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - if SG1000+SMS+SVI+NABU - pop af - ei - reti - endif - if MSX - pop af - ret - endif - if SORD+MEMOTECH - pop af - ei - ret - -ctc_reti: - reti - endif - if EINSTEIN - pop af - ret - endif - if PV2000 - ld a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - - if NABU -keyboard_handler: - push af - push bc - push hl - in a,($90) - ld c,a - cp $0d ; Enter - ld a,11 - jr z,.8 - ld a,c - cp $7f ; Del - ld a,10 - jr z,.8 - ld a,c - cp $30 - jr c,.7 - cp $3a - jr nc,.7 - sub $30 -.8: ld (nabu_data2),a - jr .1 -.7: - cp $a0 - jr c,.2 - cp $c0 - jr c,.joystick -.2: - ld hl,nabu_data0 - cp $80 - jr nz,.3 - res 4,(hl) - jr .1 -.3: - cp $81 - jr nz,.4 - set 4,(hl) - jr .1 -.4: - cp $e0 - jr c,.1 - and $0f - ld b,2 - jr z,.5 - dec a - ld b,8 - jr z,.5 - dec a - ld b,1 - jr z,.5 - dec a - ld b,4 - jr z,.5 - dec a - ld b,$80 - jr z,.5 - dec a - ld b,$40 - jr nz,.1 -.5: bit 4,c - jr nz,.6 - ld a,(hl) - or b - ld (hl),a - jr .1 - -.6: - ld a,b - cpl - and (hl) - ld (hl),a - jr .1 - -.joystick: - ld hl,nabu_data0 - bit 4,(hl) - jr z,$+5 - ld hl,nabu_data1 - ld b,$00 - bit 3,c - jr z,$+4 - set 0,b - bit 2,c - jr z,$+4 - set 1,b - bit 1,c - jr z,$+4 - set 2,b - bit 0,c - jr z,$+4 - set 3,b - bit 4,c - jr z,$+4 - set 6,b - ld (hl),b -.1: - pop hl - pop bc - pop af - ei - reti - endif - if SORD -wait: - ld de,(frame) -.1: - ld hl,(frame) - or a - sbc hl,de - jr z,.1 - ret - endif - if EINSTEIN -wait: - in a,(VDP+1) - nop - in a,(VDP+1) - bit 7,a - jr z,$-4 - ld (vdp_status),a - jp nmi_handler - endif - - ; - ; The music player code comes from my - ; game Princess Quest for Colecovision (2012) - ; - - ; - ; Init music player. - ; -music_init: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$9f - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$bf - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$df - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ff - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ec - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 -MIX_BASE: equ $b8 - endif - if EINSTEIN+NABU -MIX_BASE: equ $78 - endif - if MSX+SVI+EINSTEIN+NABU - ld a,$08 - ld e,$00 - call WRTPSG - ld a,$09 - ld e,$00 - call WRTPSG - ld a,$0a - ld e,$00 - call WRTPSG - ld a,$07 - ld e,MIX_BASE - call WRTPSG - endif - if SGM - ld b,$08 - xor a - call ay3_reg - ld b,$09 - call ay3_reg - ld b,$0a - call ay3_reg - ld b,$07 - ld a,$b8 - call ay3_reg - endif - if CVBASIC_MUSIC_PLAYER - else - ret - endif - - if CVBASIC_MUSIC_PLAYER - ld a,$ff - ld (audio_vol4hw),a - ld a,$ec - ld (audio_control),a - ld a,MIX_BASE - ld (audio_mix),a - ld hl,music_silence - ; - ; Play a music. - ; HL = Pointer to music. - ; -music_play: - call nmi_off - ld a,(hl) - ld (music_timing),a - inc hl - ld (music_start),hl - ld (music_pointer),hl - xor a - ld (music_note_counter),a - inc a - ld (music_playing),a - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fbf) - endif - if MSX - ld a,($bfff) - endif - ld (music_bank),a - endif - jp nmi_on - - ; - ; Generates music. - ; -music_generate: - ld a,(audio_mix) - and $c0 - or $38 - ld (audio_mix),a - xor a ; Turn off all the sound channels. - ld l,a - ld h,a - ld (audio_vol1),hl ; audio_vol1/audio_vol2 - ld (audio_vol3),a - ld a,$ff - ld (audio_vol4hw),a - - ld a,(music_note_counter) - or a - jp nz,.6 - ld hl,(music_pointer) -.15: push hl - if CVBASIC_BANK_SWITCHING - ld a,(music_bank) - if COLECO - ld e,a - ld d,$ff - ld a,(de) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - ld ($7000),a - endif - endif - ld b,(hl) - inc hl - ld c,(hl) - inc hl - ld d,(hl) - inc hl - ld e,(hl) - pop hl - ld a,(music_timing) - rlca - jr nc,.16 - ld e,d - ld d,0 - jr .17 - -.16: rlca - jr nc,.17 - ld e,0 -.17: ld a,b ; Read first byte. - cp -2 ; End of music? - jr nz,.19 ; No, jump. - xor a ; Keep at same place. - ld (music_playing),a - ret - -.19: cp -3 ; Repeat music? - jp nz,.0 - ld hl,(music_start) - jr .15 - -.0: ld a,(music_timing) - and $3f ; Restart note time. - ld (music_note_counter),a - ld a,b - cp $3f ; Sustain? - jr z,.1 - rlca - rlca - and 3 - ld (music_instrument_1),a - ld a,b - and $3f - ld (music_note_1),a - xor a - ld (music_counter_1),a -.1: ld a,c - cp $3f - jr z,.2 - rlca - rlca - and 3 - ld (music_instrument_2),a - ld a,c - and $3f - ld (music_note_2),a - xor a - ld (music_counter_2),a -.2: ld a,d - cp $3f - jr z,.3 - rlca - rlca - and 3 - ld (music_instrument_3),a - ld a,d - and $3f - ld (music_note_3),a - xor a - ld (music_counter_3),a -.3: ld a,e - ld (music_drum),a - xor a - ld (music_counter_4),a - inc hl - inc hl - inc hl - ld a,(music_timing) - and $c0 - jr nz,.14 - inc hl -.14: ld (music_pointer),hl - -.6: ld a,(music_note_1) - or a - jr z,.7 - ld bc,(music_instrument_1) - call music_note2freq - ld (audio_freq1),hl - ld (audio_vol1),a - -.7: ld a,(music_note_2) - or a - jr z,.8 - ld bc,(music_instrument_2) - call music_note2freq - ld (audio_freq2),hl - ld (audio_vol2),a - -.8: ld a,(music_note_3) - or a - jr z,.9 - ld bc,(music_instrument_3) - call music_note2freq - ld (audio_freq3),hl - ld (audio_vol3),a - -.9: ld a,(music_drum) - or a - jr z,.4 - dec a ; 1 - Long drum. - jr nz,.5 - ld a,(music_counter_4) - cp 3 - jp nc,.4 -.10: ld a,5 - ld (audio_noise),a - call enable_drum - jr .4 - -.5: dec a ; 2 - Short durm. - jr nz,.11 - ld a,(music_counter_4) - or a - jp nz,.4 - ld a,8 - ld (audio_noise),a - call enable_drum - jr .4 - -.11: ;dec a ; 3 - Roll. - ;jp nz,.4 - ld a,(music_timing) - and $3e - rrca - ld b,a - ld a,(music_counter_4) - cp 2 - jp c,.10 - cp b - jp c,.4 - dec a - dec a - cp b - jp c,.10 -.4: - ld a,(music_counter_1) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_1),a - - ld a,(music_counter_2) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_2),a - - ld a,(music_counter_3) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_3),a - - ld hl,music_counter_4 - inc (hl) - ld hl,music_note_counter - dec (hl) - ret - - ; - ; Converts note to frequency. - ; Input: - ; A = Note (1-62). - ; B = Instrument counter. - ; C = Instrument. - ; Output: - ; HL = Frequency. - ; A = Volume. - ; -music_note2freq: - add a,a - ld e,a - ld d,0 - ld hl,music_notes_table - add hl,de - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - ld a,c - or a - jp z,music_piano - dec a - jp z,music_clarinet - dec a - jp z,music_flute - ; - ; Bass instrument. - ; -music_bass: - add hl,hl - - ; - ; Piano instrument. - ; -music_piano: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ret - -.1: - db 12,11,11,10,10,9,9,8 - db 8,7,7,6,6,5,5,4 - db 4,4,5,5,4,4,3,3 - - ; - ; Clarinet instrument. - ; -music_clarinet: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - srl h - rr l - jp nc,.2 - inc hl -.2: ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - - db 13,14,14,13,13,12,12,12 - db 11,11,11,11,12,12,12,12 - db 11,11,11,11,12,12,12,12 - - ; - ; Flute instrument. - ; -music_flute: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - - db 10,12,13,13,12,12,12,12 - db 11,11,11,11,10,10,10,10 - db 11,11,11,11,10,10,10,10 - - ; - ; Emit sound. - ; -music_hardware: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.7 ; Yes, jump. - ld a,(audio_vol2) - or a - jp nz,.7 - ld a,(audio_vol3) - or a - jp z,.7 - ld (audio_vol2),a - xor a - ld (audio_vol3),a - ld hl,(audio_freq3) - ld (audio_freq2),hl -.7: - ld hl,(audio_freq1) - ld a,h - cp 4 - ld a,$9f - jp nc,.1 - ld a,l - and $0f - or $80 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol1) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $90 -.1: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld hl,(audio_freq2) - ld a,h - cp 4 - ld a,$bf - jp nc,.2 - ld a,l - and $0f - or $a0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol2) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $b0 -.2: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.6 ; Yes, jump. - - ld hl,(audio_freq3) - ld a,h - cp 4 - ld a,$df - jp nc,.3 - ld a,l - and $0f - or $c0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol3) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $d0 -.3: out (PSG),a - if MEMOTECH - in a,($03) - endif - -.6: - ld a,(music_mode) - and 1 ; NO DRUMS? - ret z ; Yes, return. - - ld a,(audio_vol4hw) - inc a - jr z,.4 - ld a,(audio_noise) - cp 16 - ld b,$ec - jp c,.5 - ld b,$ed -; ld b,$ee -.5: ld a,(audio_control) - cp b - jr z,.4 - ld a,b - ld (audio_control),a - out (PSG),a - if MEMOTECH - in a,($03) - endif -.4: ld a,(audio_vol4hw) - out (PSG),a - if MEMOTECH - in a,($03) - endif - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.8 ; Yes, jump. - ld hl,audio_freq1 - ld bc,$0b00 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret -.8: - ld hl,audio_freq1 - ld bc,$0400 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - inc hl - inc hl - inc c - inc c - ld a,(music_mode) - and 1 - jr z,.9 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - jr .10 -.9: inc hl - inc c - inc hl - inc c -.10: ld b,$02 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret - endif - - ; - ; Enable drum. - ; -enable_drum: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$f5 - ld (audio_vol4hw),a - else - ld hl,audio_mix - ld a,(audio_vol2) - or a - jr nz,.1 - ld a,10 - ld (audio_vol2),a - set 1,(hl) -.1: res 4,(hl) - endif - ret - - ; - ; Musical notes table. - ; -music_notes_table: - ; Silence - 0 - dw 0 - if MEMOTECH+EINSTEIN - ; Values for 4.00 mhz. - ; 2nd octave - Index 1 - dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 - ; 3rd octave - Index 13 - dw 956,902,851,804,758,716,676,638,602,568,536,506 - ; 4th octave - Index 25 - dw 478,451,426,402,379,358,338,319,301,284,268,253 - ; 5th octave - Index 37 - dw 239,225,213,201,190,179,169,159,150,142,134,127 - ; 6th octave - Index 49 - dw 119,113,106,100,95,89,84,80,75,71,67,63 - ; 7th octave - Index 61 - dw 60,56,53 - else - ; Values for 3.58 mhz. - ; 2nd octave - Index 1 - dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 - ; 3rd octave - Index 13 - dw 855,807,762,719,679,641,605,571,539,508,480,453 - ; 4th octave - Index 25 - dw 428,404,381,360,339,320,302,285,269,254,240,226 - ; 5th octave - Index 37 - dw 214,202,190,180,170,160,151,143,135,127,120,113 - ; 6th octave - Index 49 - dw 107,101,95,90,85,80,76,71,67,64,60,57 - ; 7th octave - Index 61 - dw 53,50,48 - endif - - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ; - ; Converts AY-3-8910 volume to SN76489 - ; -ay2sn: - db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 - endif - -music_silence: - db 8 - db 0,0,0,0 - db -2 - endif - - if CVBASIC_COMPRESSION -define_char_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - else - ld a,(mode) - and 8 - jp z,unpack3 - endif - jp unpack - - if SMS - else -define_color_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d -unpack3: - call .1 - call .1 -.1: - push de - push hl - call unpack - pop hl - pop de - ld a,d - add a,8 - ld d,a - ret - endif - - ; - ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) - ; -unpack: -; Initialization - ld a,(hl) - inc hl - exx - ld de,0 - add a,a - inc a - rl e - add a,a - rl e - add a,a - rl e - rl e - ld hl,.modes - add hl,de - ld c,(hl) - inc hl - ld b,(hl) - push bc - pop ix - ld e,1 - exx - ld iy,.loop - -; Main depack loop -.literal: - ex af,af' - call nmi_off - ld a,(hl) - ex de,hl - call WRTVRM - ex de,hl - inc hl - inc de - call nmi_on - ex af,af' -.loop: add a,a - call z,.getbit - jr nc,.literal - -; Compressed data - exx - ld h,d - ld l,e -.getlen: add a,a - call z,.getbitexx - jr nc,.lenok -.lus: add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr nc,.lenok - add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr c,.lus -.lenok: inc hl - exx - ld c,(hl) - inc hl - ld b,0 - bit 7,c - jr z,.offsok - jp (ix) - -.mode6: add a,a - call z,.getbit - rl b -.mode5: add a,a - call z,.getbit - rl b -.mode4: add a,a - call z,.getbit - rl b -.mode3: add a,a - call z,.getbit - rl b -.mode2: add a,a - call z,.getbit - rl b - add a,a - call z,.getbit - jr nc,.offsok - or a - inc b - res 7,c -.offsok: inc bc - push hl - exx - push hl - exx - ld l,e - ld h,d - sbc hl,bc - pop bc - ex af,af' -.loop2: - call nmi_off - call RDVRM ; unpack - ex de,hl - call WRTVRM - ex de,hl ; 4 - call nmi_on - inc hl ; 6 - inc de ; 6 - dec bc ; 6 - ld a,b ; 4 - or c ; 4 - jr nz,.loop2 ; 10 - ex af,af' - pop hl - jp (iy) - -.getbit: ld a,(hl) - inc hl - rla - ret - -.getbitexx: - exx - ld a,(hl) - inc hl - exx - rla - ret - -.modes: - dw .offsok - dw .mode2 - dw .mode3 - dw .mode4 - dw .mode5 - dw .mode6 - - endif - -START: - if SVI+SG1000+SMS - im 1 - endif - if MEMOTECH -Z80_CTC: equ $08 - endif - if EINSTEIN -Z80_CTC: equ $28 - endif - - if EINSTEIN+MEMOTECH - di - im 2 - ld a,rom_start>>8 - ld i,a - ld a,$03 ; Reset Z80 CTC - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - ld a,$08 ; Interrupt vector offset - out (Z80_CTC+0),a - endif - if MEMOTECH - ld a,$25 ; Disable channel 2 interrupt. - out (Z80_CTC+2),a - ld a,$9c - out (Z80_CTC+2),a - ld a,$25 ; Disable channel 1 interrupt. - out (Z80_CTC+1),a - ld a,$9c - out (Z80_CTC+1),a - ld a,$c5 ; Enable channel 0 interrupt (VDP). - out (Z80_CTC+0),a - ld a,$01 - out (Z80_CTC+0),a - endif - if SORD - ld hl,$186c ; Disable handling of CTC Channel 1 interruption. - ld ($7002),hl - ld hl,$7040 - set 0,(hl) ; Avoid BIOS VDP handling. - endif - if SVI - ld e,$00 - ld a,$08 - call WRTPSG - ld a,$09 - call WRTPSG - ld a,$0A - call WRTPSG - ld a,$07 - ld e,$b8 - call WRTPSG - ld a,$92 ; Setup 8255 for keyboard/joystick reading. - out ($97),a - endif - if SG1000+SMS - ; Contributed by SiRioKD - ld a,$9F ; Turn off PSG - out (PSG),a - ld a,$BF - out (PSG),a - ld a,$DF - out (PSG),a - ld a,$FF - out (PSG),a - ld a,$92 ; Setup 8255 for SC3000. - out ($df),a - endif - if SG1000+SMS+SVI - ; Wait for VDP ready (around 1000 ms) - ld b,11 - ld de,$FFFF -.delay1: - ld hl,$39DE -.delay2: - add hl,de - jr c,.delay2 - djnz .delay1 - else - di - ld sp,STACK - endif - if NABU - im 2 - ld a,nabu_int>>8 - ld i,a - ld a,$03 ; Disable ROM - out ($00),a - ld a,$07 - out ($41),a - ld a,$78 ; Setup output ports and mixer. - out ($40),a - ld a,$0e - out ($41),a - ld a,$30 ; Enable video and keyboard. - out ($40),a - endif - if PV2000 - ld hl,nmi_handler - ld ($7499),hl - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - else - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - endif - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffc0) ; Megacart - endif - if SG1000+SMS - ld a,1 ; Sega mapper - ld ($fffe),a - endif - if MSX - ld a,1 ; ASCII 16K - ld ($7000),a - endif - endif - if MEMOTECH+EINSTEIN+NABU - ld ix,(lfsr) - ld hl,ram_start - ld de,ram_start+1 - ld bc,ram_end-ram_start-1 - ld (hl),0 - ldir - ld (lfsr),ix - endif - if MSX+SVI+SMS - ld ix,(lfsr) - ld hl,BASE_RAM - ld de,BASE_RAM+1 - ld bc,RAM_SIZE-1 - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO+SG1000+SORD+PENCIL+PV2000 - ld hl,(lfsr) ; Save RAM trash for random generator. - ld de,BASE_RAM - xor a - ld (de),a - inc de - if PV2000 - bit 7,d ; 2.5K of RAM - endif - if PENCIL - bit 3,d ; 2K of RAM - endif - if COLECO+SG1000+SORD - bit 2,d ; 1K of RAM - endif - jp z,$-4 - ld (lfsr),hl - endif - - if SGM -WRITE_REGISTER: equ $1fd9 -FILL_VRAM: equ $1f82 -WRITE_VRAM: equ $1fdf - - ld b,$00 ; First step. -.0: ld hl,$2000 ; RAM at $2000. -.1: ld (hl),h ; Try to write a byte. - inc h - jp p,.1 ; Repeat until reaching $8000. - ld h,$20 ; Go back at $2000. -.2: ld a,(hl) ; Read back byte. - cp h ; Is it correct? - jr nz,.3 ; No, jump. - inc h - jp p,.2 ; Repeat until reaching $8000. - jp .4 ; Memory valid! - -.3: ld a,$01 ; Enable SGM - out ($53),a - inc b - bit 1,b ; Already enabled? - jr z,.0 ; No, test RAM again. - - ld bc,$0000 - call WRITE_REGISTER - ld bc,$0180 - call WRITE_REGISTER - ld bc,$0206 - call WRITE_REGISTER - ld bc,$0380 - call WRITE_REGISTER - ld bc,$0400 - call WRITE_REGISTER - ld bc,$0536 - call WRITE_REGISTER - ld bc,$0607 - call WRITE_REGISTER - ld bc,$070D - call WRITE_REGISTER - ld bc,$03F0 - ld de,$00E8 - ld hl,$158B ; Note! direct access to Colecovision ROM - call WRITE_VRAM - ld hl,$2000 - ld de,32 - ld a,$FD - call FILL_VRAM - ld hl,$1B00 - ld de,128 - ld a,$D1 - call FILL_VRAM - ld hl,$1800 - ld de,769 - ld a,$20 - call FILL_VRAM - ld bc,$0020 - ld de,$1980 - ld hl,.5 - call WRITE_VRAM - ld bc,$01C0 - call WRITE_REGISTER - jr $ - -.5: db " SUPER GAME MODULE NOT DETECTED " - -.4: - ld ix,(lfsr) - ld hl,$2000 - ld de,$2001 - ld bc,$5FFF - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO - ld a,($0069) - cp 50 - ld a,1 - jr nz,$+3 - dec a - endif - if SG1000+SMS+SVI+SORD+PV2000+NABU - ld a,1 ; Always NTSC. - endif - if MEMOTECH+EINSTEIN - ld a,0 ; Always PAL. - endif - if MSX - call RSLREG - ld b,1 ; $4000-$7fff - call get_slot_mapping - ld h,$80 - call ENASLT ; Map into $8000-$BFFF - - ld a,($002b) - cpl - rlca - and $01 - endif - ld (ntsc),a - - call music_init - - xor a - ld (mode),a - if SMS - call mode_4 - else - call mode_0 - endif - - xor a - ld (joy1_data),a - ld (joy2_data),a - if NABU - ld (nabu_data0),a - ld (nabu_data1),a - endif - ld a,$0f - ld (key1_data),a - ld (key2_data),a - if NABU - ld (nabu_data2),a - endif - - if MSX - ld hl,nmi_handler - ld ($fd9b),hl - ld a,$c3 - ld ($fd9a),a - endif - if SORD - ld hl,nmi_handler - ld ($7006),hl - endif - - ; CVBasic program start. - ; PRINT "The constant is ",myconst - LD HL,cv1 - LD A,16 - CALL print_string - JP cv2 -cv1: - DB $54,$68,$65,$20,$63,$6f,$6e,$73 - DB $74,$61,$6e,$74,$20,$69,$73,$20 -cv2: - LD HL,7 - CALL print_number - ; - ; - ; CVBasic epilogue (BASIC compiler for Colecovision) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and - ; read_pointer variables. - ; Revision date: Mar/04/2024. Added music player. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/13/2024. Added Pletter decompressor. - ; Revision date: Mar/19/2024. Added support for sprite flicker. - ; Revision date: Apr/11/2024. Added support for Super Game Module. - ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. - ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it - ; can remain accessible in bank 0 (bank switching). - ; Revision date: Aug/02/2024. Added rom_end label for Memotech. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. - ; Revision date: Nov/12/2024. Added vdp_status. - ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. - ; - -rom_end: - - ; ROM final size rounding - if MSX+COLECO+SG1000+SMS+SVI+SORD - TIMES (($+$1FFF)&$1e000)-$ DB $ff - endif - if MEMOTECH+EINSTEIN+NABU - ; Align following data to a 256-byte page. - TIMES $100-($&$ff) DB $4f - endif - if PV2000 - TIMES $10000-$ DB $ff - endif - if SG1000+SMS - if CVBASIC_BANK_SWITCHING - forg CVBASIC_BANK_ROM_SIZE*1024-1 ; Force final ROM size - db $ff - endif - forg $7FF0 - org $7FF0 - db "TMR SEGA" - db 0,0 - db 0,0 ; Checksum - db $11,$78 ; Product code - db $00 ; Version - db $4c ; SMS Export + 32KB for checksum - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 - org BASE_RAM - endif -ram_start: - -sprites: - if SMS - rb 256 - else - rb 128 - endif -sprite_data: - rb 4 -frame: - rb 2 -read_pointer: - rb 2 -cursor: - rb 2 -lfsr: - rb 2 -mode: - rb 1 -flicker: - rb 1 -joy1_data: - rb 1 -joy2_data: - rb 1 -key1_data: - rb 1 -key2_data: - rb 1 -ntsc: - rb 1 -vdp_status: - rb 1 - if NABU -nabu_data0: rb 1 -nabu_data1: rb 1 -nabu_data2: rb 1 - endif - - if CVBASIC_MUSIC_PLAYER -music_tick: rb 1 -music_mode: rb 1 - - if CVBASIC_BANK_SWITCHING -music_bank: rb 1 - endif -music_start: rb 2 -music_pointer: rb 2 -music_playing: rb 1 -music_timing: rb 1 -music_note_counter: rb 1 -music_instrument_1: rb 1 -music_counter_1: rb 1 -music_note_1: rb 1 -music_instrument_2: rb 1 -music_counter_2: rb 1 -music_note_2: rb 1 -music_instrument_3: rb 1 -music_counter_3: rb 1 -music_note_3: rb 1 -music_counter_4: rb 1 -music_drum: rb 1 - -audio_freq1: rb 2 -audio_freq2: rb 2 -audio_freq3: rb 2 -audio_noise: rb 1 -audio_mix: rb 1 -audio_vol1: rb 1 -audio_vol2: rb 1 -audio_vol3: rb 1 - -audio_control: rb 1 -audio_vol4hw: rb 1 - endif - - if SGM - org $2000 ; Start for variables. - endif -ram_end: diff --git a/test1.bas b/test1.bas deleted file mode 100644 index 6b8c654..0000000 --- a/test1.bas +++ /dev/null @@ -1,2 +0,0 @@ - PRINT "The constant is ",myconst - From dc1c62eba7258a6cfc921e5a0e5bee55f2451b18 Mon Sep 17 00:00:00 2001 From: Tursilion Date: Sat, 3 May 2025 15:18:35 -0600 Subject: [PATCH 036/155] - fix the unpack function which was using the stack register as a temp --- cvbasic_9900_prologue.asm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 8158433..4b016bd 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -18,6 +18,7 @@ ; Revision date Aug/18/2024. Ported bugfixes to TMS9900 version ; Revision date Aug/30/2024. All samples except pletter and banking working on TMS9900 version ; Revision date Oct/15/2024. Added LDIRMV. +; Revision date May/03/2025. Fix for unpack3 which was using the stack pointer as a temp register ; ; Platforms supported: @@ -1515,15 +1516,15 @@ define_color_unpack ; entered from one of the above two functions unpack3 mov r11,r9 ; save return address - mov r4,r10 ; save VDP address + mov r4,r12 ; save VDP address mov r2,r4 bl @unpack - ai r10,>800 - mov r10,r1 + ai r12,>800 + mov r12,r1 mov r4,r2 bl @unpack - ai r10,>800 - mov r10,r1 + ai r12,>800 + mov r12,r1 mov r4,r2 bl @unpack b *r9 From 1aa06935b890d9e6e5a7ba223e4a2afdaa4a633a Mon Sep 17 00:00:00 2001 From: Tursilion Date: Sat, 3 May 2025 16:10:34 -0600 Subject: [PATCH 037/155] - fix uninitialized variable going into unpack (why did it ever work?) --- cvbasic_9900_prologue.asm | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 4b016bd..d645d1c 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -135,7 +135,7 @@ lastsp equ $ ; reads VDP status for us (no choice). intcnt equ >8379 ; interrupt counter byte, adds 1 (from GPLWS r14) every frame -vdp_status equ >837B ; VDP status byte mirror +vdp_status equ >837B ; VDP status byte mirror intwsr1 equ >83c2 ; INT WS R1 - interrupt control flags - must be >8000 intwsr2 equ >83c4 ; INT WS R2 - address of user interrupt routine (point to int_handler) intwsr11 equ >83d6 ; screen timeout counter - must be odd (init to 1, is inct every frame) @@ -1516,16 +1516,17 @@ define_color_unpack ; entered from one of the above two functions unpack3 mov r11,r9 ; save return address - mov r4,r12 ; save VDP address - mov r2,r4 + mov r4,r15 ; save VDP address + mov r2,r14 ; save CPU address + mov r15,r1 bl @unpack - ai r12,>800 - mov r12,r1 - mov r4,r2 + ai r15,>800 + mov r15,r1 + mov r14,r2 bl @unpack - ai r12,>800 - mov r12,r1 - mov r4,r2 + ai r15,>800 + mov r15,r1 + mov r14,r2 bl @unpack b *r9 @@ -1535,15 +1536,6 @@ unpack3 ; Unpack data to VDP: VDP address in R1, CPU data in R2 ; Original: pointer = VDP, temp = CPU address, a = number chars -; The challenge with porting is the 8 bit vs 16-bit registers, and the behaviour of rotate -; 9900 shifts and rotates are always 16 bits wide, and do not include the carry bit -; rather, shifted out bits are /copied/ to carry, but carry is never copied in. This makes -; most of the optimized code difficult to port - but if we knew the original intent, it -; wouldn't be so bad. In addition, the 9900 has very few instructions that preserve -; status flags, meaning we can't execute an instruction and then check status for the -; instruction before it in nearly any case, the code uses this too. -; I've not been able to locate any C code for the unpacker which would probably be easier to port. - r0lsb equ mywp+1 r1lsb equ mywp+3 r2lsb equ mywp+5 From 05874bcb7f86ce33ce0538e87f0672f5afce22d3 Mon Sep 17 00:00:00 2001 From: Tursilion Date: Tue, 6 May 2025 15:08:10 -0600 Subject: [PATCH 038/155] - add an EVEN directive before labels in the CPU9900 target. This fixes misaligned code after a data table with an odd number of bytes. --- cvbasic.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cvbasic.c b/cvbasic.c index ad09815..76badea 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5735,6 +5735,12 @@ void compile_basic(void) } else { label = label_add(name); } + + if (target == CPU_9900) { + // code MUST be even aligned - most of the time this will do nothing + cpu9900_noop("even"); + } + label->used |= LABEL_DEFINED; strcpy(temp, LABEL_PREFIX); strcat(temp, name); From 631f7f99b465797d2350c43403441c3e97e99026 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 6 May 2025 16:00:21 -0600 Subject: [PATCH 039/155] Added vgm_ay.bas example for AY-3-8910 VGM playing --- README.md | 3 +- examples/02 Map Screen.vgm | Bin 0 -> 28778 bytes examples/vgm_ay3.bas | 88 +++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 examples/02 Map Screen.vgm create mode 100644 examples/vgm_ay3.bas diff --git a/README.md b/README.md index 49d62f0..4e8a73d 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,8 @@ The following files compose the compiler: examples/test3_sms.bas Shows usage of SELECT CASE / END CASE (Sega Master System) examples/varptr.bas VARPTR example for redefining graphics. examples/varptr_sms.bas VARPTR example for redefining graphics (Sega Master System) - examples/vgm.bas VGM audio player. + examples/vgm.bas VGM audio player for SN76489. + examples/vgm_ay.bas VGM audio player for AY-3-8910. examples/viboritas.bas Game example. examples/viboritas_sms.bas Game example (Sega Master System) examples/vramcopy.bas VRAM copy example. diff --git a/examples/02 Map Screen.vgm b/examples/02 Map Screen.vgm new file mode 100644 index 0000000000000000000000000000000000000000..74dd80e3d8ed985042fcfc17b850c5a723197411 GIT binary patch literal 28778 zcmd6wO^jYwdB?A3#(q6Bp0ORb3vfJ6+dxqQL?N=24<{pV=~NAYp>ZjurS9zv#!O7G zGj=A%#P0&h3LzRrQ5Hy1HLpY@WU@4L19DqsWx)>30%e&+g-|p?ZnGh-`ujiU``-J` zj1yE9eZ~x#or2 z{Qc#<2df>tZ;Iyz)!bl5H5i#2j8=oO-wby42D|nSdb5Mw)nL3DOjP|r@3HfPYOQ}^ z&^vm0F!J+rgVE9F2E9+79gOTaI~d*3e`e6T=lQ|do^ykpJ1!2!etdSY^T+l7j0|>9 zpC63xeTGM9HcG1p&krW1>TizHmNq;3gRyn~UDf~0m8FHV{Jbz2yHVGpgYoHa55^Yj zGoyovJ-YVnU~H}a2F>Od_#3~h1G{p?y7)TJO!15faXxhX)zLxkp_M`JkriH0FOCkX zYv%{OhrcrzSwW=UvWe8YMDMQcD_p z8$*`tPO7i*#x>sf;HAOD1U;M7dV|UQ4;prTj(@s0s>j9JMsg{Pd4Ul;jP&zN&&Zpa zZgt0>dk}5M@?c_|?$%hN>5GG1`unl^<2=HwoA7Tk#6zsWub)MLX9i=FTBG`(Mh7Ds zT$$v`ujOtB}(S~>L9M$xVPcIKf?&s<>SMTNOn6;bZ z3U3^{Dd9)H%0&H)dpqsdvTyxeuI#ca-+OK__Bg+K*5edCvY-?Ed+Y#Lch^kX$WIyJ zVMg4**V0e(%^XPM*Q*Wcor zrh^IHxknQ)K27`Y^UKt8Vw`@Tv42AsG$@V3_WBR zLYT3iAi@|!eYF1T2?nrmf#s|JV+tHB&~A3&+W_}@KX0hPQQl*i4Vqp*Iy%^mzMG;1 zh#sx~ogStac*{in6hnBlK0)uk%ZpwI>F!ZUtfipkIQqBuIj?_=psGLRrEcjTcXtTj zBO8c2$uuzg!$tD-7>WU2^1Y`VykP8W40 z=^|P;Zn{YCZC#wfBm`Y#&_Nfc1ww%mAnrl*sEZMRW-SYSMB8lOP9LRTzn4Ze^${E5 z^bs4_JM`>eZ*zt8j-%jfk~)&?`(JInx` z-kxMaFI*Z_t6ZHC@SfDn@+S@!Guc$&d-}+`p{3{FjsPYl6^H~!4dZX^F#gwTtlQYh z1$6y7Sicqx|A}b$uOZf|nfbW|{>HD3T4r*^K~FE`nswBBn6*ABogMiRDvpHCPG;sp z#{D|&uhmcZDf5bS+GwLf6xO(Y3EEYYvH-DKcFZLP2NtxB^ z1=!HPBi=cofmJU(>ln(tKsQ%GsDz%Y|B+uW_pyX;3Y?N0bQvuPUA$}ca&F;2O7m9) zT&DL;q`#9Ve~sQwu&k4Yu)m|ltKZI1CY-$ToVWC}mAbx0+mTv#UIsY_z2>tXSbJS% zzMaMAPC^{CRlP({hBV%I)7rjB4+(7=&o;_(36IcML4sd68 zt+uPQ{V6js!wkG-S0v{zm~E$3AYxj}+d?4R?IuX->-BF2R6GSLCaj}ZSwxv1heGN6 zE0={tE%3`?Ywo>?AbV_8Z6XlbAyVrsB^XCodWR*nzAy6pL4NJEUoSil^0@zYy!Qt8 z_Q}<8n!uDM6zct}U@e2-%g?)YH4SYH6peNCalz5YJ))0KBJusaV~obAjz{5#==l}z zhDBvJ3ehNDMP_>jB|2K$EQrCXmlyov3r^Kb%*P(la`htDU*OM+*2)&nTF6#Bik~%W zJ{I#=&7K|XkRm^ZuVpL1-;YYlY`rGyPs2ddo`If3^+&OkN9%u^qPJyKPj<1wTI{Iw zv{t45iSe5{UO+imA#;d~+hmIcmmDh0M^)eNEm1dAN-~lIW6n?k5nV0e5uKp|8gg9{ zEc8@@gnpH9hy;XIHk_dd19OHV1hi)FFm7{*Y+CUZ3<93ilS9PRR=;gb?F`1|DW=3h z;5RJ@{5C@19oaa9a1fAsW9`faItU2gzmtY~V#;Mm#PnCRy6I&I(L z%pC{bj=1)FZm=%I4F(rQE!Ga=x*;_mTU>BX`Zbvdo12oi%7EpH@zycNTe$aE;GuQR zK_ftszz^fL{eS`NWB}&tX9Gw93M*_3U@Za8gRtSE;AjELHGAI)WEA173EaJhGUZ_QN~>sW+Yk?x?^Axv8bmMm^eDpFQcMg zLgOtO0@6Mx!7Tj}bdIn>34hyk0-0xrH?%LK8wD{ALye$>q3n~lG(J_(3r3`Omv{SmzdJ%poK` zr7dNc-NSO5=*|bybp8OpCM_`bfi%|~PXN*JX>6O*S-B31%1p;D5Wq0`Qkxtr$%Q%+ zTmdG?T7nlK?Dd?UTY-#%_!M~CyIE%q*6BHz88Meflgpp{y=@N)^S`0hk2LV7UJFXE z33YPqpsMRe11A@P!=GqCa8=&w8h=9gf=iaiFOqkPxys@fX8NQ#h!?Q`!D;HU|1O64 zOXhdkM*-H_bHIuE@40hMfrw21YOPpfSs}`tIkOk!XgX0&Xo)&>4z<0+mE_3j z%JallMj%M#2t;$Pb}6GEAIT<$x0D$!wOygDkqM)Av5n;X#ihZ>yFp*&(7HJ*lMB_d zcj({c?g++JK9$3$u;q?3^o_7fa-G9Ca zZFKJq)@7e*h>bTS#DLR&3o4`x376{e0#-hFIEKw^tOYhP!T0nLuf*nIx(G`01I*Y? zslK^s67U=%r5wW-)i&v{Y5#R$v;GQqg7%*hbn8R@O%u)Z;r%)E=5bWBr`UCzM0Nv)D57Q7lwwdg@s=51qb$W(EY#~wD3barLM&UP z*IO_&_bx&(%Q=@+8DVGc9rrNfMb23i=duWL${oz;dpzcx4Ptn!%K2qEJg%5eF(aqv zJ;WQ6E5l%74v&Oo8)x4cj9o>7l*8NWSJ%3T7!wCtJM90Os*o5MwT;@PwGY zrSN7K_#3~LEHpV11B)fDT~$Ap4LdIPaOARFW`yp7$W_{}#T4FUKl_5nyru9I%&giw z=6IufKWlAr&02=%w8C3f+({$Ao?&<@9D^LXId<0^B}nK{FFI5Qi0@siZ)J(PWK%ADf%86foZh`NjLWJRa^p7<9Tz^z!!$fYovHq+tKE3k)SWKU9ctTw zXL+qYVd=b9J$Z^JQ|d!cw(yKP?zX663G}8Eh@Lh)qvw}%9dAXJ1)eotmR-@^Q{ZhI zc$T?lc3hMx<+pj@jq)nLPajjZV5j>TWoJ3Fz@p|>kY1`pm<1ySr#c!MPG;j}a z%8X=`BjR3mQ|KFc2VPPFub|ywr8CPc0#KKM{1ANvkXSb{r6S*1zz>kYDfl(lzK6hH4eKEwV zylLCW2L%ThK^OA%7Rf0mImW9Q;*yh`BR?$r2Sz>%F+E-4^h3FyO!u?3(Jz7nJ7fR?2*;u{KRhPDTU zIX!l;O?YOlMda%V>F)#2xM`Nz$C_!EgF;j%OBeF_d18O ziIp3u4-RKslLnm0iu~c=3>Y#v1Ku+I^mGnq+Ga$)Ih;|xw3*6?oSw`vXZdcLH4;Im zO;v*45IFN>nSL@NZ^gZG|09vJ5-$DJf^+7-b-+1W^#+_<=_luy3yL_zTN1h8cA9;L z(V+-(pnb_<&xt(vkttnlMBauy7;|YVnT(V=HirUdB9<1JlSeQHcbF!hA#tPpypNk2al6^s?BL79$jE-O3xE-3qvvHRpkgb!{#p z4+}!_E|aINHYuVu9v%`=+p{?j15=kbE_qlzDx%`+R;cs15^avm;mC?Vun8)glQ z${U*->T?c4x!tewO;6FZ@`mS_XBDa8C&KzxtSuvX63f#f{AJGHo0|#)VzO_6d7;n z*;2MbYVI@~YfPDE;vCd@SnYkV2B`fUg{3cxK@rs8VA4XSEz@M;I%LVhYS{S6j&xlI z8#9lg6xm?o&A=bn*nn@wrIU@dCZzVNC1jZ)a2=UrLbT5_<`I3~q3w|aGV{ozCD`NH zc#cPQ#mu(YIE2ATL^4`394c@AWx_I7>d2rfNz^h4X*_eZ|&&5nFOhENS&o zx2?u9-H`K=?Wv=Sk-L#X=DRD~Eri~1``f{awe+5LI*oA6R#xvip$!jKBwCC9!+dy; zA==4Cg<$O1LfGgdXzJ-DC#h!3-Wqc9i&h$1YJpew$mh3j6pTzh%$%KqjWI-B=MQ*^ z_M?nY#B1ciV2ws3jMyFdY_W?n%_*OaInP|?uk*`5iUcnDH9q2rl=or^(v}|p?;>B@ zekVX+p58KNNAD5i+8zbz9?F>SEGWQfrLlZB!&AV%c_cx4MAnJTrxZRi_gIA*^a8nNL;dOPM`&lgrvlDY@vI|==t69jZt_^eaT%P+8a$@$0 z)q9s@GW;qLw3^xksIjCGGiQ4w=o znR12?%vtU#=b9XIw49DHRG#H>Stz~Rm2o%295Qu;pmI!?bi{6ke{5b&LW%@FBCD%h zNWSlw2j6=LJ{A+o0$Hjep%(Fk-D=e3W-XT#ckdw#)-3$dXOV{2b05K#J#I({TOW!F zk?12soy#lDdenuopUV+r8jV#$T^ESEYLE%z_qEO%(NVRD`&ylNw4oTJ5<1QvDK>5E7CGz5ognl66;zaJ7+z#nQ2sU9#m2$ZE%EXRhN%o# z;S>%bC>)Sf9-+-^XhdUQE!J%qIZ2084pj(C`BVKWok3kmc~j_TOHwk7XcI#qBSo=V zm?lO{eQZ&@6PDovJ$LxX_6Ko|BVe6GBz?C1NGwF4)#InqO%KE2DGT_sM~ z)ZwG0D|v)53O`=?+M5^9x3c6h6SNZigc@c#yBdP5tLDEQUqGv{%z4Nn$Sb9yaHZTn zv~Fh{mSVPS;13XsW%d7W7bOAwjth?A^P_j*d zAoS|?j@2SybsbHMY(oz>ReEobv*sifCX8RBLS+FjOh$m(F zQLC{PjId9Ux9z(Emw+ni>vbW9?1X$cr3pg)4XrdEZVhd{RiLVGs4|UJKA$BiQhiwf zA^kFLN^AX&e~G{aA}B(9b{3_n3y%Qt2vFOvXP3R~N6 znb+Bc8hM>A-KVj(SxG{6R=5s(`xIHJC|LvSX6`^V3lbZwh$c+Q84_&EZ0b6{HnnrtO|S4}Mk9 z;Nk>2?@h%h`Bh7nrn?~x24$hT5erfoONj+<)U$rULUltZYo9)cSg$cd&Ew~Ael!en z1Vu|$FC)$ov3}6w=iO;KfM_%|JWa>)X5S;)jsuALlrU48Zjb*GL8K~3Y-sSrJG0@A8tVhr*R6^zC~laMidqn&VZLGV2Z?oGanW$ z?ap9XvSYeR7iHh21MH1r6rh+=oiV1gnuX^g4;cOOkk%5|x8SxIkr~)L*d5q-uitgS zvc89Q#`A<3xwgqIoF|M9@$$9=&Yztfwr49pWv(R#s^F}5S$YGtXJt}vieO#cIQDn1*AMkS6-q! zLJL{=ZA56y(3_0aBe00j2=9A$77?2E&V7tP!J$ifyhakv(V2pdH;m4<6R8;@Sl3A7 zULD)14n(pFR0P&XGJbduUrl>HQnuX+!3HYPS?~w*0O5EP<~g@>e^n~# zlouxlz2%_>#Pr37M%jw-*fCg*#fNE5r6Z+bQUbJYt8CSR)E5x<2;w?Ktv3;6;^F{g zh+-ZSqB^*(JhTh9xhx{&+x{+$bhuILWg)hT*OM*T%mjDVO&t~Lv(js&PQPY(?MM0FxovpyHMxdPHYy>)o1jP97P>zJK|a5 zb(v_*cjPZwkaZB)L|B-Ftu}uzRXNDfFY*QC{GNhh`!F`8?)h8#C!x&;St3zd( zY?Q)SVBT`xsh*`H7)Nx_eAadmt?RFX*1A$yutU&Qmm!z8=(bWYtco4`#$HD4fd({@ zE%thp*0Y|yLfJ%dnmeL%O8^mlS%QTkm*9=xw_fBFeU&Q%o0I8D8-d_1leZ4+9Ihn4 zuXgb!*S&eWU~PNVE=0Jky%kK|A0lW|f~gGH{+5B=C){CXe};y;qjcAE+<~-R+9&fq z_gHLxbWRpB;)BAH=AM$HFc^MTtYkiQqY%EJ4atMpVboaflVoR z2D0EHI)#oYN5ngBTRp|~auc@(+NbIMW8Pwgm2z&PfWDT1CUm4~au~pERm2KZ$*0|{ zB9?iFR!xq(>klE7ml@1y}%_y6qmL3g2*e6 zIKx~z4wX-Udh4CeV-$yOp8R0uQiY6nK7wR-sEFfs!EgUO460*Ed;aaRAS4^(Y_!kA z^ohq(k{{lsQWlc@cp$Ot%9YNHTp5E9Z-u-#246bkmD;eSoTL*~WB3?jaEI9< zl5g3*m40-Aht<$Je9Cxq?RI$%KkHWt3p+N->*^*^8d~V8)AA&>VWq4AC`v2+OW`2; zm%R78=>0AceKSg9!m+iRe=r>jYKy{L49}C~To($TDN@_o&y+2p5Us+76p((?sT3W+JIa+Z9kRidA%Ps~=eJR{(jmN| zcZjcQDwsQr9=M(IvFH{+CmHzDy-h@`Ionvxl%Q0G>z2qc26!16axF`d@CF51jtm8m z&5w&=RHI`X5~G%&G+=H`hz54vd6;)PP(qPbP%4jwF*W(X+j$f?qVz=f(@zLJtpW#C zrv&9Xgcu^d8Qi37LuE&ZT(qwaaw^M`^g{GKmqNyya%CJj`w56UBMl=#xHE>@rx$x~= #vgm_end THEN #vgm_pointer = 0: RETURN + + WHILE 1 + vgm_byte = PEEK(#vgm_pointer) + #vgm_pointer = #vgm_pointer + 1 + IF vgm_byte = $a0 THEN + OUT VGM_PSG_PORT,PEEK(#vgm_pointer) + #vgm_pointer = #vgm_pointer + 1 + OUT VGM_PSG_PORT + 1,PEEK(#vgm_pointer) + #vgm_pointer = #vgm_pointer + 1 + ELSEIF vgm_byte = $61 THEN + #vgm_pointer = #vgm_pointer + 2 + EXIT WHILE + ELSEIF vgm_byte = $62 THEN + EXIT WHILE + ELSEIF vgm_byte = $63 THEN + EXIT WHILE + ELSEIF vgm_byte = $66 THEN + #vgm_pointer = 0 + EXIT WHILE + END IF + WEND + END + + ' + ' You can download VGM music from: + ' https://vgmrips.net/packs/chip/ay-3-8910?letter=L + ' + ' You need to decompress the file, and inside each file is compressed with gzip, + ' so you need to decompress again each file. + ' +vgm_music: + ASM INCBIN "02 map screen.vgm" From 9fae405354ae2da8a605ecc51ed5255a289e0ee7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 6 May 2025 17:39:56 -0600 Subject: [PATCH 040/155] Adjusted precedence so NOT NOT 5 and NOT -5 are functional --- cvbasic.c | 4 ++-- examples/02 Map Screen.vgm | Bin 28778 -> 0 bytes 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 examples/02 Map Screen.vgm diff --git a/cvbasic.c b/cvbasic.c index ad09815..d9e8865 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -1213,7 +1213,7 @@ struct node *evaluate_level_6(int *type) if (lex == C_MINUS) { get_lex(); - left = evaluate_level_7(type); + left = evaluate_level_6(type); if ((*type & MAIN_TYPE) == TYPE_8) left = node_create(N_NEG8, 0, left, NULL); else @@ -1221,7 +1221,7 @@ struct node *evaluate_level_6(int *type) } else if (lex == C_NAME && strcmp(name, "NOT") == 0) { get_lex(); - left = evaluate_level_7(type); + left = evaluate_level_6(type); if ((*type & MAIN_TYPE) == TYPE_8) left = node_create(N_NOT8, 0, left, NULL); else diff --git a/examples/02 Map Screen.vgm b/examples/02 Map Screen.vgm deleted file mode 100644 index 74dd80e3d8ed985042fcfc17b850c5a723197411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28778 zcmd6wO^jYwdB?A3#(q6Bp0ORb3vfJ6+dxqQL?N=24<{pV=~NAYp>ZjurS9zv#!O7G zGj=A%#P0&h3LzRrQ5Hy1HLpY@WU@4L19DqsWx)>30%e&+g-|p?ZnGh-`ujiU``-J` zj1yE9eZ~x#or2 z{Qc#<2df>tZ;Iyz)!bl5H5i#2j8=oO-wby42D|nSdb5Mw)nL3DOjP|r@3HfPYOQ}^ z&^vm0F!J+rgVE9F2E9+79gOTaI~d*3e`e6T=lQ|do^ykpJ1!2!etdSY^T+l7j0|>9 zpC63xeTGM9HcG1p&krW1>TizHmNq;3gRyn~UDf~0m8FHV{Jbz2yHVGpgYoHa55^Yj zGoyovJ-YVnU~H}a2F>Od_#3~h1G{p?y7)TJO!15faXxhX)zLxkp_M`JkriH0FOCkX zYv%{OhrcrzSwW=UvWe8YMDMQcD_p z8$*`tPO7i*#x>sf;HAOD1U;M7dV|UQ4;prTj(@s0s>j9JMsg{Pd4Ul;jP&zN&&Zpa zZgt0>dk}5M@?c_|?$%hN>5GG1`unl^<2=HwoA7Tk#6zsWub)MLX9i=FTBG`(Mh7Ds zT$$v`ujOtB}(S~>L9M$xVPcIKf?&s<>SMTNOn6;bZ z3U3^{Dd9)H%0&H)dpqsdvTyxeuI#ca-+OK__Bg+K*5edCvY-?Ed+Y#Lch^kX$WIyJ zVMg4**V0e(%^XPM*Q*Wcor zrh^IHxknQ)K27`Y^UKt8Vw`@Tv42AsG$@V3_WBR zLYT3iAi@|!eYF1T2?nrmf#s|JV+tHB&~A3&+W_}@KX0hPQQl*i4Vqp*Iy%^mzMG;1 zh#sx~ogStac*{in6hnBlK0)uk%ZpwI>F!ZUtfipkIQqBuIj?_=psGLRrEcjTcXtTj zBO8c2$uuzg!$tD-7>WU2^1Y`VykP8W40 z=^|P;Zn{YCZC#wfBm`Y#&_Nfc1ww%mAnrl*sEZMRW-SYSMB8lOP9LRTzn4Ze^${E5 z^bs4_JM`>eZ*zt8j-%jfk~)&?`(JInx` z-kxMaFI*Z_t6ZHC@SfDn@+S@!Guc$&d-}+`p{3{FjsPYl6^H~!4dZX^F#gwTtlQYh z1$6y7Sicqx|A}b$uOZf|nfbW|{>HD3T4r*^K~FE`nswBBn6*ABogMiRDvpHCPG;sp z#{D|&uhmcZDf5bS+GwLf6xO(Y3EEYYvH-DKcFZLP2NtxB^ z1=!HPBi=cofmJU(>ln(tKsQ%GsDz%Y|B+uW_pyX;3Y?N0bQvuPUA$}ca&F;2O7m9) zT&DL;q`#9Ve~sQwu&k4Yu)m|ltKZI1CY-$ToVWC}mAbx0+mTv#UIsY_z2>tXSbJS% zzMaMAPC^{CRlP({hBV%I)7rjB4+(7=&o;_(36IcML4sd68 zt+uPQ{V6js!wkG-S0v{zm~E$3AYxj}+d?4R?IuX->-BF2R6GSLCaj}ZSwxv1heGN6 zE0={tE%3`?Ywo>?AbV_8Z6XlbAyVrsB^XCodWR*nzAy6pL4NJEUoSil^0@zYy!Qt8 z_Q}<8n!uDM6zct}U@e2-%g?)YH4SYH6peNCalz5YJ))0KBJusaV~obAjz{5#==l}z zhDBvJ3ehNDMP_>jB|2K$EQrCXmlyov3r^Kb%*P(la`htDU*OM+*2)&nTF6#Bik~%W zJ{I#=&7K|XkRm^ZuVpL1-;YYlY`rGyPs2ddo`If3^+&OkN9%u^qPJyKPj<1wTI{Iw zv{t45iSe5{UO+imA#;d~+hmIcmmDh0M^)eNEm1dAN-~lIW6n?k5nV0e5uKp|8gg9{ zEc8@@gnpH9hy;XIHk_dd19OHV1hi)FFm7{*Y+CUZ3<93ilS9PRR=;gb?F`1|DW=3h z;5RJ@{5C@19oaa9a1fAsW9`faItU2gzmtY~V#;Mm#PnCRy6I&I(L z%pC{bj=1)FZm=%I4F(rQE!Ga=x*;_mTU>BX`Zbvdo12oi%7EpH@zycNTe$aE;GuQR zK_ftszz^fL{eS`NWB}&tX9Gw93M*_3U@Za8gRtSE;AjELHGAI)WEA173EaJhGUZ_QN~>sW+Yk?x?^Axv8bmMm^eDpFQcMg zLgOtO0@6Mx!7Tj}bdIn>34hyk0-0xrH?%LK8wD{ALye$>q3n~lG(J_(3r3`Omv{SmzdJ%poK` zr7dNc-NSO5=*|bybp8OpCM_`bfi%|~PXN*JX>6O*S-B31%1p;D5Wq0`Qkxtr$%Q%+ zTmdG?T7nlK?Dd?UTY-#%_!M~CyIE%q*6BHz88Meflgpp{y=@N)^S`0hk2LV7UJFXE z33YPqpsMRe11A@P!=GqCa8=&w8h=9gf=iaiFOqkPxys@fX8NQ#h!?Q`!D;HU|1O64 zOXhdkM*-H_bHIuE@40hMfrw21YOPpfSs}`tIkOk!XgX0&Xo)&>4z<0+mE_3j z%JallMj%M#2t;$Pb}6GEAIT<$x0D$!wOygDkqM)Av5n;X#ihZ>yFp*&(7HJ*lMB_d zcj({c?g++JK9$3$u;q?3^o_7fa-G9Ca zZFKJq)@7e*h>bTS#DLR&3o4`x376{e0#-hFIEKw^tOYhP!T0nLuf*nIx(G`01I*Y? zslK^s67U=%r5wW-)i&v{Y5#R$v;GQqg7%*hbn8R@O%u)Z;r%)E=5bWBr`UCzM0Nv)D57Q7lwwdg@s=51qb$W(EY#~wD3barLM&UP z*IO_&_bx&(%Q=@+8DVGc9rrNfMb23i=duWL${oz;dpzcx4Ptn!%K2qEJg%5eF(aqv zJ;WQ6E5l%74v&Oo8)x4cj9o>7l*8NWSJ%3T7!wCtJM90Os*o5MwT;@PwGY zrSN7K_#3~LEHpV11B)fDT~$Ap4LdIPaOARFW`yp7$W_{}#T4FUKl_5nyru9I%&giw z=6IufKWlAr&02=%w8C3f+({$Ao?&<@9D^LXId<0^B}nK{FFI5Qi0@siZ)J(PWK%ADf%86foZh`NjLWJRa^p7<9Tz^z!!$fYovHq+tKE3k)SWKU9ctTw zXL+qYVd=b9J$Z^JQ|d!cw(yKP?zX663G}8Eh@Lh)qvw}%9dAXJ1)eotmR-@^Q{ZhI zc$T?lc3hMx<+pj@jq)nLPajjZV5j>TWoJ3Fz@p|>kY1`pm<1ySr#c!MPG;j}a z%8X=`BjR3mQ|KFc2VPPFub|ywr8CPc0#KKM{1ANvkXSb{r6S*1zz>kYDfl(lzK6hH4eKEwV zylLCW2L%ThK^OA%7Rf0mImW9Q;*yh`BR?$r2Sz>%F+E-4^h3FyO!u?3(Jz7nJ7fR?2*;u{KRhPDTU zIX!l;O?YOlMda%V>F)#2xM`Nz$C_!EgF;j%OBeF_d18O ziIp3u4-RKslLnm0iu~c=3>Y#v1Ku+I^mGnq+Ga$)Ih;|xw3*6?oSw`vXZdcLH4;Im zO;v*45IFN>nSL@NZ^gZG|09vJ5-$DJf^+7-b-+1W^#+_<=_luy3yL_zTN1h8cA9;L z(V+-(pnb_<&xt(vkttnlMBauy7;|YVnT(V=HirUdB9<1JlSeQHcbF!hA#tPpypNk2al6^s?BL79$jE-O3xE-3qvvHRpkgb!{#p z4+}!_E|aINHYuVu9v%`=+p{?j15=kbE_qlzDx%`+R;cs15^avm;mC?Vun8)glQ z${U*->T?c4x!tewO;6FZ@`mS_XBDa8C&KzxtSuvX63f#f{AJGHo0|#)VzO_6d7;n z*;2MbYVI@~YfPDE;vCd@SnYkV2B`fUg{3cxK@rs8VA4XSEz@M;I%LVhYS{S6j&xlI z8#9lg6xm?o&A=bn*nn@wrIU@dCZzVNC1jZ)a2=UrLbT5_<`I3~q3w|aGV{ozCD`NH zc#cPQ#mu(YIE2ATL^4`394c@AWx_I7>d2rfNz^h4X*_eZ|&&5nFOhENS&o zx2?u9-H`K=?Wv=Sk-L#X=DRD~Eri~1``f{awe+5LI*oA6R#xvip$!jKBwCC9!+dy; zA==4Cg<$O1LfGgdXzJ-DC#h!3-Wqc9i&h$1YJpew$mh3j6pTzh%$%KqjWI-B=MQ*^ z_M?nY#B1ciV2ws3jMyFdY_W?n%_*OaInP|?uk*`5iUcnDH9q2rl=or^(v}|p?;>B@ zekVX+p58KNNAD5i+8zbz9?F>SEGWQfrLlZB!&AV%c_cx4MAnJTrxZRi_gIA*^a8nNL;dOPM`&lgrvlDY@vI|==t69jZt_^eaT%P+8a$@$0 z)q9s@GW;qLw3^xksIjCGGiQ4w=o znR12?%vtU#=b9XIw49DHRG#H>Stz~Rm2o%295Qu;pmI!?bi{6ke{5b&LW%@FBCD%h zNWSlw2j6=LJ{A+o0$Hjep%(Fk-D=e3W-XT#ckdw#)-3$dXOV{2b05K#J#I({TOW!F zk?12soy#lDdenuopUV+r8jV#$T^ESEYLE%z_qEO%(NVRD`&ylNw4oTJ5<1QvDK>5E7CGz5ognl66;zaJ7+z#nQ2sU9#m2$ZE%EXRhN%o# z;S>%bC>)Sf9-+-^XhdUQE!J%qIZ2084pj(C`BVKWok3kmc~j_TOHwk7XcI#qBSo=V zm?lO{eQZ&@6PDovJ$LxX_6Ko|BVe6GBz?C1NGwF4)#InqO%KE2DGT_sM~ z)ZwG0D|v)53O`=?+M5^9x3c6h6SNZigc@c#yBdP5tLDEQUqGv{%z4Nn$Sb9yaHZTn zv~Fh{mSVPS;13XsW%d7W7bOAwjth?A^P_j*d zAoS|?j@2SybsbHMY(oz>ReEobv*sifCX8RBLS+FjOh$m(F zQLC{PjId9Ux9z(Emw+ni>vbW9?1X$cr3pg)4XrdEZVhd{RiLVGs4|UJKA$BiQhiwf zA^kFLN^AX&e~G{aA}B(9b{3_n3y%Qt2vFOvXP3R~N6 znb+Bc8hM>A-KVj(SxG{6R=5s(`xIHJC|LvSX6`^V3lbZwh$c+Q84_&EZ0b6{HnnrtO|S4}Mk9 z;Nk>2?@h%h`Bh7nrn?~x24$hT5erfoONj+<)U$rULUltZYo9)cSg$cd&Ew~Ael!en z1Vu|$FC)$ov3}6w=iO;KfM_%|JWa>)X5S;)jsuALlrU48Zjb*GL8K~3Y-sSrJG0@A8tVhr*R6^zC~laMidqn&VZLGV2Z?oGanW$ z?ap9XvSYeR7iHh21MH1r6rh+=oiV1gnuX^g4;cOOkk%5|x8SxIkr~)L*d5q-uitgS zvc89Q#`A<3xwgqIoF|M9@$$9=&Yztfwr49pWv(R#s^F}5S$YGtXJt}vieO#cIQDn1*AMkS6-q! zLJL{=ZA56y(3_0aBe00j2=9A$77?2E&V7tP!J$ifyhakv(V2pdH;m4<6R8;@Sl3A7 zULD)14n(pFR0P&XGJbduUrl>HQnuX+!3HYPS?~w*0O5EP<~g@>e^n~# zlouxlz2%_>#Pr37M%jw-*fCg*#fNE5r6Z+bQUbJYt8CSR)E5x<2;w?Ktv3;6;^F{g zh+-ZSqB^*(JhTh9xhx{&+x{+$bhuILWg)hT*OM*T%mjDVO&t~Lv(js&PQPY(?MM0FxovpyHMxdPHYy>)o1jP97P>zJK|a5 zb(v_*cjPZwkaZB)L|B-Ftu}uzRXNDfFY*QC{GNhh`!F`8?)h8#C!x&;St3zd( zY?Q)SVBT`xsh*`H7)Nx_eAadmt?RFX*1A$yutU&Qmm!z8=(bWYtco4`#$HD4fd({@ zE%thp*0Y|yLfJ%dnmeL%O8^mlS%QTkm*9=xw_fBFeU&Q%o0I8D8-d_1leZ4+9Ihn4 zuXgb!*S&eWU~PNVE=0Jky%kK|A0lW|f~gGH{+5B=C){CXe};y;qjcAE+<~-R+9&fq z_gHLxbWRpB;)BAH=AM$HFc^MTtYkiQqY%EJ4atMpVboaflVoR z2D0EHI)#oYN5ngBTRp|~auc@(+NbIMW8Pwgm2z&PfWDT1CUm4~au~pERm2KZ$*0|{ zB9?iFR!xq(>klE7ml@1y}%_y6qmL3g2*e6 zIKx~z4wX-Udh4CeV-$yOp8R0uQiY6nK7wR-sEFfs!EgUO460*Ed;aaRAS4^(Y_!kA z^ohq(k{{lsQWlc@cp$Ot%9YNHTp5E9Z-u-#246bkmD;eSoTL*~WB3?jaEI9< zl5g3*m40-Aht<$Je9Cxq?RI$%KkHWt3p+N->*^*^8d~V8)AA&>VWq4AC`v2+OW`2; zm%R78=>0AceKSg9!m+iRe=r>jYKy{L49}C~To($TDN@_o&y+2p5Us+76p((?sT3W+JIa+Z9kRidA%Ps~=eJR{(jmN| zcZjcQDwsQr9=M(IvFH{+CmHzDy-h@`Ionvxl%Q0G>z2qc26!16axF`d@CF51jtm8m z&5w&=RHI`X5~G%&G+=H`hz54vd6;)PP(qPbP%4jwF*W(X+j$f?qVz=f(@zLJtpW#C zrv&9Xgcu^d8Qi37LuE&ZT(qwaaw^M`^g{GKmqNyya%CJj`w56UBMl=#xHE>@rx$x~ Date: Tue, 6 May 2025 22:30:08 -0600 Subject: [PATCH 041/155] - a more intelligent application of EVEN - will apply only to label: PROCEDURE now, instead of all labels This way byte-aligned data tables can remain byte aligned. --- cvbasic.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 76badea..15014ef 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5736,16 +5736,25 @@ void compile_basic(void) label = label_add(name); } - if (target == CPU_9900) { - // code MUST be even aligned - most of the time this will do nothing - cpu9900_noop("even"); - } - + // first build up the label into temp label->used |= LABEL_DEFINED; strcpy(temp, LABEL_PREFIX); strcat(temp, name); - generic_label(temp); + + // we can look ahead a little - get_lex won't mess with temp[] + // and we can use it to tell if the TI port needs to output an EVEN directive get_lex(); + + if ((target == CPU_9900) && (lex == C_NAME) && (0 == strcmp(name, "PROCEDURE"))) { + // code MUST be even aligned + // this won't trigger for inline labels, but I don't think inline labels + // can become misaligned? + cpu9900_noop("even"); + } + + // now we can emit the label + // remember, we already get_lex'd + generic_label(temp); label_exists = 1; } if (lex == C_NAME) { From e7455b63150ce17e979f7096ab6f7a8005106878 Mon Sep 17 00:00:00 2001 From: visrealm Date: Wed, 7 May 2025 23:43:30 +0930 Subject: [PATCH 042/155] Fix DEFINE VRAM READ on TMS9900. (nanochess/CVBasic#27) --- cvbasic_9900_prologue.asm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 8158433..ea941f7 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -256,14 +256,14 @@ FILVRM ; Read VRAM - address in R0, CPU data at R2, count in R3 ; Inline address set to avoid needing to cache r11 LDIRMV - swpb r2 - movb r2,@VDPWADR - swpb r2 - movb r2,@VDPWADR - swpb r2 - swpb r2 + swpb r0 + movb r0,@VDPWADR + swpb r0 + movb r0,@VDPWADR + swpb r0 + swpb r0 !1 - movb @VDPDATA,*r0+ + movb @VDPDATA,*r2+ dec r3 jne -!1 b *r11 From 6b01afe2bbfa6d0c2bd5f85a59d3a7d2c0fb716a Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 7 May 2025 11:05:39 -0600 Subject: [PATCH 043/155] Correction in CHR$ --- cvbasic.c | 2 ++ cvbasic_9900_prologue.asm | 3 +++ 2 files changed, 5 insertions(+) diff --git a/cvbasic.c b/cvbasic.c index d9e8865..c31806d 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3487,7 +3487,9 @@ void compile_statement(int check_for_else) cpu9900_2op("mov", "r0", "r2"); cpu9900_1op("swpb", "r2"); } + generic_interrupt_disable(); generic_call("print_char"); + generic_interrupt_enable(); } else { type = evaluate_expression(1, TYPE_16, 0); if (target == CPU_9900) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index ea941f7..c83df34 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -431,6 +431,9 @@ print_char movb r2,@VDPWDATA inc @cursor ; track it b *r6 +print_char2 + mov r11,r6 + b @print_char ; Load sprite definitions: Sprite number in R4, CPU data in R0, count of sprites in R5 (MSB) ; Original: pointer = sprite number, temp = CPU address, a = number sprites From 710e12b48146b55aa834ccd3c403e9ecb6ddf923 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 7 May 2025 11:06:44 -0600 Subject: [PATCH 044/155] Further correction in CHR$ for TMS9900 --- cvbasic_9900_prologue.asm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index c83df34..283b482 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -416,13 +416,13 @@ print_digit ci r5,>0200 jl !6 mov r5,r2 - jne print_char + jne print_char2 !6 li r2,>30 !3 andi r5,>00ff ori r5,>0100 -print_char +print_char2 mov @cursor,r0 ; get cursor andi r0,>07ff ; enforce position - large range for two screen pages ai r0,>1800 ; add is safer than OR, and we have that option @@ -431,9 +431,9 @@ print_char movb r2,@VDPWDATA inc @cursor ; track it b *r6 -print_char2 +print_char mov r11,r6 - b @print_char + b @print_char2 ; Load sprite definitions: Sprite number in R4, CPU data in R0, count of sprites in R5 (MSB) ; Original: pointer = sprite number, temp = CPU address, a = number sprites From 63cd74d00f731f7a485ed9df4b3871f0f163f790 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 7 May 2025 11:20:42 -0600 Subject: [PATCH 045/155] Solved precedence bug when using DEF FN --- cvbasic.c | 100 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 25b3cd9..2fe0cff 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -992,6 +992,14 @@ int evaluate_expression(int cast, int to_type, int label) return type; } +/* + ** Check for macro replacement + */ +void check_for_macro(void) { + if (lex == C_NAME && macro_search(name) != NULL) + replace_macro(); +} + /* ** Expression evaluation level 0 (OR) */ @@ -1001,10 +1009,12 @@ struct node *evaluate_level_0(int *type) struct node *right; int type2; + check_for_macro(); left = evaluate_level_1(type); while (1) { if (lex == C_NAME && strcmp(name, "OR") == 0) { get_lex(); + check_for_macro(); right = evaluate_level_1(&type2); *type = mix_types(&left, *type, &right, type2); if ((*type & MAIN_TYPE) == TYPE_8) @@ -1027,10 +1037,12 @@ struct node *evaluate_level_1(int *type) struct node *right; int type2; + check_for_macro(); left = evaluate_level_2(type); while (1) { if (lex == C_NAME && strcmp(name, "XOR") == 0) { get_lex(); + check_for_macro(); right = evaluate_level_2(&type2); *type = mix_types(&left, *type, &right, type2); if ((*type & MAIN_TYPE) == TYPE_8) @@ -1053,10 +1065,12 @@ struct node *evaluate_level_2(int *type) struct node *right; int type2; + check_for_macro(); left = evaluate_level_3(type); while (1) { if (lex == C_NAME && strcmp(name, "AND") == 0) { get_lex(); + check_for_macro(); right = evaluate_level_3(&type2); *type = mix_types(&left, *type, &right, type2); if ((*type & MAIN_TYPE) == TYPE_8) @@ -1083,6 +1097,7 @@ struct node *evaluate_level_3(int *type) enum node_type operation8s; enum node_type operation16s; + check_for_macro(); left = evaluate_level_4(type); while (1) { if (lex == C_EQUAL) { @@ -1119,6 +1134,7 @@ struct node *evaluate_level_3(int *type) break; } get_lex(); + check_for_macro(); right = evaluate_level_4(&type2); *type = mix_types(&left, *type, &right, type2); if ((*type & MAIN_TYPE) == TYPE_8) @@ -1138,28 +1154,29 @@ struct node *evaluate_level_4(int *type) struct node *left; struct node *right; int type2; - + enum node_type operation8; + enum node_type operation16; + + check_for_macro(); left = evaluate_level_5(type); while (1) { if (lex == C_PLUS) { - get_lex(); - right = evaluate_level_5(&type2); - *type = mix_types(&left, *type, &right, type2); - if ((*type & MAIN_TYPE) == TYPE_8) - left = node_create(N_PLUS8, 0, left, right); - else - left = node_create(N_PLUS16, 0, left, right); + operation8 = N_PLUS8; + operation16 = N_PLUS16; } else if (lex == C_MINUS) { - get_lex(); - right = evaluate_level_5(&type2); - *type = mix_types(&left, *type, &right, type2); - if ((*type & MAIN_TYPE) == TYPE_8) - left = node_create(N_MINUS8, 0, left, right); - else - left = node_create(N_MINUS16, 0, left, right); + operation8 = N_MINUS8; + operation16 = N_MINUS16; } else { break; } + get_lex(); + check_for_macro(); + right = evaluate_level_5(&type2); + *type = mix_types(&left, *type, &right, type2); + if ((*type & MAIN_TYPE) == TYPE_8) + left = node_create(operation8, 0, left, right); + else + left = node_create(operation16, 0, left, right); } return left; } @@ -1172,33 +1189,32 @@ struct node *evaluate_level_5(int *type) struct node *left; struct node *right; int type2; - + enum node_type operation16; + enum node_type operation16s; + + check_for_macro(); left = evaluate_level_6(type); while (1) { if (lex == C_MUL) { - get_lex(); - right = evaluate_level_6(&type2); - *type = extend_types(&left, *type, &right, type2); - left = node_create(N_MUL16, 0, left, right); + operation16 = N_MUL16; + operation16s = N_MUL16; } else if (lex == C_DIV) { - get_lex(); - right = evaluate_level_6(&type2); - *type = extend_types(&left, *type, &right, type2); - if (*type & TYPE_SIGNED) - left = node_create(N_DIV16S, 0, left, right); - else - left = node_create(N_DIV16, 0, left, right); + operation16 = N_DIV16; + operation16s = N_DIV16S; } else if (lex == C_MOD) { - get_lex(); - right = evaluate_level_6(&type2); - *type = extend_types(&left, *type, &right, type2); - if (*type & TYPE_SIGNED) - left = node_create(N_MOD16S, 0, left, right); - else - left = node_create(N_MOD16, 0, left, right); + operation16 = N_MOD16; + operation16s = N_MOD16S; } else { break; } + get_lex(); + check_for_macro(); + right = evaluate_level_6(&type2); + *type = extend_types(&left, *type, &right, type2); + if (*type & TYPE_SIGNED) + left = node_create(operation16s, 0, left, right); + else + left = node_create(operation16, 0, left, right); } return left; } @@ -1212,7 +1228,7 @@ struct node *evaluate_level_6(int *type) if (lex == C_MINUS) { get_lex(); - + check_for_macro(); left = evaluate_level_6(type); if ((*type & MAIN_TYPE) == TYPE_8) left = node_create(N_NEG8, 0, left, NULL); @@ -1220,13 +1236,14 @@ struct node *evaluate_level_6(int *type) left = node_create(N_NEG16, 0, left, NULL); } else if (lex == C_NAME && strcmp(name, "NOT") == 0) { get_lex(); - + check_for_macro(); left = evaluate_level_6(type); if ((*type & MAIN_TYPE) == TYPE_8) left = node_create(N_NOT8, 0, left, NULL); else left = node_create(N_NOT16, 0, left, NULL); } else { + check_for_macro(); left = evaluate_level_7(type); } return left; @@ -1672,11 +1689,6 @@ struct node *evaluate_level_7(int *type) tree = node_create(N_DIV16, 0, tree, node_create(N_NUM16, 2, NULL, NULL)); return tree; } - if (macro_search(name) != NULL) { /* Function (macro) */ - if (replace_macro()) - return node_create(N_NUM8, 0, NULL, NULL); - return evaluate_level_0(type); - } if (lex_sneak_peek() == '(') { /* Indexed access */ int type2; struct node *addr; @@ -5747,10 +5759,10 @@ void compile_basic(void) // and we can use it to tell if the TI port needs to output an EVEN directive get_lex(); - if ((target == CPU_9900) && (lex == C_NAME) && (0 == strcmp(name, "PROCEDURE"))) { + if (target == CPU_9900 && lex == C_NAME && strcmp(name, "PROCEDURE") == 0) { // code MUST be even aligned - // this won't trigger for inline labels, but I don't think inline labels - // can become misaligned? + // this won't trigger for inline labels, but I don't + // think inline labels can become misaligned? cpu9900_noop("even"); } From 1534bff376cae7bc96dcd968048302ff69ca1113 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 7 May 2025 11:46:41 -0600 Subject: [PATCH 046/155] Simplified controller compilation routine --- cvbasic.c | 173 ++++++++++++++++------------------------------------- manual.txt | 3 + 2 files changed, 56 insertions(+), 120 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 2fe0cff..9b543b7 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -996,7 +996,7 @@ int evaluate_expression(int cast, int to_type, int label) ** Check for macro replacement */ void check_for_macro(void) { - if (lex == C_NAME && macro_search(name) != NULL) + if (lex == C_NAME && macro_search(name) != NULL) /* Function (macro) */ replace_macro(); } @@ -1367,142 +1367,72 @@ struct node *evaluate_level_7(int *type) *type = TYPE_16 | TYPE_SIGNED; return tree; } - if (strcmp(name, "CONT") == 0) { + if (strcmp(name, "CONT") == 0 || strcmp(name, "CONT1") == 0 || strcmp(name, "CONT2") == 0) { + struct node *tree = NULL; + int cont; + + if (strcmp(name, "CONT1") == 0) + cont = 1; + else if (strcmp(name, "CONT2") == 0) + cont = 2; + else + cont = 0; get_lex(); if (lex == C_PERIOD) { get_lex(); + if (strcmp(name, "KEY") == 0) { + if (cont == 1) { + tree = node_create(N_KEY1, 0, NULL, NULL); + } else if (cont == 2) { + tree = node_create(N_KEY2, 0, NULL, NULL); + } else { + tree = node_create(N_KEY1, 0, NULL, NULL); + tree = node_create(N_AND8, 0, tree, node_create(N_KEY2, 0, NULL, NULL)); + } + } else { + if (cont == 1) { + tree = node_create(N_JOY1, 0, NULL, NULL); + } else if (cont == 2) { + tree = node_create(N_JOY2, 0, NULL, NULL); + } else { + tree = node_create(N_JOY1, 0, NULL, NULL); + tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); + } + } if (lex != C_NAME) { - tree = node_create(N_JOY1, 0, NULL, NULL); emit_error("CONT syntax error"); } else if (strcmp(name, "UP") == 0) { get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 1, NULL, NULL)); } else if (strcmp(name, "RIGHT") == 0) { get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 2, NULL, NULL)); } else if (strcmp(name, "DOWN") == 0) { get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 4, NULL, NULL)); } else if (strcmp(name, "LEFT") == 0) { get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 8, NULL, NULL)); } else if (strcmp(name, "BUTTON") == 0) { get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x40, NULL, NULL)); } else if (strcmp(name, "BUTTON2") == 0) { get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x80, NULL, NULL)); } else if (strcmp(name, "KEY") == 0) { get_lex(); - tree = node_create(N_KEY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_KEY2, 0, NULL, NULL)); } else { - tree = node_create(N_JOY1, 0, NULL, NULL); emit_error("Wrong field for CONT"); } } else { - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); - } - *type = TYPE_8; - return tree; - } - if (strcmp(name, "CONT1") == 0) { - get_lex(); - if (lex == C_PERIOD) { - get_lex(); - if (lex != C_NAME) { - tree = node_create(N_JOY1, 0, NULL, NULL); - emit_error("CONT1 syntax error"); - } else if (strcmp(name, "UP") == 0) { - get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 1, NULL, NULL)); - } else if (strcmp(name, "RIGHT") == 0) { - get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 2, NULL, NULL)); - } else if (strcmp(name, "DOWN") == 0) { - get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 4, NULL, NULL)); - } else if (strcmp(name, "LEFT") == 0) { - get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 8, NULL, NULL)); - } else if (strcmp(name, "BUTTON") == 0) { - get_lex(); + if (cont == 1) { tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x40, NULL, NULL)); - } else if (strcmp(name, "BUTTON2") == 0) { - get_lex(); - tree = node_create(N_JOY1, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x80, NULL, NULL)); - } else if (strcmp(name, "KEY") == 0) { - get_lex(); - tree = node_create(N_KEY1, 0, NULL, NULL); - } else { - emit_error("Wrong field for CONT1"); - tree = node_create(N_JOY1, 0, NULL, NULL); - } - } else { - tree = node_create(N_JOY1, 0, NULL, NULL); - } - *type = TYPE_8; - return tree; - } - if (strcmp(name, "CONT2") == 0) { - get_lex(); - if (lex == C_PERIOD) { - get_lex(); - if (lex != C_NAME) { - emit_error("CONT2 syntax error"); + } else if (cont == 2) { tree = node_create(N_JOY2, 0, NULL, NULL); - } else if (strcmp(name, "UP") == 0) { - get_lex(); - tree = node_create(N_JOY2, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 1, NULL, NULL)); - } else if (strcmp(name, "RIGHT") == 0) { - get_lex(); - tree = node_create(N_JOY2, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 2, NULL, NULL)); - } else if (strcmp(name, "DOWN") == 0) { - get_lex(); - tree = node_create(N_JOY2, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 4, NULL, NULL)); - } else if (strcmp(name, "LEFT") == 0) { - get_lex(); - tree = node_create(N_JOY2, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 8, NULL, NULL)); - } else if (strcmp(name, "BUTTON") == 0) { - get_lex(); - tree = node_create(N_JOY2, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x40, NULL, NULL)); - } else if (strcmp(name, "BUTTON2") == 0) { - get_lex(); - tree = node_create(N_JOY2, 0, NULL, NULL); - tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x80, NULL, NULL)); - } else if (strcmp(name, "KEY") == 0) { - get_lex(); - tree = node_create(N_KEY2, 0, NULL, NULL); } else { - emit_error("Wrong field for CONT2"); - tree = node_create(N_JOY2, 0, NULL, NULL); + tree = node_create(N_JOY1, 0, NULL, NULL); + tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); } - } else { - tree = node_create(N_JOY2, 0, NULL, NULL); } *type = TYPE_8; return tree; @@ -4343,7 +4273,7 @@ void compile_statement(int check_for_else) fprintf(output, "%s\n", temp); } else if (target == CPU_9900) { sprintf(temp, CONST_PREFIX "%s\tequ >%04x", assigned, c->value); - cpu9900_label(temp); // Hack + cpu9900_label(temp); /* Hack */ } node_delete(tree); tree = NULL; @@ -5500,7 +5430,7 @@ void compile_statement(int check_for_else) if (lex != C_NUM) { emit_error("Bad syntax for BANK ROM"); } else if (value != 128 && value != 256 && value != 512 && value != 1024) { - // TODO: TI can do 2MB as it stands, and 32MB with the scheme. But leaving at 1MB for now. + /* TODO: TI can do 2MB as it stands, and 32MB with the scheme. But leaving at 1MB for now. */ emit_error("BANK ROM not 128, 256, 512 or 1024"); get_lex(); } else if (bank_switching != 0) { @@ -5533,8 +5463,8 @@ void compile_statement(int check_for_else) emit_error("Using BANK SELECT without BANK ROM"); } else { if (machine == TI994A) { - // the TI needs to use 8k banks, so our masks are different - c+=2; // reserving 3 banks (0,1,2) for 'fixed' space + /* the TI needs to use 8k banks, so our masks are different */ + c += 2; /* reserving 3 banks (0,1,2) for 'fixed' space */ if (bank_rom_size == 128) c &= 0x0f; @@ -5545,7 +5475,7 @@ void compile_statement(int check_for_else) else c &= 0x7f; - c = 0x6000+(c*2); // ROM address to poke + c = 0x6000+(c*2); /* ROM address to poke */ sprintf(temp, "@>%x", c); cpu9900_1op("clr", temp); } else { @@ -5599,8 +5529,8 @@ void compile_statement(int check_for_else) } else { d = c; if (machine == TI994A) { - // the TI needs to use 8k banks, so our masks are different - c+=2; // reserving 3 banks (0,1,2) for 'fixed' space + /* the TI needs to use 8k banks, so our masks are different */ + c += 2; /* reserving 3 banks (0,1,2) for 'fixed' space */ if (bank_rom_size == 128) c &= 0x0f; @@ -5619,7 +5549,7 @@ void compile_statement(int check_for_else) if (machine == COLECOVISION || machine == COLECOVISION_SGM) c--; if (machine == TI994A) - c+=2; // reserving 3 banks (0,1,2) for 'fixed' space + c+=2; /* reserving 3 banks (0,1,2) for 'fixed' space */ if (bank_rom_size == 128) c &= 0x07; else if (bank_rom_size == 256) @@ -5750,24 +5680,27 @@ void compile_basic(void) label = label_add(name); } - // first build up the label into temp + /* first build up the label into temp */ label->used |= LABEL_DEFINED; strcpy(temp, LABEL_PREFIX); strcat(temp, name); - // we can look ahead a little - get_lex won't mess with temp[] - // and we can use it to tell if the TI port needs to output an EVEN directive + /* + ** We can look ahead a little - get_lex won't mess with temp[] + ** and we can use it to tell if the TI port needs to output an EVEN directive. + */ get_lex(); if (target == CPU_9900 && lex == C_NAME && strcmp(name, "PROCEDURE") == 0) { - // code MUST be even aligned - // this won't trigger for inline labels, but I don't - // think inline labels can become misaligned? + /* + ** code MUST be even aligned + ** this won't trigger for inline labels, but I don't + ** think inline labels can become misaligned? + */ cpu9900_noop("even"); } - // now we can emit the label - // remember, we already get_lex'd + /* Now we can emit the label. Remember, we already get_lex'd */ generic_label(temp); label_exists = 1; } diff --git a/manual.txt b/manual.txt index ae54293..30a87ad 100644 --- a/manual.txt +++ b/manual.txt @@ -22,6 +22,9 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version +v0.8.1 May/07/2025 o Solved bug in DEF FN precedence inside expressions. + o Corrected bug in CHR$ and DEFINE VRAM READ for TI-99/4A. + v0.8.0 Apr/26/2025 o Added support for Sega Master System using --sms o Added support for VDP.STATUS (for reading VDP status) o Added SELECT CASE / END SELECT From bbe2ec99c4cca5aa031c3394de90a43d3302d6e2 Mon Sep 17 00:00:00 2001 From: "Stefan A. Haubenthal" Date: Thu, 29 May 2025 20:00:02 +0200 Subject: [PATCH 047/155] Fixed makefile --- LICENSE.txt | 0 Makefile | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt old mode 100755 new mode 100644 diff --git a/Makefile b/Makefile index 8556dc0..d26333b 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ # CFLAGS = -O -build: cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o - @$(CC) cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o -o cvbasic +cvbasic: cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o + @$(CC) cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o -o $@ check: build @./cvbasic examples/viboritas.bas /tmp/viboritas.asm From 4340f7c671229c50375562fd89928e62aca70ce6 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 5 Jun 2025 13:05:02 -0600 Subject: [PATCH 048/155] Added support for Konami mapper in MSX target --- README.md | 2 +- cpu6502.c | 1 + cpu9900.c | 9 +++-- cpuz80.c | 3 +- cvbasic.c | 82 ++++++++++++++++++++++++++++++-------------- cvbasic.h | 17 ++++----- cvbasic_prologue.asm | 21 ++++++++++++ driver.c | 3 +- manual.txt | 7 ++-- 9 files changed, 103 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 4e8a73d..f64b139 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Using CVBasic to compile a NABU PC program: cvbasic --nabu -cpm game.bas game.asm gasm80 game.asm -o game.com -The .npz file is directlty usable by [MAME NABU port](https://github.com/ontheslab/nabu-mame-builds/releases) (put it in the nabu directory). The 000001.nabu name is important or it doesn't work. I've used the script _boot-built-in-adapter-local.sh_ +The .npz file is directly usable by [MAME NABU port](https://github.com/ontheslab/nabu-mame-builds/releases) (put it in the nabu directory). The 000001.nabu name is important or it doesn't work. I've used the script _boot-built-in-adapter-local.sh_ I don't have tested the COM files for NABU CP/M yet. diff --git a/cpu6502.c b/cpu6502.c index 1c44cbf..9ed6b8e 100644 --- a/cpu6502.c +++ b/cpu6502.c @@ -12,6 +12,7 @@ #include #include "cvbasic.h" #include "node.h" +#include "cpu6502.h" static char temp2[MAX_LINE_SIZE]; diff --git a/cpu9900.c b/cpu9900.c index 22515f8..8a8d262 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -12,6 +12,7 @@ #include #include "cvbasic.h" #include "node.h" +#include "cpu9900.h" /* ** Conventions of register usage: @@ -46,7 +47,11 @@ static char op1[128], op2[128], op3[128], op4[128]; static char s1[128], s2[128], s3[128], s4[128], s5[128], s6[128], s7[128], s8[128]; static void cpu9900_emit_line(void); +static void nomatch(char *); static int getargument(char *src, char *dest, int start); +static int skipcomma(char *src, int start); +static void parseline(char *buf, char *op, char *s1, char *s2); +static int loadsr0(char *op, char *s1, char *s2); // set to a unique string that will never match void nomatch(char *src) @@ -76,7 +81,7 @@ int getargument(char *src, char *dest, int start) *dest = '\0'; - return src - p; + return (int) (src - p); } /* @@ -91,7 +96,7 @@ int skipcomma(char *src, int start) ++src; if (*src == ',') ++src; /* skip past */ - return src - p; + return (int) (src - p); } /* diff --git a/cpuz80.c b/cpuz80.c index ada172a..d2f935f 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -12,6 +12,7 @@ #include #include "cvbasic.h" #include "node.h" +#include "cpuz80.h" static char z80_line[MAX_LINE_SIZE]; @@ -27,8 +28,6 @@ static void z80_emit_line(void); void z80_emit_line(void) { - int c; - int d; /* ** Optimize the following cases: diff --git a/cvbasic.c b/cvbasic.c index 9b543b7..2b25c7e 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -32,7 +32,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.8.0 Apr/26/2025" +#define VERSION "v0.8.1 Jun/05/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -57,7 +57,7 @@ struct console consoles[TOTAL_TARGETS] = { {"sg1000", "", "Sega SG-1000/SC-3000 (1K RAM)", "Sega SG-1000/SC-3000", 0xc000, 0xc400, 0x0400, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, - {"msx", "-ram16", "MSX (8K RAM), use -ram16 for 16K of RAM", + {"msx", "-ram16", "MSX (8K RAM), use -ram16 for 16K of RAM,\n use -konami for Konami mapper instead of ASCII16", "MSX", 0xe000, 0xf380, 0x1380, 0x98, 0x98, 0, 1, CPU_Z80}, {"sgm", "", "Colecovision with Opcode's Super Game Module", @@ -97,6 +97,9 @@ struct console consoles[TOTAL_TARGETS] = { {"sms", "", "Sega Master System (8K RAM)", "Sega Master System", 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, +/* {"nes", "", "NES/Famicom (2K RAM)", + "NES/Famicom", + 0x0000, 0x01ff, 0x0800, 0, 0, 0, 1, CPU_6502},*/ }; static int err_code; @@ -110,6 +113,7 @@ static int compression_used; static int bank_switching; static int bank_rom_size; static int bank_current; +static int bank_konami; static char current_file[MAX_LINE_SIZE]; static int current_line; @@ -198,6 +202,7 @@ struct node *process_usr(int); int optimized; +void check_for_macro(void); struct node *evaluate_level_0(int *); struct node *evaluate_level_1(int *); struct node *evaluate_level_2(int *); @@ -259,6 +264,7 @@ void accumulated_push(enum lexical_component, int, char *); void compile_assignment(int); void compile_statement(int); void compile_basic(void); +int process_variables(void); /* ** Emit an error @@ -302,7 +308,7 @@ void bank_finish(void) fprintf(output, "BANK_%d_FREE:\tEQU $bfff-$\n", bank_current); fprintf(output, "\tTIMES $bfff-$ DB $ff\n"); } - fprintf(output, "\tDB $%02x\n", bank_current); + fprintf(output, "\tDB $%02x\n", bank_konami ? bank_current * 2 : bank_current); } else if (machine == TI994A) { if (bank_current == 0) { // bank 0 is copied to RAM so is 24k @@ -1297,8 +1303,8 @@ struct node *evaluate_level_7(int *type) } get_lex(); *type = TYPE_8; - if ((machine == CREATIVISION)||(machine == TI994A)) - emit_warning("Ignoring INP (not supported in Creativision or TI994A)"); + if (machine == CREATIVISION || machine == TI994A || machine == NES) + emit_warning("Ignoring INP (not supported in this platform)"); return tree; } if (strcmp(name, "PEEK") == 0) { @@ -1508,6 +1514,7 @@ struct node *evaluate_level_7(int *type) if (strcmp(name, "VARPTR") == 0) { /* Access to variable/array/label address */ *type = TYPE_16; get_lex(); + check_for_macro(); if (lex != C_NAME) { emit_error("missing variable name for VARPTR"); return node_create(N_NUM16, 0, NULL, NULL); @@ -2554,7 +2561,6 @@ void compile_statement(int check_for_else) emit_error("bad nested LOOP"); } } else if (strcmp(name, "SELECT") == 0) { - int label_loop; int label_exit; int type; struct loop *new_loop; @@ -2633,6 +2639,7 @@ void compile_statement(int check_for_else) } else { min = tree->value; } + max = min; node_delete(tree); if (lex == C_NAME && strcmp(name, "TO") == 0) { get_lex(); @@ -2651,8 +2658,6 @@ void compile_statement(int check_for_else) max = tree->value; } node_delete(tree); - } else { - max = min; } if (loops->var[0] == (TYPE_8 | TYPE_SIGNED)) { min ^= 0x80; @@ -2833,7 +2838,7 @@ void compile_statement(int check_for_else) generic_call("cls"); } else if (strcmp(name, "WAIT") == 0) { get_lex(); - if (machine == SORD || machine == CREATIVISION || machine == EINSTEIN || machine == TI994A) + if (machine == SORD || machine == CREATIVISION || machine == NES || machine == EINSTEIN || machine == TI994A) generic_call("wait"); else cpuz80_noop("HALT"); @@ -2958,6 +2963,7 @@ void compile_statement(int check_for_else) int type2; get_lex(); + check_for_macro(); if (lex != C_NAME) { emit_error("missing variable name for VARPTR"); } else { @@ -3162,6 +3168,7 @@ void compile_statement(int check_for_else) struct node *tree; get_lex(); + label2 = 0; start = 1; cursor_value = 0; cursor_pos = 0; @@ -4664,11 +4671,9 @@ void compile_statement(int check_for_else) unsigned int notes; int note; int c; - int label; generic_dump(); get_lex(); - label = 0; notes = 0; arg = 0; while (1) { @@ -5437,7 +5442,7 @@ void compile_statement(int check_for_else) emit_error("BANK ROM used twice"); get_lex(); } else { - if (machine == SVI || machine == SORD || machine == MEMOTECH || machine == CREATIVISION || machine == EINSTEIN || machine == PV2000) { + if (machine == SVI || machine == SORD || machine == MEMOTECH || machine == CREATIVISION || machine == NES || machine == EINSTEIN || machine == PV2000) { emit_error("Bank-switching not supported with current platform"); } else { bank_switching = 1; @@ -5494,9 +5499,19 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "($fffe)", "A"); } else if (machine == MSX) { - sprintf(temp, "%d", c & 0x3f); - cpuz80_2op("LD", "A", temp); - cpuz80_2op("LD", "($7000)", "A"); + if (bank_konami) { + sprintf(temp, "%d", (c & 0x3f) * 2); + cpuz80_noop("DI"); + cpuz80_2op("LD", "A", temp); + cpuz80_2op("LD", "($8000)", "A"); + cpuz80_1op("INC", "A"); + cpuz80_2op("LD", "($a000)", "A"); + cpuz80_noop("EI"); + } else { + sprintf(temp, "%d", c & 0x3f); + cpuz80_2op("LD", "A", temp); + cpuz80_2op("LD", "($7000)", "A"); + } } else { if (bank_rom_size == 128) c |= 0xfff8; @@ -5583,6 +5598,7 @@ void compile_statement(int check_for_else) get_lex(); if (lex != C_NUM) { emit_error("Not a constant in VDP"); + vdp_reg = 0; } else { vdp_reg = value; get_lex(); @@ -5791,8 +5807,7 @@ int process_variables(void) int size; int address; - if (machine == CREATIVISION || machine == TI994A) - address = consoles[machine].base_ram; + address = consoles[machine].base_ram; /* Only Creativision, NES and TI994A */ bytes_used = 0; for (c = 0; c < HASH_PRIME; c++) { label = label_hash[c]; @@ -5912,10 +5927,8 @@ int process_variables(void) */ int main(int argc, char *argv[]) { - struct label *label; FILE *prologue; int c; - int size; char *p; char *p1; int bytes_used; @@ -5940,11 +5953,11 @@ int main(int argc, char *argv[]) machine = COLECOVISION; while (machine < TOTAL_TARGETS) { if (machine == COLECOVISION) - fprintf(stderr, " cvbasic [-DMYCONST=123] input.bas output.asm [library_path]\n"); + fprintf(stderr, " cvbasic [-DCONST=5] input.bas output.asm [library_path]\n"); else - fprintf(stderr, " cvbasic --%s [-DMYCONST=123] input.bas output.asm [library_path]\n", consoles[machine].name); + fprintf(stderr, " cvbasic --%s input.bas output.asm [library_path]\n", consoles[machine].name); if (consoles[machine].options[0]) - fprintf(stderr, " cvbasic --%s %s [-DMYCONST=123] input.bas output.asm [library_path]\n", consoles[machine].name, consoles[machine].options); + fprintf(stderr, " cvbasic --%s %s input.bas output.asm [library_path]\n", consoles[machine].name, consoles[machine].options); fprintf(stderr, " %s\n", consoles[machine].description); machine++; @@ -6001,6 +6014,7 @@ int main(int argc, char *argv[]) } else { pencil = 0; } + bytes_used = 0; /* ** Extra options. @@ -6017,6 +6031,18 @@ int main(int argc, char *argv[]) exit(2); } } + bank_konami = 0; + if (argv[c][0] == '-' && tolower(argv[c][1]) == 'k' && tolower(argv[c][2] == 'o') && + tolower(argv[c][3] == 'n') && tolower(argv[c][4]) == 'a' && tolower(argv[c][5]) == 'm' && tolower(argv[c][6]) == 'i' && + argv[c][7] == '\0') { + c++; + if (machine == MSX) { + bank_konami = 1; + } else { + fprintf(stderr, "-konami option only applies to MSX.\n"); + exit(2); + } + } cpm_option = 0; if (machine == EINSTEIN) cpm_option = 1; /* Forced */ @@ -6076,7 +6102,7 @@ int main(int argc, char *argv[]) } } if (d == NULL) { - fprintf(stderr, "%s missing assignment. Syntax: -DMYCONSTANT=123 -D#MYBIGCONSTANT=12345\n", argv[c]); + fprintf(stderr, "%s missing assignment. Syntax: -DCONST=123 -D#BIGCONST=12345\n", argv[c]); exit(2); } c++; @@ -6159,6 +6185,8 @@ int main(int argc, char *argv[]) (machine == COLECOVISION || machine == COLECOVISION_SGM) ? 1 : 0); fprintf(output, "SG1000:\tequ %d\n", (machine == SG1000) ? 1 : 0); fprintf(output, "MSX:\tequ %d\n", (machine == MSX) ? 1 : 0); + if (machine == MSX) + fprintf(output, "KONAMI:\tequ %d\n", bank_konami); fprintf(output, "SGM:\tequ %d\n", (machine == COLECOVISION_SGM) ? 1 : 0); fprintf(output, "SVI:\tequ %d\n", (machine == SVI) ? 1 : 0); fprintf(output, "SORD:\tequ %d\n", (machine == SORD) ? 1 : 0); @@ -6202,8 +6230,10 @@ int main(int argc, char *argv[]) } } strcpy(path, library_path); - if (target == CPU_6502) + if (target == CPU_6502 && machine == CREATIVISION) strcat(path, "cvbasic_6502_prologue.asm"); + else if (target == CPU_6502 && machine == NES) + strcat(path, "cvbasic_nes_prologue.asm"); else if (target == CPU_9900) strcat(path, "cvbasic_9900_prologue.asm"); else @@ -6262,8 +6292,10 @@ int main(int argc, char *argv[]) remove(TEMPORARY_ASSEMBLER); strcpy(path, library_path); - if (target == CPU_6502) + if (target == CPU_6502 && machine == CREATIVISION) strcat(path, "cvbasic_6502_epilogue.asm"); + else if (target == CPU_6502 && machine == NES) + strcat(path, "cvbasic_nes_epilogue.asm"); else if (target == CPU_9900) strcat(path, "cvbasic_9900_epilogue.asm"); else diff --git a/cvbasic.h b/cvbasic.h index a21a739..2a7f11a 100644 --- a/cvbasic.h +++ b/cvbasic.h @@ -33,6 +33,7 @@ enum supported_machine { TI994A, NABU, SMS, + NES, TOTAL_TARGETS }; @@ -96,16 +97,16 @@ struct label { /* ** These flags are used in labels */ -#define LABEL_USED 0x10 -#define LABEL_DEFINED 0x20 +#define LABEL_USED 0x10 +#define LABEL_DEFINED 0x20 #define LABEL_CALLED_BY_GOTO 0x40 #define LABEL_CALLED_BY_GOSUB 0x80 -#define LABEL_IS_PROCEDURE 0x100 -#define LABEL_IS_VARIABLE 0x200 -#define LABEL_IS_ARRAY 0x400 +#define LABEL_IS_PROCEDURE 0x100 +#define LABEL_IS_VARIABLE 0x200 +#define LABEL_IS_ARRAY 0x400 -#define LABEL_VAR_READ 0x0800 -#define LABEL_VAR_WRITE 0x1000 -#define LABEL_VAR_ACCESS (LABEL_VAR_READ | LABEL_VAR_WRITE) +#define LABEL_VAR_READ 0x0800 +#define LABEL_VAR_WRITE 0x1000 +#define LABEL_VAR_ACCESS (LABEL_VAR_READ | LABEL_VAR_WRITE) extern void emit_error(char *); diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 7028e23..f565934 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -2595,7 +2595,13 @@ nmi_handler: ld ($fffe),a endif if MSX + if KONAMI + ld ($8000),a + inc a + ld ($a000),a + else ld ($7000),a + endif endif endif pop de @@ -2900,7 +2906,13 @@ music_generate: ld ($fffe),a endif if MSX + if KONAMI + ld ($8000),a + inc a + ld ($a000),a + else ld ($7000),a + endif endif endif ld b,(hl) @@ -3805,8 +3817,17 @@ Z80_CTC: equ $28 ld ($fffe),a endif if MSX + if KONAMI + ld a,1 + ld ($6000),a + inc a + ld ($8000),a + inc a + ld ($a000),a + else ld a,1 ; ASCII 16K ld ($7000),a + endif endif endif if MEMOTECH+EINSTEIN+NABU diff --git a/driver.c b/driver.c index c2fbbb1..d1ebdb2 100644 --- a/driver.c +++ b/driver.c @@ -10,12 +10,11 @@ #include #include "cvbasic.h" #include "node.h" +#include "driver.h" #include "cpuz80.h" #include "cpu6502.h" #include "cpu9900.h" -static char driver_temp[MAX_LINE_SIZE]; - /* ** Dump peephole optimization */ diff --git a/manual.txt b/manual.txt index 30a87ad..f4e2947 100644 --- a/manual.txt +++ b/manual.txt @@ -22,7 +22,8 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.8.1 May/07/2025 o Solved bug in DEF FN precedence inside expressions. +v0.8.1 Jun/05/2025 o MSX: Added support for Konami mapper using -konami + o Solved bug in DEF FN precedence inside expressions. o Corrected bug in CHR$ and DEFINE VRAM READ for TI-99/4A. v0.8.0 Apr/26/2025 o Added support for Sega Master System using --sms @@ -1207,10 +1208,12 @@ Currently CVBasic handles in its own the bitmap, color and sprites tables. However, you probably will need direct access to the screen. -The screen is a 32x24 grid located at the VRAM address $1800-$1aff. It can be accessed using VPOKE (writing) and VPEEK (reading). +The screen is a 32x24 grid located at the VRAM addresses $1800-$1aff. It can be accessed using VPOKE (writing) and VPEEK (reading). See the included example viboritas.bas for examples. +For Sega Master System the screen is a 32x28 grid located at the VRAM addresses $3800-$3dff. It can be accessed using VPOKE and VPEEK. SMS uses two bytes for each pattern to display on the screen, the first byte is the pattern number, and the second byte are flags. See the SCREEN statement for further details on the flags. + >>>>>>>>>>>>>> Assembly language interfacing From c47dbdc477425e8a1646874a7f0d7b2476c3b1ad Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 5 Jun 2025 13:11:32 -0600 Subject: [PATCH 049/155] Adjusted credits --- README.md | 2 +- cvbasic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f64b139..c7f161e 100644 --- a/README.md +++ b/README.md @@ -270,4 +270,4 @@ All the games in the book will compile for **all** the platforms (exception of D ### Acknowledgments -Thanks to the following members of Atariage for contributing valuable suggestions: abeker, aotta, ARTRAG, atari2600land, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. +Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. diff --git a/cvbasic.c b/cvbasic.c index 2b25c7e..1843c9c 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5972,7 +5972,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "\n"); fprintf(stderr, " It will return a zero error code if compilation was\n"); fprintf(stderr, " successful, or non-zero otherwise.\n\n"); - fprintf(stderr, "Many thanks to Albert, abeker, aotta, artrag, atari2600land,\n"); + fprintf(stderr, "Many thanks to acadiel, Albert, abeker, aotta, artrag, atari2600land,\n"); fprintf(stderr, "carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan,\n"); fprintf(stderr, "Kamshaft, Kiwi, MADrigal, pixelboy, SiRioKD, Tarzilla,\n"); fprintf(stderr, "Tony Cruise, tursilion, visrealm, wavemotion, and youki.\n"); From 61281e479bdfd54046c191b9527534403eb7eb40 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 25 Jun 2025 22:08:47 -0600 Subject: [PATCH 050/155] Add moving_faces.bas example for Early Clock usage --- examples/moving_faces.bas | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 examples/moving_faces.bas diff --git a/examples/moving_faces.bas b/examples/moving_faces.bas new file mode 100644 index 0000000..22af1b5 --- /dev/null +++ b/examples/moving_faces.bas @@ -0,0 +1,64 @@ + ' + ' Multiple happy faces (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Jun/25/2025. + ' + + DEFINE SPRITE 0,1,happy_face + + PRINT AT 36,"Happy faces!" + + SIGNED #x + + DIM #x(4) + DIM #y(4) + + ' The horizontal movement range for sprites is from -32 to 255 + + #x(0) = -32 + #y(0) = -8 + + #x(1) = 32 + #y(1) = 64 + + #x(2) = 64 + #y(2) = 128 + + #x(3) = 96 + #y(3) = 184 + +game_loop: + FOR c = 0 tO 3 + IF #x(c) < 0 THEN + ' The early clock bit moves the sprite 32 pixels to the left. + SPRITE c, #y(c) - 1, #x(c) + 32, 0, 10 + $80 + ELSE + SPRITE c, #y(c) - 1, #x(c), 0, 10 + END IF + #x(c) = #x(c) + 1 + IF #x(c) >= 256 THEN #x(c) = -32 + NEXT c + WAIT + WAIT + GOTO game_loop + +happy_face: + BITMAP "......XXXX......" + BITMAP "....XXXXXXXX...." + BITMAP "...XXXXXXXXXX..." + BITMAP "..XXXXXXXXXXXX.." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP "XXXX..XXXX..XXXX" + BITMAP "XXXX..XXXX..XXXX" + BITMAP "XXXXXXXXXXXXXXXX" + BITMAP "XXXXXXXXXXXXXXXX" + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXX..XXXX..XXX." + BITMAP "..XXX......XXX.." + BITMAP "...XXX....XXX..." + BITMAP "....XXXXXXXX...." + BITMAP "......XXXX......" From 19015ede8dc5df9be8c2e68b247bc1a340a411a9 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 27 Jun 2025 09:44:25 +0200 Subject: [PATCH 051/155] Fixed last change --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d26333b..ebf61bf 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ CFLAGS = -O cvbasic: cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o @$(CC) cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o -o $@ -check: build - @./cvbasic examples/viboritas.bas /tmp/viboritas.asm +check: cvbasic + @./$< examples/viboritas.bas /tmp/viboritas.asm clean: @rm cvbasic cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o From 5da09ae261bb2a00d781773d252a12fa4c7b1955 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sat, 28 Jun 2025 18:03:18 +0200 Subject: [PATCH 052/155] Fixed minor typo --- cvbasic_9900_prologue.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 30d9038..619e9ed 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -606,7 +606,7 @@ rmask data >b400 ; mask for 16 bit .endif -; Set SN Frequency: R0=freqency code, R2=channel command (MSB) +; Set SN Frequency: R0=frequency code, R2=channel command (MSB) ; Original: A=least significant byte X=channel command Y=most significant byte sn76489_freq mov r0,r3 From 17ec2bf704eaf0ecf1c43c3eeb230fe3315b7893 Mon Sep 17 00:00:00 2001 From: Troy Schrapel Date: Sat, 5 Jul 2025 19:03:24 +0930 Subject: [PATCH 053/155] Fixed DEFINE COLOR PLETTER on TMS9900. Issue #33 Was writing to the wrong address. VDP Color table #1 at >2000 --- cvbasic_9900_prologue.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 619e9ed..d5a807c 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -1513,7 +1513,7 @@ define_color_unpack mov r0,r2 andi r4,>00ff ; mask off to 0-255 sla r4,3 ; char times 8 - li r0,>4000 ; base of color table + li r0,>2000 ; base of color table a r0,r4 ; set base for color then fall through ; entered from one of the above two functions From cbaaac2aba97c95150ba4c4d6956b270a85123ee Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 22 Aug 2025 09:17:53 -0600 Subject: [PATCH 054/155] TI-99/4A solved bug in DEFINE COLOR PLETTER, DEFINE CHAR PLETTER with MODE 0, SELECT CASE with 8-bit variable, and bad optimization of 8-bit variable read to 16-bit --- README.md | 12 ++++--- cpu9900.c | 70 +++++++++++++++++++++++++++++++++++++- cpuz80.c | 1 + cvbasic.c | 12 ++++--- cvbasic_9900_prologue.asm | 9 +++-- cvbasic_prologue.asm | 30 ++++++++-------- driver.c | 59 +++++++++++++++++++++++++++----- examples/hello.bas | 15 ++++++++ gasm80 | Bin 87667 -> 0 bytes node.c | 11 ++++-- 10 files changed, 177 insertions(+), 42 deletions(-) create mode 100644 examples/hello.bas delete mode 100755 gasm80 diff --git a/README.md b/README.md index c7f161e..672c170 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ Using CVBasic to compile a Spectravideo SVI-318/328 program: cvbasic --svi game.bas game.asm gasm80 game.asm -o game.rom -Using CVBasic to compile a Sord M5 program: +Using CVBasic to compile a Sord M5 program (16K ROM): cvbasic --sord game.bas game.asm gasm80 game.asm -o game.rom @@ -136,7 +136,9 @@ Using CVBasic to compile a VTech Creativision (Dick Smith's Wizzard / Vtech Lase cvbasic --creativision game.bas game.asm gasm80 game.asm -o game.rom -You can use the -rom16 option to generate a 16K ROM instead of a 32K ROM, and it is provided utility/switch.c to switch the two 8K banks in a 16K ROM and run it with MAME, as MAME doesn't yet support 32K ROM. For 32K ROM you can use the Creativision emulator. +You can use the -rom16 option to generate a 16K ROM instead of a 32K ROM, and it is provided utility/switch.c to switch the two 8K banks in a 16K ROM and run it with MAME, as MAME doesn't yet support 32K ROM. For 32K ROM you can use the [Creativision emulator](https://sourceforge.net/projects/creativisionemulator/), and the command line is: + + creativision -g -b ..\BIOS\BIOSCV.ROM -r game.rom Using CVBasic to compile a Hanimex/Soundic Pencil II program (almost exactly like a Colecovision, but with 2K of RAM and different cartridge header): @@ -148,7 +150,7 @@ Using CVBasic to compile a Tatung Einstein program: cvbasic --einstein game.bas game.asm gasm80 game.asm -o game.com -Using CVBasic to compile a Casio PV-2000 program: +Using CVBasic to compile a Casio PV-2000 program (16k ROM): cvbasic --pv2000 game.bas game.asm gasm80 game.asm -o game.rom @@ -172,7 +174,7 @@ Using CVBasic to compile a NABU PC program: cvbasic --nabu -cpm game.bas game.asm gasm80 game.asm -o game.com -The .npz file is directly usable by [MAME NABU port](https://github.com/ontheslab/nabu-mame-builds/releases) (put it in the nabu directory). The 000001.nabu name is important or it doesn't work. I've used the script _boot-built-in-adapter-local.sh_ +The .npz file is directly usable by [MAME NABU port v1.0.2](https://github.com/ontheslab/nabu-mame-builds/releases) (put it in the nabu directory). The 000001.nabu name is important or it doesn't work. I've used the script _boot-built-in-adapter-local.sh_ I don't have tested the COM files for NABU CP/M yet. @@ -216,7 +218,7 @@ The Creativision can only use binaries up to 32 kb, the joysticks are controller The TI-99/4A can only generate non-banked binaries up to 24 kb. When banking, the fixed space is 24k and pages are 8k. Both joysticks are supported with a single button. The second button is simulated on the keyboard with control for player 1 and fctn for player 2. CONT1.KEY will also return uppercase ASCII characters from the keyboard in addition to the stock 0-9, #, * for compatibility with Coleco programs. No keypad is implemented for controller 2 - only the joystick. The program supports FCTN-= (Alt-= on PC emulation) to reset. -The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1, and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. +The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1 (<||| is the primary button and |||> is the secondary button), and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) diff --git a/cpu9900.c b/cpu9900.c index 8a8d262..6b5f859 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -298,7 +298,7 @@ void cpu9900_emit_line(void) // first check - labels cancels all bets. We can try to get smarter with the registers like // the other ports later... if (buf[0] > ' ') { - strcpy(last_r0_load,""); + strcpy(last_r0_load, ""); } else { // is r0 the target? if (strcmp(op1, "mov") == 0 && strcmp(s2, "r0") == 0) { @@ -1063,6 +1063,74 @@ void cpu9900_node_generate(struct node *node, int decision) break; } } + if (node->type == N_EQUAL16) { + if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { + int c; + + if (node->left->type == N_NUM16) + explore = node->left; + else + explore = node->right; + if (node->left != explore) + cpu9900_node_generate(node->left, 0); + else + cpu9900_node_generate(node->right, 0); + c = explore->value; + sprintf(temp, "%d", c); + cpu9900_2op("ci", "r0", temp); + if (decision) { + optimized = 1; + sprintf(temp, "@" INTERNAL_PREFIX "%d", decision); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); + cpu9900_1op("jeq", temp + 100); + cpu9900_1op("b", temp); + cpu9900_label(temp + 100); + } else { + sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + cpu9900_1op("jeq", temp); + cpu9900_1op("clr", "r0"); + cpu9900_1op("jmp", "$+4"); + cpu9900_label(temp); + cpu9900_1op("seto", "r0"); + cpu9900_empty(); + } + break; + } + } + if (node->type == N_NOTEQUAL16) { + if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { + int c; + + if (node->left->type == N_NUM16) + explore = node->left; + else + explore = node->right; + if (node->left != explore) + cpu9900_node_generate(node->left, 0); + else + cpu9900_node_generate(node->right, 0); + c = explore->value; + sprintf(temp, "%d", c); + cpu9900_2op("ci", "r0", temp); + if (decision) { + optimized = 1; + sprintf(temp, "@" INTERNAL_PREFIX "%d", decision); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); + cpu9900_1op("jne", temp + 100); + cpu9900_1op("b", temp); + cpu9900_label(temp + 100); + } else { + sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + cpu9900_1op("jne", temp); + cpu9900_1op("clr", "r0"); + cpu9900_1op("jmp", "$+4"); + cpu9900_label(temp); + cpu9900_1op("seto", "r0"); + cpu9900_empty(); + } + break; + } + } if (node->type == N_MINUS16) { if (node->right->type == N_NUM16) explore = node->right; diff --git a/cpuz80.c b/cpuz80.c index d2f935f..ba681ce 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -1555,6 +1555,7 @@ void cpuz80_node_generate(struct node *node, int decision) cpuz80_node_generate(node->left, 0); if ((node->right->regs & REG_DE) == 0) { cpuz80_2op("EX", "DE", "HL"); + cpuz80_node_generate(node->right, 0); } else { cpuz80_1op("PUSH", "HL"); cpuz80_node_generate(node->right, 0); diff --git a/cvbasic.c b/cvbasic.c index 1843c9c..2baf2f1 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -32,7 +32,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.8.1 Jun/05/2025" +#define VERSION "v0.9.0 Jul/19/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -48,6 +48,10 @@ enum cpu_target target; /* ** Base information about each platform. + ** + ** Machine name (for command line), extra options, description, canonical name + ** base address of ram, base address of stack, available ram bytes + ** vdp port for writing, vdp port for reading, psg port, 1 it uses INT for VDP */ struct console consoles[TOTAL_TARGETS] = { /* RAM STACK Size VDP R VDP W PSG */ @@ -99,7 +103,7 @@ struct console consoles[TOTAL_TARGETS] = { 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, /* {"nes", "", "NES/Famicom (2K RAM)", "NES/Famicom", - 0x0000, 0x01ff, 0x0800, 0, 0, 0, 1, CPU_6502},*/ + 0x0000, 0x00ff, 0x0800, 0, 0, 0, 1, CPU_6502},*/ }; static int err_code; @@ -4983,7 +4987,7 @@ void compile_statement(int check_for_else) } else { if (value < 3 && (machine == MSX || machine == SVI || machine == EINSTEIN || machine == NABU)) emit_warning("using SOUND 0-3 with AY-3-8910 target"); - else if (value >= 5 && machine != MSX && machine != COLECOVISION_SGM && machine != SVI && machine != SORD && machine != MEMOTECH) + else if (value >= 5 && machine != MSX && machine != COLECOVISION_SGM && machine != SVI && machine != SORD && machine != MEMOTECH && machine != NABU) emit_warning("using SOUND 5-9 with SN76489 target"); switch (value) { case 0: @@ -5534,7 +5538,7 @@ void compile_statement(int check_for_else) tree = evaluate_level_0(&type); if (tree->type != N_NUM8 && tree->type != N_NUM16) { - emit_error("not a constant expression in BANK SELECT"); + emit_error("not a constant expression in BANK"); break; } c = tree->value; diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 619e9ed..8c3b939 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -325,7 +325,6 @@ ENASCR ; address in R8, CPU data at R9, count per row in R6 (MSB), number rows in R4 (MSB), CPU stride in R5 (MSB) (VDP stride fixed at 32) ; original: address in pointer, CPU address at temp, count per row in temp2, num rows in temp2+1, stride in YYXX CPYBLK - limi 0 mov r11,r7 ; save return srl r6,8 srl r4,8 @@ -334,13 +333,13 @@ CPYBLK mov r8,r0 ; get vdp address mov r9,r2 ; get cpu address mov r6,r3 ; get count -!2 + limi 0 bl @LDIRVM ; copy one row + limi 2 a r5,r9 ; add stride to CPU address ai r8,32 ; add 32 to VDP dec r4 ; count down rows jne -!1 ; loop till done - limi 2 b *r7 ; back to caller ; clear screen and reset cursor to >1800 @@ -1505,6 +1504,7 @@ define_char_unpack movb @mode,r0 ; get mode andi r0,>0800 ; check bitmap bit jeq unpack3 ; 3 times if yes + mov r4,r1 jmp unpack ; once if no ; Load bitmap color definitions: Char number in R4, CPU data in R0, count in R5 (MSB) @@ -1513,8 +1513,7 @@ define_color_unpack mov r0,r2 andi r4,>00ff ; mask off to 0-255 sla r4,3 ; char times 8 - li r0,>4000 ; base of color table - a r0,r4 ; set base for color then fall through + ai r4,>2000 ; base of color table ; entered from one of the above two functions unpack3 diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index f565934..8179506 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -2664,53 +2664,53 @@ keyboard_handler: .8: ld (nabu_data2),a jr .1 .7: - cp $a0 + cp $a0 ; Is it data for joystick? jr c,.2 cp $c0 - jr c,.joystick + jr c,.joystick ; Yes, jump. .2: ld hl,nabu_data0 cp $80 jr nz,.3 - res 4,(hl) + res 4,(hl) ; Now data for joystick 1. jr .1 .3: cp $81 jr nz,.4 - set 4,(hl) + set 4,(hl) ; Now data for joystick 2. jr .1 .4: - cp $e0 - jr c,.1 - and $0f + cp $e0 ; Keys with up/down event? + jr c,.1 ; No, jump. + and $0f ; Arrow right ld b,2 jr z,.5 - dec a + dec a ; Arrow left ld b,8 jr z,.5 - dec a + dec a ; Arrow up ld b,1 jr z,.5 - dec a + dec a ; Arrow down ld b,4 jr z,.5 - dec a + dec a ; |||> ld b,$80 jr z,.5 - dec a + dec a ; <||| ld b,$40 jr nz,.1 .5: bit 4,c - jr nz,.6 + jr nz,.6 ; Jump if depress event. ld a,(hl) - or b + or b ; Key pressed. ld (hl),a jr .1 .6: ld a,b cpl - and (hl) + and (hl) ; Key depressed. ld (hl),a jr .1 diff --git a/driver.c b/driver.c index d1ebdb2..6b4bf59 100644 --- a/driver.c +++ b/driver.c @@ -157,9 +157,18 @@ void generic_comparison_8bit(int min, int max, char *label) cpu6502_1op("BNE.L", label); } if (target == CPU_9900) { - sprintf(value, "%d", min * 256); - cpu9900_2op("ci", "r0", value); - cpu9900_1op("jne", label); + char internal_label[256], internal_label2[256]; + int number = next_local++; + + sprintf(internal_label, INTERNAL_PREFIX "%d", number); + sprintf(internal_label2, "@%s", label); + + sprintf(value, "%d ; %d*256", min * 256, min); + cpu9900_2op("li", "r1", value); + cpu9900_2op("cb", "r1", "r0"); + cpu9900_1op("jeq", internal_label); + cpu9900_1op("b", internal_label2); + cpu9900_label(internal_label); } return; } @@ -180,12 +189,24 @@ void generic_comparison_8bit(int min, int max, char *label) cpu6502_1op("BCS.L", label); } if (target == CPU_9900) { + char internal_label[256], internal_label2[256], internal_label3[256]; + int number; + + number = next_local++; + sprintf(internal_label, INTERNAL_PREFIX "%d", number); + sprintf(internal_label2, "@%s", label); + number = next_local++; + sprintf(internal_label3, INTERNAL_PREFIX "%d", number); + sprintf(value, "%d", min * 256); cpu9900_2op("ci", "r0", value); - cpu9900_1op("jl", label); - sprintf(value, "%d", max * 256); + cpu9900_1op("jl", internal_label3); + sprintf(value, "%d", max * 256 + 255); cpu9900_2op("ci", "r0", value); - cpu9900_1op("jh", label); + cpu9900_1op("jle", internal_label); + cpu9900_label(internal_label3); + cpu9900_1op("b", internal_label2); + cpu9900_label(internal_label); } } @@ -214,9 +235,17 @@ void generic_comparison_16bit(int min, int max, char *label) cpu6502_1op("BNE.L", label); } if (target == CPU_9900) { + char internal_label[256], internal_label2[256]; + int number = next_local++; + + sprintf(internal_label, INTERNAL_PREFIX "%d", number); + sprintf(internal_label2, "@%s", label); + sprintf(value, "%d", min); cpu9900_2op("ci", "r0", value); - cpu9900_1op("jne", label); + cpu9900_1op("jeq", internal_label); + cpu9900_1op("b", internal_label2); + cpu9900_label(internal_label); } return; } @@ -255,12 +284,24 @@ void generic_comparison_16bit(int min, int max, char *label) cpu6502_1op("BCS.L", label); } if (target == CPU_9900) { + char internal_label[256], internal_label2[256], internal_label3[256]; + int number; + + number = next_local++; + sprintf(internal_label, INTERNAL_PREFIX "%d", number); + sprintf(internal_label2, "@%s", label); + number = next_local++; + sprintf(internal_label3, INTERNAL_PREFIX "%d", number); + sprintf(value, "%d", min); cpu9900_2op("ci", "r0", value); - cpu9900_1op("jl", label); + cpu9900_1op("jl", internal_label3); sprintf(value, "%d", max); cpu9900_2op("ci", "r0", value); - cpu9900_1op("jh", label); + cpu9900_1op("jle", internal_label); + cpu9900_label(internal_label3); + cpu9900_1op("b", internal_label2); + cpu9900_label(internal_label); } } diff --git a/examples/hello.bas b/examples/hello.bas new file mode 100644 index 0000000..35287ec --- /dev/null +++ b/examples/hello.bas @@ -0,0 +1,15 @@ + ' + ' Hello World! + ' + ' by Oscar Toledo G. + ' + ' Creation date: Jul/19/2025. + ' + + FOR #c = $0000 TO $0210 STEP $21 + + PRINT AT #c,"Hello world!" + + NEXT #c + + WHILE 1: WEND diff --git a/gasm80 b/gasm80 deleted file mode 100755 index b5bdf50f1e5966da15d3bdb5c427001993724f0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87667 zcmeHw3wV^p)&FcRunC|bC{zSCB9Z_??ia0^kVF%T0h6HMZP_Fnh~xs<1VYss1S=M; ztYXDlCA3}=)K99Y#9DHUzT4y zi_p*?T{#r$MUkA%rF#>+r6O9HVpmB+XY_zv(2i{lp27{NFk7t zUI9FoUbX_Xs7;^E17K0T^pZZi-4&h&Pfz{+20bwBba19RblR`{V6Xo${}k10oL z3CCmkz(n-Y(W49WDOv7o@YYP7J{5XZkumUdCLWUS zf_)N^CNNF*qMtELXO}osidIU);a_13ge?%ZK-dCd3xq8Ywm{edVGD#U5Vkb~#rle;`tIx2zo3wJ~?x)|Qp-uHTGQ>(qSZ-;A{5MAaQQF}u6K zp`OGyVn^Wn!E2qvvb&WdyE{&)LvgFe_}75XrJ9ScLrT2k99Eri(W<*O*S)n9So|>6 zPG#z1<===lB2@G3wZtEp-R*>|oywBm37YugA!91qlk&hI)lKb-jKHAmZU zK61_UHt5$&Px6OWl#?usjn<238uu@b9=(g|L!U#=IIAD=5zNCF@ezM4`ao&Su=mj4_a1` zUrA%+XgiXNF=AVh?UZ9%Rsiz0DU~X=cSd8*fTs(#>;TV^YjWC-Vr=zT+vK$DzJ>_ zuXP-h-HxxmpA@23F3tO>wj=P#mPpL?9b>od8;*G&>F(MNdl1&TWoe#a z@C~$kGWin9$<{Z)Cg_{CwZ_oi!_cppG4kD?FnAjl#1UgS-`K04?(vjyr^?$}O+9rNCbj2S*2-?upM{GUE z=o9{y#0b(Af97C>*wPtc=_a-m`v!(%EJw1xjm&QE1ic??Xo4elkkb*fD3<-Bb7XV- zLOriX_#Mlux;o00--Z6n=l$zBcZc$??t{O`&i`^Ke`_E7Id=X#L-`j*_O=hrkKp)j zS4$2=+583b&iS5NGLtciFAxXmIZbt9sGQby)T8-5NY+L1KhzDpgf$#xG{-0&+38T} zIuBVf4($KJ3mMKKF@rdsv2ga+4={IPM9*k-n0%OGvpCGbxVdBf_}eb)NalBWg7VOZ zzS<;Ny<&;bIP;Lxfj!fTeRRx#es|mCt|Y%=xUcm{iFDgVj*V~$2rhB z!21TZLox30=(`PV;BVz<-Hxjc^m+nyWW0_QSMEhj(g9ueA|^Qt<4mz8>9(3Pz1V$x33(Kd9% zPNMOkeU4<3KjQE6jOc)$_VO7cPX4a_xy|g)^8c0o%=o|R&*f%+?pFUB;}iQo(Vx@wbU)e-0xa;@HyiH>{Ds9Cj?Ge;>@~r%m|2J{OS>CeWG?_wuQhKdSZ#?1$Rl zyZdM#*zvZHb7Y@$V2Ig%LQnhlc|frW*{1zF&IQ=C&vvs}9?j8Lzc%Lfqej1uF}LwI zx%!kJZ}!W9JxI@UoNK6z)(qO`o;?1xj@yP5>v3Cs*>J~qwBb+t>EkM!4X-h6*mnH= zTH25NYSV_-#f+AIRoHF#TeZZ)XO(YTixDUFIbIiAZRxce=W~5`fEetM6Xz~k&z&(? zPxw5-F~Y96XUF=7ePf;PwO$-olAmH9(CfOMQ!zb0oo3hjPRyy})caU_laW>Ag%)Tt|<@aYMcj4Nk`h# z9|s?ue`vp^^R%3W9ub`9r0nf>UeVzXI1Bcr!#yMeI#LWq@hjP_4K(c;($4MncCgOG z+3yBeCuwJMKkckw85AG<$Sx1DuES|Nv*SMCXD6w3&ee`3IRkre__FT%^SNWUl3hqQ zin-$@=BC(1Vs3lc3y8Z>hWiq2Pi-5r7u~ z?zsc#%RY2hkV<@!J$!`a0P7g9+5_X!XF9J)eu7%^8uv$+jj_t8FKy6WW5Z%51#Q4% zPiK<8`W9vHn;*8a_W^wyV)lXM*~ggljqIZjL;sKZ@JIGFJ&W9t<57q+v6J>6 z8fWa~=D2;_&$#_ebVK`2j9X5~e7CTT_W8tfb0>Y?kYw#Wrk}4cWQNpd8|b|Y>n-hF zX8k2xpKP)e{dVzw7o3Zj&$#Cco#VJm75fMIaF@DbP;WjD_mS>e=6^WJ$3A2<0l?!oAh4t<8v;j^nS>} z+MD$+$fCAz$B=at^HaA)FM{hp3rhV_h@^qGA5nD=$I zy%zRd>x{F`0^$c`Q=NxT;r^7)xtr!^S8s^?cYZ~?3j*$uouo?TayeuM(F#Kqo{Ydm|$@Jq0=YaTiKD7Fc~5 zRsg-@IZu5cIi#cXSNbsd$Wc8ns9YWzW6ZN|jQbYC+Tf#tVXZiDI?ttt!AJKuRp2H6 zyqZ4SflpE$!b$J`biVmJ=xp!Dk!x&sx+^2`xyBHDZWHN;U98VD;R{t5hXjmu=SbC^ zp!2ZJXw}_DcSRQiAICiKkMRN3R=AFJHLnhIe7LN+g00#epSGpwd?i(;^UZO%rnxB zW6!ZH}d&p5|+WkR-IJ9v)b?~sT1^Y&mnWNXWx;}{F}!8XQ?{q$jMANKnmw|%v} zO?-Z|LSox~=54R`ZR0zqpZ33r=$W(PU){j;XPh#B@mbg2Z)v;7?mfOoeiaL!B74yK zOms>=di=EyJ>CYUKZg}PZpD0N9}n8t*2mNOk^KVX;PX;F&aDnB_L6ZAsICkeXQ7=q zQ{8Iw@2C3E>({`j&as~IZ*b;9e<`kf?F6+hI1iO`QL|0{eOf;JlKKG~1^Is6b9N=W zZT&aRfw7pU?1$X%LT-o77CVEnE5#1*$&Y&cTy(h;x}bfIKgV|c2<<<7_XYA4&daN)?n=~M$#o@fuS;cA7iCnp4ee-tI`cvv$=;Ov^R1ncv6~VQOShq4 zZMkZ9eAT2(t@jYJ@tCd=+UC?p^aJy1JCBFv(c>^i+u`}#(OaK~+~>Ky)?Bn7hj*OL z<+V&~fxgOT$95T-A9}PxPKQ2gbDOju^7_+8GKV%7$KZ}y+s46tA=#{pT@K!l!oJRO zD1OPX=_346j=g?+@V>$(Ps*|G=J1*oKzz{#9CpK*XAF&h`zGkthJ69=6fBCt9e#*@ zr1uc3Z>Nz@icIR8tc`^6+Sscdtc~_|UOrYkF;+V?=Jc$v+rSnh{U?1`WS5D!p=Zxv zTVsDcZd+on{6Dd!wDTX>a*Dm*h<9a=!TTRpA6WLy6vJbmr87$#<^=hNlkTtOOuqyE z;D|_iMdlLGM;uE&Vw&%_H^&vY{PVCU&^VrEZyPZ}FTa6*%DkfWS=-dsSDN$q9AB^9 zx(xGMe2U8G?vd7t2zxu2?|bDP0i%!7r#P7t5*x&*lLEYE2KNc?sf49cKZ1Q*?ed?_ zeGBqk7diZR=h2Ih6`V)dbGM&lpWC$N!rr_O)A;P4h%*&*d>Hd=5$y6X<}HoS40yW5R3X)JW2 z@t6^f_cnlC9i!SwS1K2OiHzm&h^kD0K+BT$}s6%5(w$^sF z=}-Pb`WHa|c(hA8OWPzL@9DM|@Sfa>`r;GR?*xnw-Q|;?;+>EYG>)6FSK%%y)9Dyp zj60LeN3fS2h#b6$?6wH|$ivvr4q$Jqb_`y#2-q5&^B)G!!N@_IZbA7YDF1FxKQ#rZ4PPo$5>>+||u zUc3GCPWN95yHlITdSX!?;CihqFYD^Wd#z;qIGhLK9y#5A0c6-eOTuSrBaay$ti*bS zv6cSPp0D@2>ztUsea94{-QwYuQs_He0cCw=ME7#>)IaDzezKqLZ@K=n3tiN&>Uws(YA^ZRA{!B+s?=)SoSx}m>WG%j?X zw+VVc->knuUwZ$H?wkA63!jtqWtY3{cCmeyb}YLb>%DBcm%j5e+)HEZ^_ar;@%;IR z&~)x-W*?3xU&Vc_LjPLXwsyazv4{g6w{yII9(1juvGCIv>HFYeC~v3!+WqD0y64*D zUGbPxRuw0r&d><75pn)oM+ar^KDr}fcMJST;U2sLcaCUxm-Z>#Ij*KW?jHl=F;7^x z0PY+`w*c-OHO}*a=F3s+7h1fgi@1AJAv(~3QGAH;?Mq6cwU3QY)AP;`gj{4SG@NMK zozQJE>f=sfGp!Sa$R{`k4T8Vvy*CDWldh}q`EWk!bYN}OeV%`&e+1;J8y-4OAx7ad2kmJX$Kafky27jH^EBE!xlh&}6O^Op3(9r9Y1!=y<$X+U zf3MHsKVZ|L!=2s!N8HzaNOLBcdMwWe|(pZS;NTOl^a-N0U6qs>0u&3&iw8HTYW+wH~^ z98c#&e+$~jfBYC6PkWzU`TW1GMkh>3pu9s5Jy=@EOs z$M415i+1#!h_mLz&X}IQ&>o34vk<%Jd2-avpS!r5+Y4y!=S=oH@g95uzeh@T>9m#6 zJMweUmu>v{rL-M@Z()5NCNdoFR&{j(qc|=C`R8>1uqL99&}|FZ-9Dzl_v}%J&dmYn z^%wNb-ZtsAI>L%c_d_r7;ZDRhvae(P^{ekk_&e|!3*FhC9(lu_@mL?qM@;k|j#2CO zB4(iTh{8BhY-QKsOt#=5BeWZQb4_C%>|<2Ce=_RsMT|vbeKz`d3gmY}zNJfy*5CdaKKA8yd;H!x9=y;) zRdr^bBj@|^R(ui|ui7bo$9LLBQvb(szmMfFvEVs!%_Z=YIr#2hw2rGoVwy`!V6#h=P{yY{q{H?qv{^?x6JczeC z7ipPm6G%>->UJUx_*7Kk>-oF$4 zRhTno4C#r6U*nFG?imi?-t21ZkNa=4?j`mQbhPh>tgA6kFx%T>Rr5*vhdbI4zhxob zZa+H6p?$LBob2v>(8Hl_C~ieN^ILhHKOcUJvICG0x$U^)7zSAs*MJx8q8xjY-k0Ks za;y`?5HsODq!oOZ9^|FZsg^jFY~%BJC-~z@2A^L-t<;PG=2ER{08v&HN z`~D4JsHXquKC8R?oGr8Y~OhBq5gxQX>8xYolRhPPCMpa@cpE~$Q*n>5*Y4zV#oIA z7)SeYYJ&eI)XhH8+N1U^vc{WY@_&7bIQTBr9k>e^-*3{sgmwD9wLmT2q0 zHI{woNMk7vtuM$Qiu-Jm{~fg3!sla}=a_@|UbLfK)&R_jQmSWP12AVb_6j~*rnQ~s zeCLAfZmdu3H19u${)E$fB0Kk*`)acP4)D;r6hJ+)CwNk+o#6WL{mK5HfJbzed4zRA z^XYe6p>F`Oi`GxKm)(6LeDwk773^d4Wd8>Av6=rC!guZC?T~c`-nAfk2^e487jL2V z`fL9a@ZM-|fBj_t_5VTp^^oP`_G7H}pFCFkZ-CcpZ-2{VzZ>nVC_Y2*+TPc=*6_H_ zL46wkPVxt=`5PHWY;_XZJBG%M;8k$}CS6Mjkl^)twv!aCAE)mLA{M^Cr6-7(pJ8rsfgTa1Am(Q^gzL7zD^*?$uF zw(;knt(Ysc7ttDb68aY8Q&ap-@L_G$eQ5(<0{CQYrF)Q|KaZH=e+%n9^@*OZ>E2Q1 z;kqgQFQO4+vyc9p?vvP`FDD(rC-;pxJRhmt04xEv845Y zWa<0Rakl$Vv@2zFuc~8oluX++<`jydjfscuSR`Zf2oYtVp?})Exw(`9{uYx2E#g>gz{|o zW54V0FV6DEgD0JMbS#7W0q96^L6J@G;MhUe9NYQM>}$?3bY1W*x(+}&&A(&mdIW2v z6FfSG7kyz%>Oc9UjIo)L?Px5n$J{I6c{1ESPX9nc-H=?jMNsPe#e&eJ5eeQGUd@P?^hjMz4_*mn( z20Z%gDrbWj_?5&W=#SRlfxqv9F>^SY+vy(eC(x7nKsJ#znEDoL>)U*f|vGajD0EL3U;^%pF8Nk7lppR!gqL7=B9eE4YfySt?gV#;`iII*AO3#z1}NM z)Unl}xPqzvBG{>eeL&85_L#5fSa!i#ZzRg;eT;s`eEwAb3E=5jXQ*FlN$@)_7<2M* zc?SS~i@!e+t^dZE+=1%z-nOa!{gH^J2U)RnH|A#?+U;2nAOro9_24wNPv;M?eqLzJ z6Z@Tj-uvNaw7v!I;C<}G9Qu4Nm29Qu-eIjRF_5(mPXOg)Uux%b>=VQnJQKl><6=3c zuG3@D-5SH^Ss5F-Q$RVbNvMA)E_0e6@BQnue1P%JL5R8d@0^i6G+*g7|L?#T)D3;& zvJtwEn7`B)_!H8Y0};G`(w--B3s5HeWGp^k>cqWz0Po@i+gLme@1Ci3^tY3AJ3iE9 zxg_%jnWuLBS55Q(0(Hz7;V|u^xNGT5f$hPcZRw`J%S7!?Lcijpb>DWyt)1py!+i@x zS~ixokbJfkWfTvYcP0vZd^!8Ju7@$$Zi}OS&h_+Nj3Z{vIK%>bufg5Ovh42pu)V@( z>wn@kn zdndu~7s2n=I&)z66LlPg&+?GRxe>Va`Tj`NT|n|z03U6;^Tz#$#y!Btb3P7v+zn}b z81nese<6L=LijY6N%<7!@gtw1x}79{7}@pIE?xIx`pydHbLjoz(Os)aAJoNrS6!`? z*EqhTL;5=iKdtNe9rU*z`S0(nbnADI9P*BRn^rsa^)&wpCbl@y zA7f%8lKfG?DDM3t0)8+WV>1#yH5~VSCuVm)zj90$;xGMv9`;LpUqNeJ>kj@7_YV3# zG<3sS`jZ4}e$sa(+jiWC?^;)N>G=0a+`CQaU8eBf?_jjuvT`imKf`yg@t*E>`Q8!a zVlBYCPbjmsF`4}@q_2S_{~w_{^#Skk!wy#a3hlp#&)@Ad=H0Hi(qw-Cd@b_6Ci)ED zZKuzsd+}Bz``-iaHsNCwhp7Xon8j}5wux@ydU#~Cxcjk28 zXdSS=ql5nbw&%T5JI}ZFzcj^v2e*MU^tu4Xjn*pYu!ZD@*lJsfe>L;|5Gj4vkaXXq z$Ls1Y(%arP)u-nfl0#$k>;I;X6{-HKx!o&BNBCF2I_^sKyP5Z5(hnm?U+asRlE=FIWvSSdQH^xaB`pRG#wf9$Yq zi8J&%kpp|SgP;3hTf6cs_w*QD*|pP{KX#o$=D0J{{{+i>z|ft(t7z&-^yBod>B=knw%z7T{|1)l zM@pYb?w^MBcrxxTCSrXapWXe@IIPW>tLNjn8MaB-sNW^S_h_4oZ^l|yg{Ke?#<0Bw z?JS}ADnt7-;yAvufDH0)r_oR7w=2$-<;UOn2--&KYF`|#ebKsy>XC6+-#ws=`iJ@5 zzB5+-7Kd$|w`BPjLheWC2la>gr9X3poP+2W`lRpt(FffZdY9Ae%X#R_e*Epd0P2t} zHsy}N{?ijf1b`7;!0+z}P51gv{!E1G#Z%vhSf4Q@#2}UTts}>5#rw~YY5T4M(YEg@ zh|F>LY~p#ePkp8*D3|qlkLFqKm0K6`{p&EYjeR_!M<@D0_AvWy_FJLf_fg!(mad=`Xu+Yqm~s4kw6`84-z|NGo7-b>RyC~I-B z9jv$Zc6L!akyrF?2Ymgu6LpUN1#ahQX$N`*A&?H|6?q7BU17S z^40wq_@~yBhY}4*^T4ROpu@T+9ko~$1 zH2DJAFvd9JVT^Xg&HujtR;@qTU%zvvW6M5yH-F!czb%TsTD%1m!zR(4VCdOV%XOaX zUj|rAH;~iS? zN!+kA`1h_YeP^%?@&VE%Sgw5{yL)=D+_EWjO(p%wr>T#){~Q)$jX}HfUH#ahlF)2B(=;N>b3@EJi(?mT_9n zX$7ZVPAjc6rzlsAx0EW=O6ANfhH*GwjC?xhi(s@&D?f8CjN!5JCDUPyaw|WlWIFZO zA|_NNrR#wpGAUg(rAQ`CG8vpH%_%_#n3zdKnXptyrjj!y1@n{^jb^jTEzuPCpn%_UN|qsbB?byGwZ zSl>7o~vN6L^Y!X21;iaxVy4QSiL#_jHG3xLx7W){sfI9^kVWYQ#)A(<@6lu4#S zGL@Xc?8lmcd5_ZiYMKpN@)ke*aP%$+A}b_@Eh|9zcGV!o_=GN z5R#|&m3$g=_`gQfgoey1@r83IRAgeX(DAawBtS{D$iqdg(s@=Xj1XE{Fms9wbF#-8 zr<@>?!UzkW0#VWcq=V88#20GeR;krMNU2tAijGUPa)~Hq<@6d7tWV*TuHTDedTzoL z_-|senoy6)RhF1YX(IRlWLk7)5*B}5f?SgDP*d2ebE$TQf|KW5FeT@LiI`4#3VpYW zL;WO$&Z9Bx=(_bK^K_?zN1-s0L@WC zi?PK51&F1Df*?VdCn$!TO!L?f%`>4K;|gEW6_X~E>&Ei2?h$}W8YqFOEPy#?%_-#* zM-Kc1t6@bJrWlPbT$d&m1+7@|=N9NWfE}FEG+tRTn##A8m1|1MDoC#>)2-GK=MaSfAf3{aG)4OrQOTO3n2x9v zO$D_{Pi30rrc>VvXzFS13{W$Jt&lBd23vu#KuIeeO-UUg-^ zlcwfU>`j*NFpsA~2~@^xWf)#;p~O|jTxF#7lgVQy<>etr(|E#oT$;scnX+#WO(}>Yu`y@~6f;sBGj~b}Yn_rsK5yGj zbZjR4wCPEnVzpr2hEwb&IPHy+r&unSx8azUz+H$bEuDh2Hq&@wy;SrD?VR2u6<;ztA!u=LiY39DMi#er<0fyGDw!Q*sm!vf z(53+P_=1^W14~}M-Y2|eSg^63V-IRV=t7G5GO?yAAXAVHL9zHUkF^_ui(Cebv`dDT z(b)rFQT~Oxpb3i-c8ek=FwZYi=sv_DWLJeW8Fe1JT~8C(021{M9E=b`%D4%LE#%r2 zsyHaA5-+T3nQ7@Xr8%FWu%}W>XpBx0UP9!p%2 z4fA|<*NA#^iBpqhP|^xnZKkaiY%rRZR!Doj!DzX9gAt9a z4MzG&8w~W(8wm08k(O%rU|701RMi^{@zDmOQyw2|Fq)>#g>c$jbjszlxe!g8i%z+m zHWp2DIqfP$V^^_KE~hPJp59WZl(v+4dP^aSwv>6n8A?cSOPR-8iUxVQ%9etIt%hYw z5t>F2rsdKsPH9W&Ia36;6p|oY$~?WLXvEr5Z2WZGr>%fWWlN#FY$-a=TLk50OVN27 zE?WxWbovsRvPICALS;eP8%onMX)mWO#ZJ?f5<(m0vZdI%)@w_#)$iF-LO|J42n=p1 zY;oFBG)`N}yaXn!ErnUIb|A#n4$9{r9ns_HM<~v0w2RbdQVx%fjjcl<1;#lRjey$< zxuGHs2~WY zzuZ+>SMRF!lzFRT)r7N>6Me1;iK$J<`_6WGmo$RPY+4wr%5aO|^_6=TdtFtvzAC8d zYpAcPU7#wemR9+y>S|qO%UwV8*4L?;x{Ai?x*&N`mCpx0muGPuYSb-W=vDdk^>y`U zyJi(%=vwBjZE%%&$`>v3)Z^v>ExVTbT#M_yORMS{MU}eBN}spE)lgUGs;)zm%j)sl zg)^4RQ&Cax_4!o2x7yQCwbbjny0K<)4`YS5yspA~HZ*SV*4KKfU0!P0l`_>;Zz}Vjn8%&c=2@6 zK@VRO?25s_SoP6*kCwiwAJQPZ>dQj-@`Az|$(%J+wVnp_$#R2G&P&ytV4rOUrk+E^ ziK@O#<$7vs>)?iqy|tD>$PKG%7dJMj3#zKU7Uo-6SC6J#4GTR`2i{m!PgeBSE@)V& z>ZNbx{fdHVFP>w$Zm{pF*xP$JM3gl^q*!Gg4B{&DLM=;~SXEeC4kxMdHF#^wmrt<| zX0U=Pyg*H-nbOl-k0rElA6WA8FTn32O7drxtnd=YbR5k4WGJhu zl>un&dkCKi&SahMYtEJt*bqY4A9`gl(luR*1N!(drLjljb6BZ zMS@;atXeMpqcF4Qx?D(-=PINwOm(`$^x@sG<%_GzF*O@~o(0~sW7PtWuO>6mwZK#3 zorr!o<%TvFgv4)l=^2)O+vHZbe z<#jc}Qde8O+%*y4#3`$f zA%P|>R0%Tnl7WSrHMhyA{%$fb5WQt!kr6xep@+3pS~Et^s47}SgK|RLrC+Yb+C{Z> z%dj9xL*x>y33ey1HTCPTQ0le8RY_|@EqsI4x>!|IXTu4m$+8r?6RoOEi#@d!wDr)Y zfWG)#wO-8q3O%Sa%g%PGsmhfH=~($8s;;pC>yK{3khM&7Dz9s-uBe@8U$`K*8jAuo zMA`+_@0%5lR#sQdoXg6NE!U<{tculBCcn6NR&j~zf?0El@~}zMEV?wOxTvt`LID|_ zT|Dc;;+%_I)901um&D56eo4;EIr-CYty`R5Lg>t#>G?BNPMKb5&UWQW_b|)Ls;X%t zsDVAvH9dl{c-I}TI4Onirzrg2nd%HY^g}7p_=&>18c_j!ndAE)=!wCXYUqdZ_zs2| zj2G@*T8dJ6_;%*O3>D$ZRF1@piA%%`ZKigV8rp2h9okHFiH_nF|1XiI@jXhN;_nve z6z|^XG=@{HH0t5|#2UxnI@2lMG0`dhc7;yy?ukyJzfOm7itm(ZdN`-}5{;%$<`nO< zXd3^2pic4k0d$J@E9s|M{|^5OTOe$Kum!>v2wNa*fv^R_76@A)Y=N)^!WIZyAZ&rK z1;Q2xTOe$Kum!>v2wNa*fv^R_76@A)Y=N)^!WIZyAZ&rK1;Q2xTOe$Kum!>v2wNa* zfv^R_76@A)Y=N)^!WIZyAZ&rK1;Q2xTOe$Kum!>v2wNa*fv^R_76@A)Y=N)^!WIZy z;QuoVoVI}!9;#fN#&aroBGZ|iW^*e1c?K^0GZ`;6_~#n9@Xu#_p}}8m;KJX)__YRq zGt;X%75-b8UT5&HH*n!^VZ7Dgf5gCre+%Q!8vNS~T=;h~E_U9<^qU6$SEl!In$4;3 z?>BJa|CI4kga1nd7ygJA%MZlkNDa(>ELVtxVr(;CC~<(ZC;I`cVUa zoaxiJU(YbTom24#!T-RxjJx1}WL(Bq@V_$t0jGj@GX1H6f5Ehji|`+1TWA=O&-iM_rN65gmw6%leghZ&pEEA@7ye%vxaji;<1#M7|D=Hn|8tDL z#HsL${RJ0(vHxoZzt~@J;V)*sKN|dEf5C-c?EkL8FZLH)_{IM38~kGb4;UAFiv155 z{9=E>g5C0~4%1f}xQFQ~1FvDa(ZH88y@JylIlY-vzk%P$^t}eY zk?A%Af0XGb4ZNM{?FRk=)2|u$Zl>Qg@b{ShfK!=A2bliMz`tZV@>ikjMhw#@8Tcrs z;|zQv(}@P2&h+^Pp3iiVftNCUC8r)v%Q&s%RQh!_(>_jxe;L!)82I%}iyyi+Sp8mU z;E9Z{VO;!E`0p@q;lGD*@mt~lm4OTY!;FhR3;z=aF8se?d$0U2L4y(AIG??S0ZPk zfeZgM#!qH{7yb;!;|%G#B|3U*7`Lh@oKN0>*4P5x$jEkQL{{jOS{yN6RPlSJ& zfeZijjEkQL|4jxi{I@YKej@yL8MyFoU|jq}_#ZNG;eU*A@e|>H+Q5bXdB$JjRQO*p zaN++W<9{*u-#2jK|B&%d4E}!^xbT0)c;o}2emjt9!G-@s#zz|bqYYfn9pf2~G5m0{ zfeU{M&uf)9MqYDd-q!G|&~^Ih=o zF)s63@Y5Ne%&Fj_f0BWV{uu@?`k!myqJOS|i~fZMF8a?haM6E`fs6i^GcNIlhiO@t zu4cNLQ(1omU(C3yGlDlT9?9b%coXB-aw_w#ndwyqzMAP<416uq>kNE7)4wqA7N+kv z@K&Y=^7?1m;Snz1%<0pd3NHNH7?=HB@Ru2veO&N81}^86zc4QQxbXjjaoNWO|A=v! zM}mK0;3EGh<1)X5-}#U=F9a9T`F7r|Nrx>{Kr!g+`RQS&`aN)m@ zahbouKij~Ce;(s9uZ6$Nz=eMi<1*iczrnzT|2oEHz6k%14P5wdV_fEu@UJ&;;or!( z%rD{JWZ=U81miOAg#TFs7ycI*AIbAn_+MvS_G`i4HgH+@Iv794kke`4((b2>&ocPG zGH~IKYPI}x2&bZt%&*}FF7r!pkt6f#dj`MEuW<%0^GnuwX;@UJE^Gk5ym-!|8j_}L; z5?uIYe#w3${4&1;7k-&v6O3_@`6amU%lw*b@XP!XT=->vB^mrOzXTV4nO_+OzsxVe zg9GfrA*&o;Om&a&%hsIdb5GIGyQ^rzs>aD4g7Pa9c|Q|p-S`_$@F*w&tf{8Q(2et zm@YK%IZV&vRMtJg%MD!Q)G)rBQ;C0m#PkiE-pHw(M{Z$yEvM@_m44mNw8Uu-GcEEr zGrfh=8~Ge|Gp8b_oy)gzn!UlYpUC+=<8p5=_)f-OhH24oQ z{S~KCn?m(*GA->6X8I&fPc`_*8vLg-eWziE1jds&J%>~2@A*tiySYpka(c1BKZogg z27VROWt>)WTE%HSr%O4#hSQrk{RyYHbJ}9y4>0`%ry^%7)4%6*C#SD+D*8x&-(vjF zoQj|Sjp>61eu(LB4BYXsHGU^@DsoO@+GXHpFr94R=}hMtcmdOw82DvOOPs%u={ioY z|oJKbx2qd;S;Gk8}DYr@!S?)}I%cewkBQX9VAE z@W0FSdj`MYA22TS@gt`HW#C^i?Rdl*FX4}2`a}aC$@CZlpTP8F15aT(%fNG(zRnrXMx%Cz<|@f$w1YWdq;M^xFph zKGPo<_(x3t%fP>4I`Yxb@fyVRa04IBbew@FFg?w{GnhWt!1I~D$iU|@?cr4RFOgqk z;3B_~aXCK<|8)i~{5LXwE2lCq{01)me>dZDz7zQy4P4~6F)rs~k^gH07y0dsZ|79_ zUoddte~s}!8T{`UxbSx{9x(V17`X8Ni*d34S4=zp%kmS!W0*dXQr!Ea++eMgwnS`Uy_O-voc2 zaq%mW{|e*cKf?buq-9ui(QOm;G1p@r=v< zD|iayvi}O6%ed^nf|oEZ`>){TjLSYNxQ}t!XIC=)Q%+@{75rC>%RVdkR>md%5r24% zafy@v#PoZdN}MD7A22TQ(nm~x%BlGImrSe8mYqeulj)(HikuNlf6w3_!}NGgWq+T@ z^fXQ-PB@q8d``u$B+f5kT=Xnwx{lLToJw4=n(4I$ekarSa@xY_FF6(Yo0$GDPGw$* zK2I6^FEYJ{(+@cneGVG@pE2FVspzAAZP`77Q_&}u=@U2={!^G9W$?S0K7-RKoQgh) zOlKPS_nFQ!@B*f18+a+xR~YzwrWYD`4bzPVzMSb527V*cw;H&g>AMa5KBgZu@Q0ax z!oasOz0JU1VEQ!!-^28u4g7tkKQ!=zOn+wJ-Ap?kx5it>WdPGB82B)z#UD;)dNilw z4F1!Zmi^*PrYCVK`-|Yo2LIVipJ(t3egWg6PZ86l27U$8Wd?pV(~AwfiRm91_>Y;s z#lY7w{c{8VCDW}2zM1K#4E#B!e{bNgGQG#Z|IBoUfd`oW*ucMF`Wpiu@Psw~CvYnE zJca4g4EzkHCmDD$)0qaI&GZEZUc_{%fnULNg@IQy-C*F?GJS)A|Agta2ELx@`waX+ zrvJ;ppJDoUoJu?+@?SS_k^dIsvTh6i-wa&%|H-(-IWjLkHgNI(FBq47O5}fI;39v( z7Hga(E)w}C7`Vtkg>i|Ognz7o3;&snOB^NqQw?1B(;1ieO8Cz+aN)mzaj}09)1?M} z1=D4mia%e?bc2DfVESeQ{~6OQoXR@(DASuc6@9ic{T!#Vz6t+}jEkJtnSRUQ7knS% zBL8EiKQr*JnI7<@HNN6+f}g~=_?5^X%eeTD@K0h~{6zTE85e&Ld^+PY?t&LFF5@fs zWsFPwEO;g35Ajpv z{4Dqvj7$71_@Jk(agq30{K3Vz#JBNGCvqzBv+!p!E^%)*)A^i=pI^juiGg3vbh&{q zVS2fNuVi`+r{afqGJOxH;%|aKz_|FE+$%oDxcHm!w=*vOCj2`X7k?A{HO9r?1b>@x z@i)QuGA{ZbVETOiyi@cS{4ke`{_?)lh0HJd3x7BBi~ho2!u+DY;Ety)e-Qlzznu9+ zf5BszU&dYTIfpSW<9;gBXXrGW8tL;VjrlS-&EoVNPS54^d`{(jCGU;oFrLThg`Cdd zw7>F;xO_IJC7jOTRP>q4^yQph#p!&V_SvN{7`8yz0$~e;EfBUq*aBe-ge?%ZK!^og zpcdlUh38Z}4m|P`Eg7Vv@FX%#d6hjtscj4(p?X2wCWUZE1fDbSOvh7+=N3G8m&NfM zoBs^!}Nyd|nrwGqgcoyTi0na)-t$4QL*@@>JJOMmkq9wQ6UA}OU zuVIn9!c)Jjs+IuX;`*xEhDs{XWP_)C5fSc6PgQj&vY^pZUtvKN-un8*R<^#})6i49 zzI^d=i}E&AH7Ivwd3Bx7i*$jv!H1-7u@}u&T8$!8@AW`rrO)d{^OX(WYP4CotiGxN zb*g-x>ctB^l&Pp%K+>vwzQvw$UDU)-jin<5VqkNnhP!JPy1h-_^2P?Qdm&Uod9+9Q9cAiON4ffWM1}fQq*v{T ztgKR>M=nqgL{+K3MOUk~0X6E&fwi6*ue!}y*VwSQu|eJGT&#ZQtoN$BVtnegn1(vH zZn)fo?r)53tgY}?R@Hhd)I+h$JoU9zwF`XeH?dKwxfyO0Sy55%_4(8qhtKD&DXaF@ zLx1mL^^9X_T~!6f2%Yw+ZH_3l3hb!#V+Ve(rm7K*Rn--c=DxbIX0cDb=vdwW)(^mX zi)LNh9PMz|HrAA(YhM9frz?4C7kJeHhZke*t*ub&BBIp#z3`C8g=$5_;zqZ6CZe&v z-do$C#i~zG-rO98*3#1wligLdux?{{Lsea^+vjaiTOxj#nb-^MM5SF%MnTc_T9X#5 z<;Lm;bk0-X;P!B@KaYT6+|`~kZ?(EFGExPuM?>C9^;JZj+hZAIxq3PhDtt!WUiTy^ zT2s~FE<<0{ZzJpL>*{^#?~zT5>)m=xI>CFtZnL?C%=K4H3>8sZ!EJmJS?_CbtJ|U= zaT}SCOs8&+YN*0^ZUDL(Xp~yJEjq$m>#g@RVAOseRb5x+sb&d(0MmNS)Z9U=s}E5F zWtdUBqN*D!ycO=ss%jXRT4=^X5LvF?ih`49SgUwPbdL$uhG_7$3?M=Hts?6xF(De% z-O=^l1yyi_diC4rrJm|WuX-Jvx3mm!xRcdRWY_9S>i{IHcR;VF>Jhc-aFow7=SKi{ zYG-NDMKH0u8Y0!d(7s#UJ|If9>H=+oTLxIQeg$~5hCQk~x=Otax_KK~Wk1?Mbcb%r ztDYF(Yk>c$cL1*L026gx_i;avwP1r@zr=LID62yQ8p;={l>?*H)^-P`;h&M)au;&d z-lZ7*UxHk9H*7f|N&RAAvU+x4iu&EaRJC(pntFX;x_T4kZ~mN|;Qn9G@3kA~_nRB( zck6>R23|M;W)eJ8-8wL6zRysv<0dNis4oVf+ynQ&*$Mx|a*4h)52W8M1EJ9aKv%a6 zBvy9M4bEVXo<-qW6q2O}M!<*F9%sG!8_?!$T0{p`^e%NTR_{3LFlT-0a}++ZkD9hm z5cP?(u3oK)A(K(Xf7}X=NKXZpPEWn3oQB*VLn}lK93ePSwu67|ewtBlenNVG{T^yX zc^9J!Cc;ZGb(mCo1bymAOvn^l8N0lutgc$!j1_0qDyn;nZg*`5`W)=uJt$qT@m5HV zQY}=fhw@3iQaOP&w>W9#q@Td`pGCAfzIGI>cdQz4aKJwzb~)(Z!HC~Sycu=yg!`io zjW7L0bg)|okBDWrf45SGLGperl%221-V$Vk(|rrPAA_5wGCh>(E0`X^^dh1mX#HYK-cq9B#YB<(wM_3i)uQQjRnl)1*QaYFqFqeCPBbb8 z&bQ?Km1*@ui|%B4-DMX28P`99>wnF(nr*c=5VA<#6*(6FaH7dR^VvR3JDHx$^iZa! zGChjvEU8bi0mNKLG#+P@C4ZKbH(TWhBdqq;T68VbPNr!UC4B}ny`JfzOmAj-1k*d1 z9>w(AMB^#o@$BGo7ndJoI-co&Go8qEBpgWFqs7vX_Ha#aw&+usb}~JV>7h&~5e=E6 z{8s-nnBEFU0j$nrddm+idN$LmW?FO=)1`1c;=h6EGm0$w9;VmMvgj>Lzd75YUt>DH z#G?PnbO+nx3#Mn!u*#1TP2<1K>R)su)4MEs2-8lc$1pvV>8VVQVme9ccUbi^gg#`^ z=M#;NO<7{KU&`f9E_ZYJKQ6G!>xjnu8JcF*Z{+efms#bjnEtxfqJPSC)O3r!hiLLA zmcNPVp-ex{^eCoxaQ#-6x0}mdT>e+4vDWJGIVki{i~a&Mx<^B&f3PWp(5D!5yg{F1 z&=(kVsX><+^g@GPY|zUL`bP$RlR^K~pzk#3Ul{cL2K}f(KV{I*8}!Qtz1yJQHR!zt z-D%LD8gwB>1+K4XUB{GCm_`ayM_r7k7!Rh6qBVXFo=fmtif1mKd3dnIs>|`vntvsp ztMIt-%*W%wQ-DY0V|pu0>Hn2>AXd3>FzS7-2=3w%(@K!<_Sl1bcUfpauY+8ioDdjL z%+9GqVjv}kcb6k>?=w8tC4EKc?s9vO@5Twm(>ppRxFKDtyKx|-C>*CL ziNX_0vMv2$Z-mn1K6gK*UL05 zxaRdCEiIR^Id@ zUvh47-k<+;a^a1+15eocrcmLuc`8;x4gdP>-PCWPuZ8z+&#JV;n5!+4XoXtdEzy{NWL+7?hRch{t%&wMrgC(T>V&bwyG&o`d;#;V8O9@Vt})conEMPC`0(-J+nrTWo#21fqj z(*rdlSDp7}&Tl7ucJ+NvY*@9qU~1#w*RM>h-?RMd#=v`zUG~#OCwnG7_tL)Yc`f&T z;D~u8>YImt^!$>`-gxQh!&_FI{^boPUONAU%3HR5{o#XqmKENy(Kpw5^{k)9UVPo* z^&j8pzVOtfho}Gf{(tN`d0%_xo?Be6%x;+RP`vM~(iN*e{Oiu`qt1TrSM3LRX<(xS;JYGsk=S*UpM&0@$Js13+~&J5uLI0 zz1C+Jo!DBJxMOkM*U^{U^!S$zcMdx$YtuKCT2gJ1bD?wJGoz8wAh zi*Ma|`L&l^R+KmAjDLS`*)wl9zkc#fMYqiv^6BLd#O(h0%ctyHSN@}OBcD33`X3Xg zZr!FH`C#tCLxmgSFFrl`?UVy|4&OZSr*|$p`a#jX_pZC-#&>Qj`%UJp%i0dNrYAH% Z`sUoM_Y2;9>#o^*0{iY7oPEZv{}1t0#VY^+ diff --git a/node.c b/node.c index 2117663..c4b037f 100644 --- a/node.c +++ b/node.c @@ -373,10 +373,15 @@ struct node *node_create(enum node_type type, int value, struct node *left, stru /* ** Optimize a 16-bit variable read to a 8-bit variable read + ** + ** This optimization isn't possible with TMS9900 because + ** byte read gets data from the high byte. */ - if (left->type == N_LOAD16) { - left->type = N_LOAD8; - return left; + if (target != CPU_9900) { + if (left->type == N_LOAD16) { + left->type = N_LOAD8; + return left; + } } /* From 5f56f96317802a59fb66f97ad8c6c10d3426d87e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 22 Aug 2025 09:29:15 -0600 Subject: [PATCH 055/155] Correction in 9900 prologue --- cvbasic_9900_prologue.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic_9900_prologue.asm b/cvbasic_9900_prologue.asm index 1c6886b..1059992 100644 --- a/cvbasic_9900_prologue.asm +++ b/cvbasic_9900_prologue.asm @@ -1513,7 +1513,7 @@ define_color_unpack mov r0,r2 andi r4,>00ff ; mask off to 0-255 sla r4,3 ; char times 8 - ai >2000,r4 ; base of color table + ai r4,>2000 ; base of color table ; entered from one of the above two functions unpack3 From 8a8e9c878dfdb708dd7c1a33e1b4d80c8dd46ad2 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 22 Aug 2025 10:18:00 -0600 Subject: [PATCH 056/155] TMS9900 more optimization for comparison with constants --- cpu9900.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/cpu9900.c b/cpu9900.c index 6b5f859..d0d0279 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -1063,7 +1063,7 @@ void cpu9900_node_generate(struct node *node, int decision) break; } } - if (node->type == N_EQUAL16) { + if (node->type == N_EQUAL16 || node->type == N_NOTEQUAL16) { if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { int c; @@ -1082,12 +1082,12 @@ void cpu9900_node_generate(struct node *node, int decision) optimized = 1; sprintf(temp, "@" INTERNAL_PREFIX "%d", decision); sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); - cpu9900_1op("jeq", temp + 100); + cpu9900_1op((node->type == N_EQUAL16 ? "jeq" : "jne"), temp + 100); cpu9900_1op("b", temp); cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); - cpu9900_1op("jeq", temp); + cpu9900_1op((node->type == N_EQUAL16 ? "jeq" : "jne"), temp); cpu9900_1op("clr", "r0"); cpu9900_1op("jmp", "$+4"); cpu9900_label(temp); @@ -1097,31 +1097,30 @@ void cpu9900_node_generate(struct node *node, int decision) break; } } - if (node->type == N_NOTEQUAL16) { - if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { + if (node->type == N_LESS16 || node->type == N_GREATER16) { + if (node->right->type == N_NUM16) { int c; - - if (node->left->type == N_NUM16) - explore = node->left; - else - explore = node->right; - if (node->left != explore) - cpu9900_node_generate(node->left, 0); - else - cpu9900_node_generate(node->right, 0); - c = explore->value; + + cpu9900_node_generate(node->left, 0); + c = node->right->value; sprintf(temp, "%d", c); cpu9900_2op("ci", "r0", temp); if (decision) { optimized = 1; sprintf(temp, "@" INTERNAL_PREFIX "%d", decision); sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); - cpu9900_1op("jne", temp + 100); + if (node->type == N_LESS16) + cpu9900_1op("jlt", temp + 100); + else if (node->type == N_GREATER16) + cpu9900_1op("jgt", temp + 100); cpu9900_1op("b", temp); cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); - cpu9900_1op("jne", temp); + if (node->type == N_LESS16) + cpu9900_1op("jlt", temp); + else if (node->type == N_GREATER16) + cpu9900_1op("jgt", temp); cpu9900_1op("clr", "r0"); cpu9900_1op("jmp", "$+4"); cpu9900_label(temp); @@ -1256,11 +1255,17 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_node_generate(node->left, 0); node_get_label(node->right, ADDRESS); } else { - cpu9900_node_generate(node->right, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->left, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if (node->right->type == N_NUM16) { + cpu9900_node_generate(node->left, 0); + sprintf(temp, "%d", node->right->value); + cpu9900_2op("li", "r1", temp); + } else { + cpu9900_node_generate(node->right, 0); + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->left, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } strcpy(temp, "r1"); } if (node->type == N_OR16) { From 510a11eef8868ba0645f765067c09c27659c57c4 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 22 Aug 2025 11:17:06 -0600 Subject: [PATCH 057/155] TMS9900 added register labeling to optimize out unnecessary stack access --- cpu9900.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++----- cpu9900.h | 11 ++ cpuz80.h | 16 +++ node.h | 16 --- 4 files changed, 374 insertions(+), 46 deletions(-) diff --git a/cpu9900.c b/cpu9900.c index d0d0279..15e8bbd 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -576,7 +576,294 @@ void cpu9900_2op(char *mnemonic, char *operand1, char *operand2) */ void cpu9900_node_label(struct node *node) { - /* Nothing to do, yet */ + struct node *explore; + int c; + + switch (node->type) { + case N_USR: /* Assembly language function with result */ + explore = node->left; + while (explore != NULL) { + cpu9900_node_label(explore->left); + explore = explore->right; + } + node->regs = REG_ALL; + break; + case N_ADDR: /* Get address of variable into r0 */ + case N_POS: /* Get screen cursor position in r0 (AAYY) */ + case N_LOAD8: /* Load 8-bit value from address */ + case N_LOAD16: /* Load 16-bit value from address */ + case N_NUM8: /* Load 8-bit constant */ + case N_NUM16: /* Load 16-bit constant */ + case N_INP: /* Read port */ + case N_JOY1: /* Read joystick 1 */ + case N_JOY2: /* Read joystick 2 */ + case N_KEY1: /* Read keypad 1 */ + case N_KEY2: /* Read keypad 2 */ + case N_MUSIC: /* Read music playing status */ + case N_NTSC: /* Read NTSC flag */ + case N_VDPSTATUS: /* Read VDP status */ + case N_FRAME: /* Read current frame number */ + node->regs = REG_0; + break; + case N_NEG8: /* Negate 8-bit value in r0 */ + case N_NOT8: /* Complement 8-bit value */ + case N_NEG16: /* Negate 16-bit value */ + case N_NOT16: /* Complement 16-bit value */ + case N_ABS16: /* Get absolute 16-bit value */ + case N_SGN16: /* Get sign of 16-bit value */ + case N_EXTEND8S: /* Extend 8-bit signed value to 16-bit */ + case N_EXTEND8: /* Extend 8-bit value to 16-bit */ + case N_REDUCE16: /* Reduce 16-bit value to 8-bit */ + case N_PEEK8: /* Load 8-bit content */ + case N_PEEK16: /* Load 16-bit content - must be aligned! */ + case N_VPEEK: /* Read VRAM */ + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + case N_READ8: /* Read 8-bit value from read_pointer */ + case N_READ16: /* Read 16-bit value - warning, will not work as expected unaligned! */ + node->regs = REG_0 | REG_1; + break; + case N_RANDOM: /* Read pseudorandom generator */ + node->regs = REG_0 | REG_3 | REG_4; + break; + case N_OR8: /* 8-bit OR */ + case N_XOR8: /* 8-bit XOR */ + case N_AND8: /* 8-bit AND */ + case N_EQUAL8: /* 8-bit = */ + case N_NOTEQUAL8: /* 8-bit <> */ + case N_LESS8: /* 8-bit < */ + case N_LESSEQUAL8: /* 8-bit <= */ + case N_GREATER8: /* 8-bit > */ + case N_GREATEREQUAL8: /* 8-bit >= */ + case N_PLUS8: /* 8-bit + */ + case N_MINUS8: /* 8-bit - */ + case N_MUL8: /* 8-bit * */ + case N_DIV8: /* 8-bit / */ + if (node->type == N_MUL8 && node->right->type == N_NUM8 && is_power_of_two(node->right->value)) { + cpu9900_node_label(node->left); + break; + } + if (node->type == N_DIV8 && node->right->type == N_NUM8 && is_power_of_two(node->right->value)) { + cpu9900_node_label(node->left); + break; + } + if (node->type == N_LESSEQUAL8 || node->type == N_GREATER8) { + if (node->left->type == N_NUM8) { + cpu9900_node_label(node->right); + node->regs = node->right->regs | REG_1; + } else if (node->left->type == N_LOAD8) { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + } else { + cpu9900_node_label(node->left); + cpu9900_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_1; + } + } else if (node->type != N_XOR8 && node->type != N_AND8 && node->right->type == N_LOAD8) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + } else if (node->right->type == N_NUM8) { + cpu9900_node_label(node->left); + node->regs = node->left->regs | REG_1; + } else { + cpu9900_node_label(node->left); + cpu9900_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_1; + } + break; + case N_ASSIGN8: /* 8-bit assignment */ + if (node->right->type == N_ADDR) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + if ((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + cpu9900_node_label(node->left); + cpu9900_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_1; + break; + case N_ASSIGN16: /* 16-bit assignment */ + if (node->right->type == N_ADDR) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + if ((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + cpu9900_node_label(node->left); + cpu9900_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_1; + break; + default: /* Every other node, all remaining are 16-bit operations */ + /* Optimization of address plus/minus constant */ + if (node->type == N_PLUS16 || node->type == N_MINUS16) { + if (node->left->type == N_ADDR) { + if (node->right->type == N_NUM16) { + node->regs = REG_0; + break; + } + } + } + if (node->type == N_PLUS16) { + if (node->left->type == N_ADDR) { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + break; + } + if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { + if (node->left->type == N_NUM16) + explore = node->left; + else + explore = node->right; + if (node->left != explore) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + } + break; + } + } + if (node->type == N_EQUAL16 || node->type == N_NOTEQUAL16) { + if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { + int c; + + if (node->left->type == N_NUM16) + explore = node->left; + else + explore = node->right; + if (node->left != explore) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + } + break; + } + } + if (node->type == N_LESS16 || node->type == N_GREATER16) { + if (node->right->type == N_NUM16) { + int c; + + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + } + if (node->type == N_MINUS16) { + if (node->right->type == N_NUM16) + explore = node->right; + else + explore = NULL; + if (explore != NULL) { + int c = explore->value; + + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + } + if (node->type == N_OR16 || node->type == N_AND16 || node->type == N_XOR16) { + if (node->right->type == N_NUM16) + explore = node->right; + else + explore = NULL; + if (explore != NULL) { + int value = explore->value; + + if (node->left != explore) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + } + if ((node->type == N_OR16 || node->type == N_XOR16) && value == 0x00) { + } else if (node->type == N_AND16 && value == 0xffff) { + } else if (node->type == N_AND16 && value == 0x0000) { + } else if (node->type == N_OR16 && value == 0xffff) { + } else { + if (node->type == N_XOR16) + node->regs |= REG_1; + } + break; + } + } + if (node->type == N_MUL16) { + if (node->left->type == N_NUM16) + explore = node->left; + else if (node->right->type == N_NUM16) + explore = node->right; + else + explore = NULL; + if (explore != NULL && (explore->value == 0 || explore->value == 1 || is_power_of_two(explore->value))) { + int c = explore->value; + + if (c == 0) { + node->regs = REG_0; + } else { + if (node->left != explore) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + } + } + break; + } + } + if (node->type == N_DIV16) { + if (node->right->type == N_NUM16 && is_power_of_two(node->right->value)) { + cpu9900_node_label(node->left); + node->regs = node->left->regs; + break; + } + } + if (node->type == N_LESSEQUAL16 || node->type == N_GREATER16) { + if (node->left->type == N_LOAD16) { + cpu9900_node_label(node->right); + node->regs = node->right->regs; + } else { + cpu9900_node_label(node->left); + cpu9900_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_1; + } + } else if (node->type != N_AND16 && node->right->type == N_LOAD16) { + /* + ** Cannot be optimized: + ** o AND requires to invert the source operand (i.e alter the variable) + */ + cpu9900_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu9900_node_label(node->left); + cpu9900_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_1; + } + if (node->type == N_MUL16) { + node->regs |= REG_1; /* r1 * r0 => r0_r1 (32 bit) */ + } else if (node->type == N_DIV16) { + node->regs |= REG_1 | REG_2; /* r0_r1 / r2 => r0, rem r1 */ + } else if (node->type == N_MOD16) { + node->regs |= REG_1 | REG_2; /* r0_r1 / r2 => r0, rem r1 */ + } else if (node->type == N_DIV16S) { + node->regs |= REG_1 | REG_2 | REG_3; + } else if (node->type == N_MOD16S) { + node->regs |= REG_1 | REG_2; + } + break; + } } /* @@ -819,10 +1106,15 @@ void cpu9900_node_generate(struct node *node, int decision) node_get_label(node->left, ADDRESS); } else { cpu9900_node_generate(node->left, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->right, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if ((node->right->regs & REG_1) == 0) { + cpu9900_2op("mov", "r0", "r1"); + cpu9900_node_generate(node->right, 0); + } else { + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->right, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } strcpy(temp, "r1"); } } else if (node->type != N_XOR8 && node->type != N_AND8 && node->right->type == N_LOAD8) { @@ -843,10 +1135,15 @@ void cpu9900_node_generate(struct node *node, int decision) strcpy(temp, "r1"); } else { cpu9900_node_generate(node->right, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->left, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if ((node->left->regs & REG_1) == 0) { + cpu9900_2op("mov", "r0", "r1"); + cpu9900_node_generate(node->left, 0); + } else { + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->left, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } strcpy(temp, "r1"); } if (node->type == N_OR8) { @@ -982,10 +1279,15 @@ void cpu9900_node_generate(struct node *node, int decision) break; } cpu9900_node_generate(node->left, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->right, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if ((node->right->regs & REG_1) == 0) { + cpu9900_2op("mov", "r0", "r1"); + cpu9900_node_generate(node->right, 0); + } else { + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->right, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } cpu9900_2op("movb", "r1", "*r0"); break; case N_ASSIGN16: /* 16-bit assignment */ @@ -1012,10 +1314,15 @@ void cpu9900_node_generate(struct node *node, int decision) break; } cpu9900_node_generate(node->left, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->right, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if ((node->right->regs & REG_1) == 0) { + cpu9900_2op("mov", "r0", "r1"); + cpu9900_node_generate(node->right, 0); + } else { + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->right, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } cpu9900_2op("mov", "r1", "*r0"); break; default: /* Every other node, all remaining are 16-bit operations */ @@ -1110,17 +1417,17 @@ void cpu9900_node_generate(struct node *node, int decision) sprintf(temp, "@" INTERNAL_PREFIX "%d", decision); sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); if (node->type == N_LESS16) - cpu9900_1op("jlt", temp + 100); + cpu9900_1op("jl", temp + 100); else if (node->type == N_GREATER16) - cpu9900_1op("jgt", temp + 100); + cpu9900_1op("jh", temp + 100); cpu9900_1op("b", temp); cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); if (node->type == N_LESS16) - cpu9900_1op("jlt", temp); + cpu9900_1op("jl", temp); else if (node->type == N_GREATER16) - cpu9900_1op("jgt", temp); + cpu9900_1op("jh", temp); cpu9900_1op("clr", "r0"); cpu9900_1op("jmp", "$+4"); cpu9900_label(temp); @@ -1202,7 +1509,7 @@ void cpu9900_node_generate(struct node *node, int decision) if (c == 0) { cpu9900_1op("clr", "r0"); } else if (c == 1) { - // nothing to do + cpu9900_node_generate(node, 0); } else { int cnt; @@ -1241,10 +1548,15 @@ void cpu9900_node_generate(struct node *node, int decision) node_get_label(node->left, ADDRESS); } else { cpu9900_node_generate(node->left, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->right, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if ((node->right->regs & REG_1) == 0) { + cpu9900_2op("mov", "r0", "r1"); + cpu9900_node_generate(node->right, 0); + } else { + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->right, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } strcpy(temp, "r1"); } } else if (node->type != N_AND16 && node->right->type == N_LOAD16) { @@ -1261,10 +1573,15 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_2op("li", "r1", temp); } else { cpu9900_node_generate(node->right, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - cpu9900_node_generate(node->left, 0); - cpu9900_2op("mov", "*r10+", "r1"); + if ((node->left->regs & REG_1) == 0) { + cpu9900_2op("mov", "r0", "r1"); + cpu9900_node_generate(node->left, 0); + } else { + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + cpu9900_node_generate(node->left, 0); + cpu9900_2op("mov", "*r10+", "r1"); + } } strcpy(temp, "r1"); } diff --git a/cpu9900.h b/cpu9900.h index cb1f703..44dacfa 100644 --- a/cpu9900.h +++ b/cpu9900.h @@ -6,6 +6,17 @@ ** Creation date: Aug/20/2024. Separated from CVBasic.c */ +#define REG_0 0x01 +#define REG_1 0x02 +#define REG_2 0x04 +#define REG_3 0x08 +#define REG_4 0x10 +#define REG_5 0x20 +#define REG_6 0x40 +#define REG_7 0x80 + +#define REG_ALL (REG_0 | REG_1 | REG_2 | REG_3 | REG_4 | REG_5 | REG_6 | REG_7) + extern void cpu9900_dump(void); extern void cpu9900_label(char *); extern void cpu9900_empty(void); diff --git a/cpuz80.h b/cpuz80.h index 71add89..0929def 100644 --- a/cpuz80.h +++ b/cpuz80.h @@ -6,6 +6,22 @@ ** Creation date: Jul/31/2024. Separated from CVBasic.c */ +#define REG_A 0x01 +#define REG_F 0x02 +#define REG_B 0x04 +#define REG_C 0x08 +#define REG_D 0x10 +#define REG_E 0x20 +#define REG_H 0x40 +#define REG_L 0x80 + +#define REG_AF (REG_A | REG_F) +#define REG_BC (REG_B | REG_C) +#define REG_DE (REG_D | REG_E) +#define REG_HL (REG_H | REG_L) + +#define REG_ALL (REG_AF | REG_BC | REG_DE | REG_HL) + extern void cpuz80_dump(void); extern void cpuz80_label(char *); extern void cpuz80_empty(void); diff --git a/node.h b/node.h index 71c6622..64dbfad 100644 --- a/node.h +++ b/node.h @@ -35,22 +35,6 @@ enum node_type { N_USR, N_COMMA, }; -#define REG_A 0x01 -#define REG_F 0x02 -#define REG_B 0x04 -#define REG_C 0x08 -#define REG_D 0x10 -#define REG_E 0x20 -#define REG_H 0x40 -#define REG_L 0x80 - -#define REG_AF (REG_A | REG_F) -#define REG_BC (REG_B | REG_C) -#define REG_DE (REG_D | REG_E) -#define REG_HL (REG_H | REG_L) - -#define REG_ALL (REG_AF | REG_BC | REG_DE | REG_HL) - struct node { enum node_type type; int value; From 0e3d6983210dc27c9314b5f97636aa83b53920b1 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 22 Aug 2025 12:09:18 -0600 Subject: [PATCH 058/155] TMS9900 more optimization --- cpu9900.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cpu9900.c b/cpu9900.c index 15e8bbd..b3a4387 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -640,6 +640,14 @@ void cpu9900_node_label(struct node *node) case N_MINUS8: /* 8-bit - */ case N_MUL8: /* 8-bit * */ case N_DIV8: /* 8-bit / */ + if (node->type == N_PLUS8 && node->right->type == N_NUM8) { + cpu9900_node_label(node->left); + break; + } + if (node->type == N_MINUS8 && node->right->type == N_NUM8) { + cpu9900_node_label(node->left); + break; + } if (node->type == N_MUL8 && node->right->type == N_NUM8 && is_power_of_two(node->right->value)) { cpu9900_node_label(node->left); break; @@ -1061,6 +1069,24 @@ void cpu9900_node_generate(struct node *node, int decision) case N_MINUS8: /* 8-bit - */ case N_MUL8: /* 8-bit * */ case N_DIV8: /* 8-bit / */ + if (node->type == N_PLUS8 && node->right->type == N_NUM8) { + int value; + + cpu9900_node_generate(node->left, 0); + value = node->right->value; + sprintf(temp, "%d\t; %d", value * 256, value); + cpu9900_2op("ai", "r0", temp); + break; + } + if (node->type == N_MINUS8 && node->right->type == N_NUM8) { + int value; + + cpu9900_node_generate(node->left, 0); + value = -node->right->value & 0xff; + sprintf(temp, "%d\t; -%d", value * 256, node->right->value); + cpu9900_2op("ai", "r0", temp); + break; + } if (node->type == N_MUL8 && node->right->type == N_NUM8 && is_power_of_two(node->right->value)) { int c,cnt; From 00753a37096fe31d9d370269acecc1f1861ba937 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 22 Aug 2025 14:44:16 -0600 Subject: [PATCH 059/155] Solved bug where headers mixed --- cpu9900.c | 2 ++ cpu9900.h | 2 -- cpuz80.c | 2 ++ cpuz80.h | 2 -- cvbasic.c | 2 +- cvbasic.h | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpu9900.c b/cpu9900.c index b3a4387..00699e3 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -14,6 +14,8 @@ #include "node.h" #include "cpu9900.h" +#define REG_ALL (REG_0 | REG_1 | REG_2 | REG_3 | REG_4 | REG_5 | REG_6 | REG_7) + /* ** Conventions of register usage: ** r0-r3 Available for expression evaluation and support subroutines (div16s/mod16s) diff --git a/cpu9900.h b/cpu9900.h index 44dacfa..fe73b0c 100644 --- a/cpu9900.h +++ b/cpu9900.h @@ -15,8 +15,6 @@ #define REG_6 0x40 #define REG_7 0x80 -#define REG_ALL (REG_0 | REG_1 | REG_2 | REG_3 | REG_4 | REG_5 | REG_6 | REG_7) - extern void cpu9900_dump(void); extern void cpu9900_label(char *); extern void cpu9900_empty(void); diff --git a/cpuz80.c b/cpuz80.c index ba681ce..403d2d9 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -14,6 +14,8 @@ #include "node.h" #include "cpuz80.h" +#define REG_ALL (REG_AF | REG_BC | REG_DE | REG_HL) + static char z80_line[MAX_LINE_SIZE]; static char z80_line_1[MAX_LINE_SIZE]; diff --git a/cpuz80.h b/cpuz80.h index 0929def..64955fe 100644 --- a/cpuz80.h +++ b/cpuz80.h @@ -20,8 +20,6 @@ #define REG_DE (REG_D | REG_E) #define REG_HL (REG_H | REG_L) -#define REG_ALL (REG_AF | REG_BC | REG_DE | REG_HL) - extern void cpuz80_dump(void); extern void cpuz80_label(char *); extern void cpuz80_empty(void); diff --git a/cvbasic.c b/cvbasic.c index 2baf2f1..500bdaf 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -32,7 +32,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.0 Jul/19/2025" +#define VERSION "v0.9.0 Aug/22/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" diff --git a/cvbasic.h b/cvbasic.h index 2a7f11a..e149a00 100644 --- a/cvbasic.h +++ b/cvbasic.h @@ -33,8 +33,8 @@ enum supported_machine { TI994A, NABU, SMS, - NES, - TOTAL_TARGETS + TOTAL_TARGETS, + NES }; extern enum supported_machine machine; From 44c9419c26f4a9f8efc897199621ad13da268591 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 09:36:09 -0600 Subject: [PATCH 060/155] Added NES preliminary support. 32K ROM, CHRROM definition, controller support, and SPRITE --- README.md | 20 +- cvbasic.c | 266 ++++++++++++-- cvbasic.h | 4 +- cvbasic_nes_epilogue.asm | 6 + cvbasic_nes_prologue.asm | 701 ++++++++++++++++++++++++++++++++++++ examples/happy_face_nes.bas | 53 +++ 6 files changed, 1014 insertions(+), 36 deletions(-) create mode 100644 cvbasic_nes_epilogue.asm create mode 100644 cvbasic_nes_prologue.asm create mode 100644 examples/happy_face_nes.bas diff --git a/README.md b/README.md index 672c170..24747f6 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Later it was extended to support the following platforms: * Hanimex/Soundic Pencil II. * NABU PC. * Sega Master System (supporting bank switching with Sega mapper) +* NES/Famicom (preliminary, currently only CHRROM/SPRITE support) One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. @@ -63,6 +64,7 @@ The following files compose the compiler: examples/face_joystick_sms.bas Moving face with joystick (Sega Master System) examples/happy_face.bas Bouncing face. examples/happy_face_sms.bas Bouncing face (Sega Master System). + examples/happy_face_nes.bas Bouncing face (NES/Famicom). examples/music.bas Music example. examples/oscar_compressed.bas High-resolution graphics example compressed with Pletter. examples/oscar_compressed_sms.bas High-resolution graphics example compressed with Pletter (Sega Master System) @@ -108,6 +110,11 @@ Using CVBasic to compile a MSX program for 8K RAM (wider compatibility) and 16K cvbasic --msx -ram16 game.bas game.asm gasm80 game.asm -o game.rom + cvbasic --msx -ram16 -konami game.bas game.asm + gasm80 game.asm -o game.rom + +For bank-switched programs the default mapper is ASCII16, but you have the option of using a standard Konami 8K mapper using the -konami switch. + Using CVBasic to compile a Colecovision Super Game Module program: cvbasic --sgm game.bas game.asm @@ -185,6 +192,12 @@ Using CVBasic to compile a Sega Master System program: The -sms option of gasm80 will generate automatically a valid checksum so the game can run on a real console. +Using CVBasic to compile a NES/Famicom program: + + cvbasic --nes game.bas game.asm + gasm80 game.asm -o game.nes + + ### Notes The current official version is v0.8.0. @@ -195,8 +208,9 @@ All platforms have been tested in emulation. * Sega SG1000/SC3000 tested in real hardware by aotta. * Spectravideo SVI-318/328 tested in real hardware by Tony Cruise. * Creativision / Dick Smith's Wizzard tested in real hardware by Scouter3d. -* NABU tested in real hardware by Sektor. +* NABU tested in real hardware by Sektor and rietveld. * Sega Master System tested in real hardware and Sega Genesis/Megadrive by myself. +* TI-99/4A tested in real hardware by retroclouds. Untested: @@ -220,6 +234,8 @@ The TI-99/4A can only generate non-banked binaries up to 24 kb. When banking, th The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1 (<||| is the primary button and |||> is the secondary button), and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. +The NES support is highly experimental, currently only 32K ROM, CHRROM definition, SPRITE, and controller support are implemented (this is great if you want to make a silent game :P ) + Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) @@ -263,7 +279,7 @@ You can also get my book **Programming Games for Colecovision** including an int The foreword is written by the legendary David R. Megarry, programmer of Zaxxon™ for Colecovision, and creator of the Dungeon!™ Board game. -All the games in the book will compile for **all** the platforms (exception of Dungeon Warrior for Casio PV2000 because the small 16KB ROM size) +All the games in the book will compile for **all** the platforms (exception of Dungeon Warrior for Sord M5 and Casio PV2000 because the small 16KB ROM size) * [Programming Games for Colecovision, paperback, 250 pages](https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-colecovision/paperback/product-95qvzj8.html?page=1&pageSize=4) * [Programming Games for Colecovision, hardcover, 250 pages](https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-colecovision/hardcover/product-84nm767.html?page=1&pageSize=4) diff --git a/cvbasic.c b/cvbasic.c index 500bdaf..97fd472 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -32,7 +32,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.0 Aug/22/2025" +#define VERSION "v0.9.0 Aug/23/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -101,9 +101,9 @@ struct console consoles[TOTAL_TARGETS] = { {"sms", "", "Sega Master System (8K RAM)", "Sega Master System", 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, -/* {"nes", "", "NES/Famicom (2K RAM)", + {"nes", "", "NES/Famicom (2K RAM)", "NES/Famicom", - 0x0000, 0x00ff, 0x0800, 0, 0, 0, 1, CPU_6502},*/ + 0x0000, 0x00ff, 0x0800, 0, 0, 0, 1, CPU_6502}, }; static int err_code; @@ -234,6 +234,16 @@ static struct loop *loops; static unsigned char bitmap[128]; static int bitmap_byte; +/* + ** NES definitions + */ +#define CHRROM_PAGE 8192 + +int current_chrrom; +int chrrom_pointer; +int chrrom_size; +unsigned char *chrrom_data; + /* ** Prototypes */ @@ -3457,6 +3467,10 @@ void compile_statement(int check_for_else) int vram_read = 0; get_lex(); + if (machine == NES) { + emit_error("DEFINE isn't implemented for NES"); + break; + } if (lex != C_NAME) { emit_error("syntax error in DEFINE"); } else if (strcmp(name, "SPRITE") == 0) { @@ -3900,9 +3914,12 @@ void compile_statement(int check_for_else) else emit_error("missing comma in SPRITE"); type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_6502) - cpu6502_1op("STA", "sprite_data+1"); - else if (target == CPU_9900) + if (target == CPU_6502) { + if (machine == NES) + cpu6502_1op("STA", "sprite_data+3"); + else + cpu6502_1op("STA", "sprite_data+1"); + } else if (target == CPU_9900) cpu9900_2op("movb","r0","r6"); else cpuz80_1op("PUSH", "AF"); @@ -3912,9 +3929,12 @@ void compile_statement(int check_for_else) emit_error("missing comma in SPRITE"); type = evaluate_expression(1, TYPE_8, 0); if (machine != SMS) { - if (target == CPU_6502) - cpu6502_1op("STA", "sprite_data+2"); - else if (target == CPU_9900) + if (target == CPU_6502) { + if (machine == NES) + cpu6502_1op("STA", "sprite_data+1"); + else + cpu6502_1op("STA", "sprite_data+2"); + } else if (target == CPU_9900) cpu9900_2op("movb","r0","r7"); else cpuz80_1op("PUSH", "AF"); @@ -3924,7 +3944,10 @@ void compile_statement(int check_for_else) emit_error("missing comma in SPRITE"); type = evaluate_expression(1, TYPE_8, 0); if (target == CPU_6502) { - cpu6502_1op("STA", "sprite_data+3"); + if (machine == NES) + cpu6502_1op("STA", "sprite_data+2"); + else + cpu6502_1op("STA", "sprite_data+3"); cpu6502_noop("PLA"); } } @@ -3935,10 +3958,53 @@ void compile_statement(int check_for_else) get_lex(); if (lex != C_STRING ) { emit_error("syntax error in BITMAP"); - } else if (name_size == 16) { /* Sprites */ + } else if (name_size == 16) { /* 16x16 sprites */ int c; - if (machine == SMS) { + if (machine == NES) { + int first_time = 1; + + for (c = 0; c < 16; c++) { + if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ + && name[c] != 0x20 && name[c] != 0x2e) { /* space and . */ + int d; + + if (name[c] >= '0' && name[c] <= '3') { + d = name[c] - 0x30; + } else { + if (first_time) { + emit_warning("only 0-3 can be used in BITMAP"); + first_time = 0; + } + d = 0; + } + if (c < 8) { + value |= ((d & 1) << 7) >> c; + value |= ((d & 2) << 6) >> c << 8; + } else { + value |= ((d & 1) << 7) >> (c & 7) << 16; + value |= ((d & 2) << 6) >> (c & 7) << 24; + } + } + } + get_lex(); + if (current_chrrom == -1) { + emit_error("BITMAP used without setting pattern table"); + } else if (chrrom_pointer + 48 >= CHRROM_PAGE) { + emit_error("More than 512 patterns"); + } else { + c = current_chrrom * CHRROM_PAGE + chrrom_pointer; + chrrom_data[c] = value; + chrrom_data[c + 8] = value >> 8; + chrrom_data[c + 32] = value >> 16; + chrrom_data[c + 40] = value >> 24; + chrrom_pointer++; + if ((chrrom_pointer & 7) == 0) + chrrom_pointer += 8; + if ((chrrom_pointer & 31) == 0) + chrrom_pointer += 32; + } + } else if (machine == SMS) { int first_time = 1; value = 0; @@ -4037,7 +4103,40 @@ void compile_statement(int check_for_else) int c; value = 0; - if (machine == SMS) { + if (machine == NES) { + int first_time = 1; + + for (c = 0; c < 8; c++) { + if (name[c] != 0x30 && name[c] != 0x5f /* 0 and _ */ + && name[c] != 0x20 && name[c] != 0x2e) { /* space and . */ + int d; + + if (name[c] >= '0' && name[c] <= '3') { + d = name[c] - 0x30; + } else { + if (first_time) { + emit_warning("only 0-3 can be used in BITMAP"); + first_time = 0; + } + d = 0; + } + value |= ((d & 1) << 7) >> c; + value |= ((d & 2) << 6) >> c << 8; + } + } + get_lex(); + if (current_chrrom == -1) { + emit_error("BITMAP used without setting pattern table"); + } else if (chrrom_pointer == 8192) { + emit_error("More than 256 patterns"); + } else { + chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer] = c; + chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer + 8] = c; + chrrom_pointer++; + if ((chrrom_pointer & 7) == 0) + chrrom_pointer += 8; + } + } else if (machine == SMS) { int first_time = 1; for (c = 0; c < 8; c++) { @@ -4144,7 +4243,7 @@ void compile_statement(int check_for_else) get_lex(); if (machine != SMS) - emit_error("The SCROLL sentence is only available on Sega Master System"); + emit_error("SCROLL is only available on Sega Master System"); if (lex != C_COMMA) { type = evaluate_expression(1, TYPE_8, 0); if (machine == SMS) { @@ -4169,10 +4268,10 @@ void compile_statement(int check_for_else) } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System */ int type; struct node *source; - + get_lex(); if (machine != SMS) - emit_error("The PALETTE sentence is only available on Sega Master System"); + emit_error("PALETTE is only available on Sega Master System"); if (lex == C_NAME && strcmp(name, "LOAD") == 0) { get_lex(); if (lex != C_NAME) { @@ -4208,6 +4307,52 @@ void compile_statement(int check_for_else) } generic_interrupt_enable(); } + } else if (strcmp(name, "CHRROM") == 0) { /* Select CHRROM */ + int type; + struct node *tree; + int c; + + get_lex(); + if (strcmp(name, "PATTERN") == 0) { + get_lex(); + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("Not a constant expression in CHRROM"); + c = 0; + } else { + c = tree->value; + } + node_delete(tree); + if (c < 0 || c > 511) { + emit_error("CHRROM PATTERN out of range 0-511"); + c = 0; + } + chrrom_pointer = c * 16; + } else { + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("Not a constant expression in CHRROM"); + c = 0; + } else { + c = tree->value; + } + node_delete(tree); + if (c + 1 > chrrom_size) { /* Grow the CHRROM */ + unsigned char *p; + + p = realloc(chrrom_data, (c + 1) * CHRROM_PAGE); + if (p == NULL) { + emit_error("Not enough memory for CHRROM"); + break; + } + chrrom_data = p; + /* Reset pixel data in new space */ + memset(chrrom_data + chrrom_size * CHRROM_PAGE, 0, (c + 1 - chrrom_size) * CHRROM_PAGE); + chrrom_size = c + 1; + } + current_chrrom = c; + chrrom_pointer = 0; + } } else if (strcmp(name, "SIGNED") == 0) { struct signedness *c; @@ -4309,9 +4454,10 @@ void compile_statement(int check_for_else) tree = evaluate_level_0(&type); if (tree->type != N_NUM8 && tree->type != N_NUM16) { emit_error("not a constant expression in DIM"); - break; + c = 10; + } else { + c = tree->value; } - c = tree->value; node_delete(tree); if (lex != C_RPAREN) { emit_error("missing right parenthesis in DIM"); @@ -5464,6 +5610,7 @@ void compile_statement(int check_for_else) tree = evaluate_level_0(&type); if (tree->type != N_NUM8 && tree->type != N_NUM16) { emit_error("not a constant expression in BANK SELECT"); + node_delete(tree); break; } c = tree->value; @@ -5539,6 +5686,7 @@ void compile_statement(int check_for_else) tree = evaluate_level_0(&type); if (tree->type != N_NUM8 && tree->type != N_NUM16) { emit_error("not a constant expression in BANK"); + node_delete(tree); break; } c = tree->value; @@ -5680,6 +5828,9 @@ void compile_basic(void) generic_dump(); fprintf(output, "\t; %s\n", line); + /* For debugging purposes */ +/* fprintf(stderr, "%s\n", line);*/ + line_start = 1; line_pos = 0; label_exists = 0; @@ -5826,18 +5977,34 @@ int process_variables(void) } if (label->used & LABEL_IS_VARIABLE) { if (target == CPU_6502) { - if ((label->used & MAIN_TYPE) == TYPE_8) { - if (address < 0x0200 && address + 1 > 0x0140) - address = 0x0200; - sprintf(temp, "%s%s:\tequ $%04x", LABEL_PREFIX, label->name, address); - address++; - bytes_used++; + if (machine == NES) { + if ((label->used & MAIN_TYPE) == TYPE_8) { + if (address < 0x0300 && address + 1 > 0x0140) + address = 0x0300; + sprintf(temp, "%s%s:\tequ $%04x", LABEL_PREFIX, label->name, address); + address++; + bytes_used++; + } else { + if (address < 0x0300 && address + 2 > 0x0140) + address = 0x0300; + sprintf(temp, "%s%s:\tequ $%04x", LABEL_PREFIX, label->name, address); + address += 2; + bytes_used += 2; + } } else { - if (address < 0x0200 && address + 2 > 0x0140) - address = 0x0200; - sprintf(temp, "%s%s:\tequ $%04x", LABEL_PREFIX, label->name, address); - address += 2; - bytes_used += 2; + if ((label->used & MAIN_TYPE) == TYPE_8) { + if (address < 0x0200 && address + 1 > 0x0140) + address = 0x0200; + sprintf(temp, "%s%s:\tequ $%04x", LABEL_PREFIX, label->name, address); + address++; + bytes_used++; + } else { + if (address < 0x0200 && address + 2 > 0x0140) + address = 0x0200; + sprintf(temp, "%s%s:\tequ $%04x", LABEL_PREFIX, label->name, address); + address += 2; + bytes_used += 2; + } } fprintf(output, "%s\n", temp); } else if (target == CPU_9900) { @@ -6073,9 +6240,9 @@ int main(int argc, char *argv[]) } } - /* - ** Passed-in constants - */ + /* + ** Passed-in constants + */ while (argv[c][0] == '-' && tolower(argv[c][1]) == 'd') { int i = 1; char ch = 0; @@ -6112,6 +6279,9 @@ int main(int argc, char *argv[]) c++; } + /* + ** Here is compiled the source code and generates a temporary assembler file. + */ strcpy(current_file, argv[c]); err_code = 0; input = fopen(current_file, "r"); @@ -6131,6 +6301,12 @@ int main(int argc, char *argv[]) option_warnings = 1; inside_proc = NULL; frame_drive = NULL; + + current_chrrom = -1; /* Only NES */ + chrrom_pointer = 0; /* Only NES */ + chrrom_size = 0; /* Only NES */ + chrrom_data = NULL; /* Only NES */ + compile_basic(); if (loops != NULL) emit_error("End of source with control block still open"); @@ -6146,6 +6322,9 @@ int main(int argc, char *argv[]) fclose(input); fclose(output); + /* + ** Now build the real output (prologue + compiled program + epilogue) + */ output = fopen(argv[c], "w"); if (output == NULL) { fprintf(stderr, "Couldn't open '%s' output file.\n", argv[2]); @@ -6202,6 +6381,10 @@ int main(int argc, char *argv[]) fprintf(output, "TI99:\tequ %d\n", (machine == TI994A) ? 1 : 0); fprintf(output, "NABU:\tequ %d\n", (machine == NABU) ? 1 : 0); fprintf(output, "SMS:\tequ %d\n", (machine == SMS) ? 1 : 0); + if (machine == NES) { + fprintf(output, "NES_PRG_BANKS:\tequ 2\t; Each one 16K.\n"); + fprintf(output, "NES_CHR_BANKS:\tequ %d\t; Each one 4K.\n", chrrom_size); + } fprintf(output, "\n"); fprintf(output, "CVBASIC_MUSIC_PLAYER:\tequ %d\n", music_used); fprintf(output, "CVBASIC_COMPRESSION:\tequ %d\n", compression_used); @@ -6317,7 +6500,26 @@ int main(int argc, char *argv[]) if (target == CPU_Z80 || target == CPU_9900) { bytes_used = process_variables(); } + + /* + ** NES CHRROM output + */ + if (machine == NES) { + fprintf(output, "\n; CHR data\n"); + for (c = 0; c < chrrom_size * CHRROM_PAGE; c += 8) { + fprintf(output, "\tdb $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", + chrrom_data[c], chrrom_data[c + 1], + chrrom_data[c + 2], chrrom_data[c + 3], + chrrom_data[c + 4], chrrom_data[c + 5], + chrrom_data[c + 6], chrrom_data[c + 7]); + } + free(chrrom_data); + } fclose(output); + + /* + ** Final reports + */ if (machine == MEMOTECH || machine == EINSTEIN || machine == NABU) { fprintf(stderr, "%d RAM bytes used for variables.\n", bytes_used); } else { diff --git a/cvbasic.h b/cvbasic.h index e149a00..2a7f11a 100644 --- a/cvbasic.h +++ b/cvbasic.h @@ -33,8 +33,8 @@ enum supported_machine { TI994A, NABU, SMS, - TOTAL_TARGETS, - NES + NES, + TOTAL_TARGETS }; extern enum supported_machine machine; diff --git a/cvbasic_nes_epilogue.asm b/cvbasic_nes_epilogue.asm new file mode 100644 index 0000000..63be4b0 --- /dev/null +++ b/cvbasic_nes_epilogue.asm @@ -0,0 +1,6 @@ +rom_end: + times $fffa-$ db $ff + + dw nmi_handler + dw START + dw irq_handler diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm new file mode 100644 index 0000000..2e049ba --- /dev/null +++ b/cvbasic_nes_prologue.asm @@ -0,0 +1,701 @@ + ; + ; CVBasic prologue (BASIC compiler, 6502 target) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: May/13/2025. + ; Revision date: Jul/20/2025. Added code to load sprites and read controllers. + ; + + CPU 6502 + + ; + ; Platforms supported: + ; o NES/Famicom + ; + + ; + ; CVBasic variables in zero page. + ; + + ; This is a block of 8 bytes that should stay together. +temp: equ $02 +temp2: equ $04 +result: equ $06 +pointer: equ $08 + +read_pointer: equ $0a +cursor: equ $0c +ppu_pointer: equ $0e + +joy1_data: equ $20 +joy2_data: equ $21 +key1_data: equ $22 +key2_data: equ $23 +frame: equ $24 +lfsr: equ $26 +mode: equ $28 +cont_bits: equ $29 +sprite_data: equ $2a +ntsc: equ $2e +vdp_status: equ $30 + + IF CVBASIC_MUSIC_PLAYER +music_playing: EQU $4f +music_timing: EQU $31 +music_start: EQU $32 +music_pointer: EQU $34 +music_note_counter: EQU $36 +music_instrument_1: EQU $37 +music_note_1: EQU $38 +music_counter_1: EQU $39 +music_instrument_2: EQU $3a +music_note_2: EQU $3b +music_counter_2: EQU $3c +music_instrument_3: EQU $3d +music_note_3: EQU $3e +music_counter_3: EQU $3f +music_drum: EQU $40 +music_counter_4: EQU $41 +audio_freq1: EQU $42 +audio_freq2: EQU $44 +audio_freq3: EQU $46 +audio_vol1: EQU $48 +audio_vol2: EQU $49 +audio_vol3: EQU $4a +audio_vol4hw: EQU $4b +audio_noise: EQU $4c +audio_control: EQU $4d +music_mode: EQU $4e + ENDIF + +SPRITE_PAGE: EQU $02 + + FORG $0000 + ; The ORG address doesn't matter here + ; iNES cartridge header + DB "NES",$1A + DB NES_PRG_BANKS + DB NES_CHR_BANKS + DB $00 ; Cartridge type LSB !!! + DB $00 ; Cartridge type MSB !!! + DB $00 ; Number of 8K RAM pages. + DB $00,$00,$00,$00,$00,$00,$00 ; Reserved + + FORG $0010 + ORG $8000 + +PPUCTRL: EQU $2000 +PPUMASK: EQU $2001 +PPUSTATUS: EQU $2002 +OAMADDR: EQU $2003 +PPUSCROLL: EQU $2005 +PPUADDR: EQU $2006 +PPUDATA: EQU $2007 +SPRRAM: EQU $4014 +CONT1: EQU $4016 +CONT2: EQU $4017 + +update_sprite: + ASL A + ASL A + STA pointer + LDA #SPRITE_PAGE + STA pointer+1 + LDY #0 + LDA sprite_data+0 + STA (pointer),Y + INY + LDA sprite_data+1 + STA (pointer),Y + INY + LDA sprite_data+2 + STA (pointer),Y + INY + LDA sprite_data+3 + STA (pointer),Y + RTS + +_abs16: + PHA + TYA + BPL _neg16.1 + PLA +_neg16: + EOR #$FF + CLC + ADC #1 + PHA + TYA + EOR #$FF + ADC #0 + TAY +.1: + PLA + RTS + +_sgn16: + STY temp + ORA temp + BEQ .1 + TYA + BMI .2 + LDA #0 + TAY + LDA #1 + RTS + +.2: LDA #$FF +.1: TAY + RTS + +_read16: + JSR _read8 + PHA + JSR _read8 + TAY + PLA + RTS + +_read8: + LDY #0 + LDA (read_pointer),Y + INC read_pointer + BNE .1 + INC read_pointer+1 +.1: + RTS + +_peek8: + STA pointer + STY pointer+1 + LDY #0 + LDA (pointer),Y + RTS + +_peek16: + STA pointer + STY pointer+1 + LDY #0 + LDA (pointer),Y + PHA + INY + LDA (pointer),Y + TAY + PLA + RTS + + ; temp2 contains left side (dividend) + ; temp contains right side (divisor) + + ; 16-bit multiplication. +_mul16: + PLA + STA result + PLA + STA result+1 + PLA + STA temp2+1 + PLA + STA temp2 + LDA result+1 + PHA + LDA result + PHA + LDA #0 + STA result + STA result+1 + LDX #15 +.1: + LSR temp2+1 + ROR temp2 + BCC .2 + LDA result + CLC + ADC temp + STA result + LDA result+1 + ADC temp+1 + STA result+1 +.2: ASL temp + ROL temp+1 + DEX + BPL .1 + LDA result + LDY result+1 + RTS + + ; 16-bit signed modulo. +_mod16s: + PLA + STA result + PLA + STA result+1 + PLA + STA temp2+1 + PLA + STA temp2 + LDA result+1 + PHA + LDA result + PHA + LDY temp2+1 + PHP + BPL .1 + LDA temp2 + JSR _neg16 + STA temp2 + STY temp2+1 +.1: + LDY temp+1 + BPL .2 + LDA temp + JSR _neg16 + STA temp + STY temp+1 +.2: + JSR _mod16.1 + PLP + BPL .3 + JMP _neg16 +.3: + RTS + + ; 16-bit signed division. +_div16s: + PLA + STA result + PLA + STA result+1 + PLA + STA temp2+1 + PLA + STA temp2 + LDA result+1 + PHA + LDA result + PHA + LDA temp+1 + EOR temp2+1 + PHP + LDY temp2+1 + BPL .1 + LDA temp2 + JSR _neg16 + STA temp2 + STY temp2+1 +.1: + LDY temp+1 + BPL .2 + LDA temp + JSR _neg16 + STA temp + STY temp+1 +.2: + JSR _div16.1 + PLP + BPL .3 + JMP _neg16 +.3: + RTS + +_div16: + PLA + STA result + PLA + STA result+1 + PLA + STA temp2+1 + PLA + STA temp2 + LDA result+1 + PHA + LDA result + PHA +.1: + LDA #0 + STA result + STA result+1 + LDX #15 +.2: + ROL temp2 + ROL temp2+1 + ROL result + ROL result+1 + LDA result + SEC + SBC temp + STA result + LDA result+1 + SBC temp+1 + STA result+1 + BCS .3 + LDA result + ADC temp + STA result + LDA result+1 + ADC temp+1 + STA result+1 + CLC +.3: + DEX + BPL .2 + ROL temp2 + ROL temp2+1 + LDA temp2 + LDY temp2+1 + RTS + +_mod16: + PLA + STA result + PLA + STA result+1 + PLA + STA temp2+1 + PLA + STA temp2 + LDA result+1 + PHA + LDA result + PHA +.1: + LDA #0 + STA result + STA result+1 + LDX #15 +.2: + ROL temp2 + ROL temp2+1 + ROL result + ROL result+1 + LDA result + SEC + SBC temp + STA result + LDA result+1 + SBC temp+1 + STA result+1 + BCS .3 + LDA result + ADC temp + STA result + LDA result+1 + ADC temp+1 + STA result+1 + CLC +.3: + DEX + BPL .2 + LDA result + LDY result+1 + RTS + + ; Random number generator. + ; From my game Mecha Eight. +random: + LDA lfsr + ORA lfsr+1 + BNE .0 + LDA #$11 + STA lfsr + LDA #$78 + STA lfsr+1 +.0: LDA lfsr+1 + ROR A + ROR A + ROR A + EOR lfsr+1 + STA temp + LDA lfsr+1 + ROR A + ROR A + EOR temp + STA temp + LDA lfsr + ASL A + ASL A + EOR temp + ROL A + ROR lfsr+1 + ROR lfsr + LDA lfsr + LDY lfsr+1 + RTS + +irq_handler: + RTI + +nmi_handler: + PHA + TXA + PHA + TYA + PHA + + LDA PPUSTATUS ; VDP interruption clear. + STA vdp_status + + LDA #$00 ; !!! Can be used for flicker + STA OAMADDR + LDA #SPRITE_PAGE + STA SPRRAM + + LDX #$00 + CPX ppu_pointer + BEQ .1 + LDA $0100,X + STA PPUADDR + LDA $0101,X + STA PPUADDR + LDA $0102 + +.1: + + LDA #$01 + STA CONT1 + LDA #$00 + STA CONT1 + LDX #$08 + LDA CONT1 + ROR A + ROL cont_bits + DEX + BNE $-7 + LDA cont_bits + JSR convert_joystick + STA joy1_data + STX key1_data + + LDX #$08 + LDA CONT2 + ROR A + ROL cont_bits + DEX + BNE $-7 + LDA cont_bits + JSR convert_joystick + STA joy2_data + STX key2_data + + if CVBASIC_MUSIC_PLAYER + LDA music_mode + BEQ .10 + JSR music_hardware +.10: + endif + INC frame + BNE .8 + INC frame+1 +.8: + INC lfsr ; Make LFSR more random + INC lfsr + INC lfsr + if CVBASIC_MUSIC_PLAYER + LDA music_mode + BEQ .9 + JSR music_generate +.9: + endif + ; This is like saving extra registers, because these + ; are used by the compiled code, and we don't want + ; any reentrancy. + LDA temp+0 + PHA + LDA temp+1 + PHA + LDA temp+2 + PHA + LDA temp+3 + PHA + LDA temp+4 + PHA + LDA temp+5 + PHA + LDA temp+6 + PHA + LDA temp+7 + PHA + + ;CVBASIC MARK DON'T CHANGE + PLA + STA temp+7 + PLA + STA temp+6 + PLA + STA temp+5 + PLA + STA temp+4 + PLA + STA temp+3 + PLA + STA temp+2 + PLA + STA temp+1 + PLA + STA temp+0 + + LDA #0 + STA PPUADDR + STA PPUADDR + STA PPUSCROLL + STA PPUSCROLL + + PLA + TAY + PLA + TAX + PLA + RTI + +convert_joystick: + LDA #0 + LDX #15 + ROR cont_bits + BCS $+4 + ORA #2 + ROR cont_bits + BCS $+4 + ORA #8 + ROR cont_bits + BCS $+4 + ORA #4 + ROR cont_bits + BCS $+4 + ORA #1 + ROR cont_bits + BCS $+4 + LDX #11 + ROR cont_bits + BCS $+4 + LDX #10 + ROR cont_bits + BCS $+4 + ORA #$40 + ROR cont_bits + BCS $+4 + ORA #$80 + RTS + +wait: + LDA frame +.1: CMP frame + BEQ .1 + RTS + +music_init: + RTS + +music_play: + RTS + +music_generate: + RTS + +music_hardware: + RTS + +START: + SEI + CLD + + BIT PPUSTATUS + + LDA #$40 + STA $4017 + LDA #$00 + STA $4015 + STA $4010 + + STA PPUCTRL + STA PPUMASK + + TAX +.1: STA $00,X + STA $0100,X + STA $0200,X + STA $0300,X + STA $0400,X + STA $0500,X + STA $0600,X + STA $0700,X + INX + BNE .1 + + LDX #STACK + TXS + + ; + ; The NES starts with the PPU registers write-protected. + ; Around 29000 cycles must happen before these can be written. + ; + + BIT PPUSTATUS + BPL $-3 + ; About 27384 cycles passed at this time. + BIT PPUSTATUS + BPL $-3 + ; About 57165 cycles passed at this time. + + ; Clear 2K of pattern memory + LDA #$20 + STA PPUADDR + LDA #$00 + STA PPUADDR + LDX #$78 + LDA #$20 +.2: + STA PPUDATA + STA PPUDATA + STA PPUDATA + STA PPUDATA + STA PPUDATA + STA PPUDATA + STA PPUDATA + STA PPUDATA + DEX + BNE .2 + + LDX #$40 + LDA #$00 +.3: STA PPUDATA + DEX + BNE .3 + + ; Setup base palette + LDA #$3F + STA PPUADDR + LDA #$00 + STA PPUADDR + LDX #8 +.4: + LDA #$0F ; Black + STA PPUDATA + LDA #$35 ; Red + STA PPUDATA + LDA #$3A ; Green + STA PPUDATA + LDA #$30 ; White + STA PPUDATA + DEX + BNE .4 + + BIT PPUSTATUS + BPL $-3 + LDA #$1e ; Color normal, Sprites visible, Background visible, No clipping, Color. + STA PPUMASK + LDA #$A8 ; Enable NMI, 8x16 sprites, BG=$0000, SPR=$1000, NAME=$2000 + STA PPUCTRL + + JSR music_init + +; JSR mode_0 + + LDA #$00 + STA joy1_data + STA joy2_data + LDA #$0F + STA key1_data + STA key2_data + diff --git a/examples/happy_face_nes.bas b/examples/happy_face_nes.bas new file mode 100644 index 0000000..2d6aab0 --- /dev/null +++ b/examples/happy_face_nes.bas @@ -0,0 +1,53 @@ + ' + ' Bouncing happy face (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Feb/28/2024. + ' Revision date: Aug/23/2025. Adapted for NES. + ' + +' DEFINE SPRITE 0,1,happy_face + +' PRINT AT 36,"Happy face!" + + x = 50 + y = 100 + dx = 1 + dy = 1 + +game_loop: + WAIT + WAIT + SPRITE 0,y-1,x,1,0 + SPRITE 1,y-1,x + 8,3,0 + + x = x + dx + IF x = 0 THEN dx = -dx + IF x = 240 THEN dx = -dx + y = y + dy + IF y = 0 THEN dy = -dy + IF y = 176 THEN dy = -dy + GOTO game_loop + + CHRROM 0 + + CHRROM PATTERN 256 + + BITMAP "......3333......" + BITMAP "....33333333...." + BITMAP "...3333333333..." + BITMAP "..333333333333.." + BITMAP ".33333333333333." + BITMAP ".33333333333333." + BITMAP "3333..3333..3333" + BITMAP "3333..3333..3333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP ".33333333333333." + BITMAP ".333..3333..333." + BITMAP "..333......333.." + BITMAP "...333....333..." + BITMAP "....33333333...." + BITMAP "......3333......" From 2749fc83f27665a1cca1ec264d040720d5f1562e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 10:37:22 -0600 Subject: [PATCH 061/155] NES added support for sprite flicker and pipelined writing --- cvbasic_nes_prologue.asm | 71 +++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 2e049ba..61be07a 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -19,6 +19,7 @@ ; CVBasic variables in zero page. ; +ppu_source: equ $00 ; Used in NMI for source address for PPU copy ; This is a block of 8 bytes that should stay together. temp: equ $02 temp2: equ $04 @@ -28,6 +29,7 @@ pointer: equ $08 read_pointer: equ $0a cursor: equ $0c ppu_pointer: equ $0e +ppu_temp: equ $0f ; Used in NMI to save X joy1_data: equ $20 joy2_data: equ $21 @@ -39,6 +41,7 @@ mode: equ $28 cont_bits: equ $29 sprite_data: equ $2a ntsc: equ $2e +flicker: equ $2f vdp_status: equ $30 IF CVBASIC_MUSIC_PLAYER @@ -437,22 +440,73 @@ nmi_handler: LDA PPUSTATUS ; VDP interruption clear. STA vdp_status - LDA #$00 ; !!! Can be used for flicker + ; Load sprites + LDA mode + AND #4 ; Flicker enabled? + BNE .5 ; No, jump. + LDA flicker + CLC + ADC #28 + STA flicker + JMP .6 +.5: + LDA #$00 +.6: STA OAMADDR LDA #SPRITE_PAGE - STA SPRRAM + STA SPRRAM ; Use DMA for sprite loading + ; Screen changes LDX #$00 - CPX ppu_pointer - BEQ .1 + CPX ppu_pointer ; Any change? + BEQ .1 ; No, jump. +.0: LDA $0101,X + STA PPUADDR + BMI .2 LDA $0100,X STA PPUADDR - LDA $0101,X + LDA $0103,X + STA ppu_source + LDA $0104,X + STA ppu_source+1 + LDY $0102,X + STX ppu_temp + LDX #0 +.4: + LDA ppu_source,X + STA PPUDATA + INX + DEY + BNE .4 + LDA ppu_temp + CLC + ADC #5 + TAX + CPX ppu_pointer + BNE .0 + JMP .1 + + ; Filling data +.2: + LDA $0100,X STA PPUADDR - LDA $0102 + LDY $0102,X + LDA $0103,X +.3: + STA PPUDATA + DEY + BNE .3 + TXA + CLC + ADC #4 + TAX + CPX ppu_pointer + BNE .0 -.1: +.1: LDA #0 + STA ppu_pointer + ; Read controllers LDA #$01 STA CONT1 LDA #$00 @@ -536,10 +590,11 @@ nmi_handler: PLA STA temp+0 + ; Final settings for PPU LDA #0 STA PPUADDR STA PPUADDR - STA PPUSCROLL + STA PPUSCROLL ; !!! For scrolling STA PPUSCROLL PLA From 7e290a14f04f49b213a7668cc7d864d5f0d10ce7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 11:29:47 -0600 Subject: [PATCH 062/155] NES added support for PALETTE --- cvbasic.c | 49 +++++++++++++++++++---- cvbasic_nes_prologue.asm | 68 ++++++++++++++++--------------- examples/controller_nes.bas | 63 +++++++++++++++++++++++++++++ examples/face_joystick_nes.bas | 73 ++++++++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+), 39 deletions(-) create mode 100644 examples/controller_nes.bas create mode 100644 examples/face_joystick_nes.bas diff --git a/cvbasic.c b/cvbasic.c index 97fd472..21170cf 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -103,7 +103,7 @@ struct console consoles[TOTAL_TARGETS] = { 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, {"nes", "", "NES/Famicom (2K RAM)", "NES/Famicom", - 0x0000, 0x00ff, 0x0800, 0, 0, 0, 1, CPU_6502}, + 0x0050, 0x01ff, 0x0800, 0, 0, 0, 1, CPU_6502}, }; static int err_code; @@ -4130,8 +4130,8 @@ void compile_statement(int check_for_else) } else if (chrrom_pointer == 8192) { emit_error("More than 256 patterns"); } else { - chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer] = c; - chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer + 8] = c; + chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer] = value; + chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer + 8] = value >> 8; chrrom_pointer++; if ((chrrom_pointer & 7) == 0) chrrom_pointer += 8; @@ -4270,8 +4270,8 @@ void compile_statement(int check_for_else) struct node *source; get_lex(); - if (machine != SMS) - emit_error("PALETTE is only available on Sega Master System"); + if (machine != SMS && machine != NES) + emit_error("PALETTE is only available on Sega Master System and NES/Famicom"); if (lex == C_NAME && strcmp(name, "LOAD") == 0) { get_lex(); if (lex != C_NAME) { @@ -4285,17 +4285,41 @@ void compile_statement(int check_for_else) strcpy(temp, LABEL_PREFIX); strcat(temp, name); cpuz80_2op("LD", "HL", temp); + generic_call("palette_load"); + } else if (machine == NES) { + cpu6502_1op("LDX", "ppu_pointer"); + cpu6502_1op("LDA", "#$00"); + cpu6502_1op("STA", "PPUBUF,X"); + cpu6502_1op("LDA", "#$3f"); + cpu6502_1op("STA", "PPUBUF+1,X"); + cpu6502_1op("LDA", "#32"); + cpu6502_1op("STA", "PPUBUF+2,X"); + strcpy(temp, "#" LABEL_PREFIX); + strcat(temp, name); + cpu6502_1op("LDA", temp); + cpu6502_1op("STA", "PPUBUF+3,X"); + strcat(temp, ">>8"); + cpu6502_1op("LDA", temp); + cpu6502_1op("STA", "PPUBUF+4,X"); + cpu6502_noop("TXA"); + cpu6502_noop("CLC"); + cpu6502_1op("ADC", "#5"); + cpu6502_1op("STA", "ppu_pointer"); } get_lex(); } - generic_call("palette_load"); } else { - generic_interrupt_disable(); type = evaluate_expression(1, TYPE_8, 0); if (machine == SMS) { + generic_interrupt_disable(); cpuz80_2op("LD", "L", "A"); cpuz80_2op("LD", "H", "$C0"); cpuz80_1op("CALL", "SETWRT"); + } else if (machine == NES) { + cpu6502_1op("LDX", "ppu_pointer"); + cpu6502_1op("STA", "PPUBUF,X"); + cpu6502_1op("LDA", "#$bf"); + cpu6502_1op("STA", "PPUBUF+1,X"); } if (lex != C_COMMA) emit_error("missing comma in PALETTE"); @@ -4304,8 +4328,17 @@ void compile_statement(int check_for_else) type = evaluate_expression(1, TYPE_8, 0); if (machine == SMS) { cpuz80_2op("OUT", "(VDP)", "A"); + generic_interrupt_enable(); + } else if (machine == NES) { + cpu6502_1op("LDX", "ppu_pointer"); + cpu6502_1op("STA", "PPUBUF+3,X"); + cpu6502_1op("LDA", "#1"); + cpu6502_1op("STA", "PPUBUF+2,X"); + cpu6502_noop("TXA"); + cpu6502_noop("CLC"); + cpu6502_1op("ADC", "#4"); + cpu6502_1op("STA", "ppu_pointer"); } - generic_interrupt_enable(); } } else if (strcmp(name, "CHRROM") == 0) { /* Select CHRROM */ int type; diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 61be07a..811bae2 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -74,6 +74,7 @@ music_mode: EQU $4e ENDIF SPRITE_PAGE: EQU $02 +PPUBUF: EQU $0100 FORG $0000 ; The ORG address doesn't matter here @@ -460,23 +461,24 @@ nmi_handler: LDX #$00 CPX ppu_pointer ; Any change? BEQ .1 ; No, jump. -.0: LDA $0101,X +.0: LDA PPUBUF+1,X STA PPUADDR BMI .2 - LDA $0100,X + LDA PPUBUF,X STA PPUADDR - LDA $0103,X + LDA PPUBUF+3,X STA ppu_source - LDA $0104,X + LDA PPUBUF+4,X STA ppu_source+1 - LDY $0102,X + LDA PPUBUF+2,X STX ppu_temp - LDX #0 + TAX + LDY #0 .4: - LDA ppu_source,X + LDA (ppu_source),Y STA PPUDATA - INX - DEY + INY + DEX BNE .4 LDA ppu_temp CLC @@ -488,10 +490,10 @@ nmi_handler: ; Filling data .2: - LDA $0100,X + LDA PPUBUF,X STA PPUADDR - LDY $0102,X - LDA $0103,X + LDY PPUBUF+2,X + LDA PPUBUF+3,X .3: STA PPUDATA DEY @@ -509,26 +511,30 @@ nmi_handler: ; Read controllers LDA #$01 STA CONT1 - LDA #$00 + STA cont_bits + LSR A STA CONT1 - LDX #$08 + LDA CONT1 - ROR A + LSR A ROL cont_bits - DEX - BNE $-7 - LDA cont_bits + BCC $-6 + JSR convert_joystick STA joy1_data STX key1_data - LDX #$08 + LDA #$01 + STA CONT1 + STA cont_bits + LSR A + STA CONT1 + LDA CONT2 - ROR A + LSR A ROL cont_bits - DEX - BNE $-7 - LDA cont_bits + BCC $-6 + JSR convert_joystick STA joy2_data STX key2_data @@ -608,28 +614,28 @@ convert_joystick: LDA #0 LDX #15 ROR cont_bits - BCS $+4 + BCC $+4 ORA #2 ROR cont_bits - BCS $+4 + BCC $+4 ORA #8 ROR cont_bits - BCS $+4 + BCC $+4 ORA #4 ROR cont_bits - BCS $+4 + BCC $+4 ORA #1 ROR cont_bits - BCS $+4 + BCC $+4 LDX #11 ROR cont_bits - BCS $+4 + BCC $+4 LDX #10 ROR cont_bits - BCS $+4 + BCC $+4 ORA #$40 ROR cont_bits - BCS $+4 + BCC $+4 ORA #$80 RTS diff --git a/examples/controller_nes.bas b/examples/controller_nes.bas new file mode 100644 index 0000000..f4a2601 --- /dev/null +++ b/examples/controller_nes.bas @@ -0,0 +1,63 @@ + ' + ' Controller bits (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Aug/23/2025. + ' Revision date: Aug/23/2025. Adapted for NES. + ' + +game_loop: + WAIT + c = CONT1 + + SPRITE 16, 24, 8, (c AND $80) / 128 * 2, 0 + SPRITE 17, 24, 16, (c AND $40) / 64 * 2, 0 + SPRITE 18, 24, 24, (c AND $20) / 32 * 2, 0 + SPRITE 19, 24, 32, (c AND $10) / 16 * 2, 0 + SPRITE 20, 24, 40, (c AND $08) / 8 * 2, 0 + SPRITE 21, 24, 48, (c AND $04) / 4 * 2, 0 + SPRITE 22, 24, 56, (c AND $02) / 2 * 2, 0 + SPRITE 23, 24, 64, (c AND $01) / 1 * 2, 0 + + GOTO game_loop + + CHRROM 0 + + CHRROM PATTERN 0 + + BITMAP "..3333.." + BITMAP ".33..33." + BITMAP ".33..33." + BITMAP ".33..33." + BITMAP ".33..33." + BITMAP ".33..33." + BITMAP ".33..33." + BITMAP "..3333.." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "...33..." + BITMAP "..333..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "..3333.." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + diff --git a/examples/face_joystick_nes.bas b/examples/face_joystick_nes.bas new file mode 100644 index 0000000..e7f383a --- /dev/null +++ b/examples/face_joystick_nes.bas @@ -0,0 +1,73 @@ + ' + ' Joystick moving with joystick (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Mar/03/2024. + ' Revision date: Aug/23/2025. Adapted for NES. + ' + +' DEFINE SPRITE 0,1,happy_face + +' PRINT AT 36,"Happy face!" + + PALETTE LOAD full_palette + + x = 50 + y = 100 + + SPRITE 2, 96, 128, 1, 3 + SPRITE 3, 96, 136, 3, 3 + +game_loop: + WAIT + PALETTE 31, (FRAME / 16) + $30 + +' PRINT AT 0, "VDP.STATUS = ", <>VDP.STATUS , " " + + SPRITE 0, y - 1, x, 1, face_palette + SPRITE 1, y - 1, x + 8, 3, face_palette + + IF FRAME AND 1 THEN + face_palette = 0 + IF cont1.up THEN IF y > 0 THEN y = y - 1 + IF cont1.left THEN IF x > 0 THEN x = x - 1 + IF cont1.right THEN IF x < 240 THEN x = x + 1 + IF cont1.down THEN IF y < 176 THEN y = y + 1 + IF cont1.button THEN face_palette = 1 + IF cont1.button2 THEN face_palette = 2 + END IF + + GOTO game_loop + +full_palette: + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$32 + DATA BYTE $0F,$30,$30,$34 + DATA BYTE $0F,$30,$30,$36 + DATA BYTE $0F,$30,$30,$38 + + CHRROM 0 + + CHRROM PATTERN 256 + + BITMAP "......3333......" + BITMAP "....33333333...." + BITMAP "...3333333333..." + BITMAP "..333333333333.." + BITMAP ".33333333333333." + BITMAP ".33333333333333." + BITMAP "3333..3333..3333" + BITMAP "3333..3333..3333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP ".33333333333333." + BITMAP ".333..3333..333." + BITMAP "..333......333.." + BITMAP "...333....333..." + BITMAP "....33333333...." + BITMAP "......3333......" From 694f9e95376ffe5c21643a2b3f46440b2af0eb6c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 14:11:08 -0600 Subject: [PATCH 063/155] NES added PRINT support and a bitmap font --- cvbasic.c | 1636 +++++++++++++++++++---------------- cvbasic_nes_prologue.asm | 272 +++++- examples/happy_face_nes.bas | 4 +- manual.txt | 52 +- 4 files changed, 1213 insertions(+), 751 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 21170cf..c66c584 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -244,6 +244,124 @@ int chrrom_pointer; int chrrom_size; unsigned char *chrrom_data; +void reset_chrrom(unsigned char *page) +{ + /* + ** Font for NES/Famicom, because it doesn't provide an ASCII charset. + ** + ** My personal font for TMS9928. + ** + ** Patterned after the TMS9928 programming manual 6x8 letters + ** with better lowercase letters, also I made a proper + ** AT sign. + */ + unsigned char font[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0x20 space + 0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, // 0x21 ! + 0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00, // 0x22 " + 0x50,0x50,0xf8,0x50,0xf8,0x50,0x50,0x00, // 0x23 # + 0x20,0x78,0xa0,0x70,0x28,0xf0,0x20,0x00, // 0x24 $ + 0xc0,0xc8,0x10,0x20,0x40,0x98,0x18,0x00, // 0x25 % + 0x40,0xa0,0x40,0xa0,0xa8,0x90,0x68,0x00, // 0x26 & + 0x60,0x20,0x40,0x00,0x00,0x00,0x00,0x00, // 0x27 ' + 0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00, // 0x28 ( + 0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00, // 0x29 ) + 0x00,0xa8,0x70,0x20,0x70,0xa8,0x00,0x00, // 0x2a * + 0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00, // 0x2b + + 0x00,0x00,0x00,0x00,0x00,0x60,0x20,0x40, // 0x2c , + 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, // 0x2d - + 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00, // 0x2e . + 0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00, // 0x2f / + 0x70,0x88,0x98,0xa8,0xc8,0x88,0x70,0x00, // 0x30 0 + 0x20,0x60,0x20,0x20,0x20,0x20,0xf8,0x00, // 0x31 1 + 0x70,0x88,0x08,0x10,0x60,0x80,0xf8,0x00, // 0x32 2 + 0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00, // 0x33 3 + 0x30,0x50,0x90,0x90,0xf8,0x10,0x10,0x00, // 0x34 4 + 0xf8,0x80,0xf0,0x08,0x08,0x08,0xf0,0x00, // 0x35 5 + 0x30,0x40,0x80,0xf0,0x88,0x88,0x70,0x00, // 0x36 6 + 0xf8,0x08,0x10,0x20,0x20,0x20,0x20,0x00, // 0x37 7 + 0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00, // 0x38 8 + 0x70,0x88,0x88,0x78,0x08,0x10,0x60,0x00, // 0x39 9 + 0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x00, // 0x3a : + 0x00,0x00,0x00,0x60,0x00,0x60,0x20,0x40, // 0x3b ; + 0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00, // 0x3c < + 0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00, // 0x3d = + 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00, // 0x3e > + 0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00, // 0x3f ? + 0x70,0x88,0x98,0xa8,0x98,0x80,0x70,0x00, // 0x40 @ + 0x20,0x50,0x88,0x88,0xf8,0x88,0x88,0x00, // 0x41 A + 0xf0,0x88,0x88,0xf0,0x88,0x88,0xf0,0x00, // 0x42 B + 0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00, // 0x43 C + 0xf0,0x88,0x88,0x88,0x88,0x88,0xf0,0x00, // 0x44 D + 0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00, // 0x45 E + 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00, // 0x46 F + 0x70,0x88,0x80,0xb8,0x88,0x88,0x70,0x00, // 0x47 G + 0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00, // 0x48 H + 0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00, // 0x49 I + 0x08,0x08,0x08,0x08,0x88,0x88,0x70,0x00, // 0x4A J + 0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00, // 0x4B K + 0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00, // 0x4C L + 0x88,0xd8,0xa8,0xa8,0x88,0x88,0x88,0x00, // 0x4D M + 0x88,0xc8,0xc8,0xa8,0x98,0x98,0x88,0x00, // 0x4E N + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, // 0x4F O + 0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00, // 0x50 P + 0x70,0x88,0x88,0x88,0x88,0xa8,0x90,0x68, // 0x51 Q + 0xf0,0x88,0x88,0xf0,0xa0,0x90,0x88,0x00, // 0x52 R + 0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00, // 0x53 S + 0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00, // 0x54 T + 0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00, // 0x55 U + 0x88,0x88,0x88,0x88,0x50,0x50,0x20,0x00, // 0x56 V + 0x88,0x88,0x88,0xa8,0xa8,0xd8,0x88,0x00, // 0x57 W + 0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00, // 0x58 X + 0x88,0x88,0x88,0x70,0x20,0x20,0x20,0x00, // 0x59 Y + 0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00, // 0x5A Z + 0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00, // 0x5B [ + 0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00, // 0x5C backslash + 0xF0,0x30,0x30,0x30,0x30,0x30,0xF0,0x00, // 0x5D ] + 0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00, // 0x5E + 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00, // 0x5F _ + 0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00, // 0x60 + 0x00,0x00,0x68,0x98,0x88,0x98,0x68,0x00, // 0x61 a + 0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00, // 0x62 b + 0x00,0x00,0x78,0x80,0x80,0x80,0x78,0x00, // 0x63 c + 0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00, // 0x64 d + 0x00,0x00,0x70,0x88,0xf8,0x80,0x70,0x00, // 0x65 e + 0x30,0x48,0x40,0xe0,0x40,0x40,0x40,0x00, // 0x66 f + 0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x70, // 0x67 g + 0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00, // 0x68 h + 0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00, // 0x69 i + 0x08,0x00,0x18,0x08,0x88,0x88,0x70,0x00, // 0x6a j + 0x80,0x80,0x88,0x90,0xe0,0x90,0x88,0x00, // 0x6b k + 0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00, // 0x6c l + 0x00,0x00,0xd0,0xa8,0xa8,0xa8,0xa8,0x00, // 0x6d m + 0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00, // 0x6e n + 0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, // 0x6f o + 0x00,0x00,0xf0,0x88,0x88,0x88,0xf0,0x80, // 0x70 p + 0x00,0x00,0x78,0x88,0x88,0x88,0x78,0x08, // 0x71 q + 0x00,0x00,0xb8,0xc0,0x80,0x80,0x80,0x00, // 0x72 r + 0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00, // 0x73 s + 0x20,0x20,0xf8,0x20,0x20,0x20,0x20,0x00, // 0x74 t + 0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00, // 0x75 u + 0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00, // 0x76 v + 0x00,0x00,0x88,0xa8,0xa8,0xa8,0x50,0x00, // 0x77 w + 0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00, // 0x78 x + 0x00,0x00,0x88,0x88,0x98,0x68,0x08,0x70, // 0x79 y + 0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00, // 0x7a z + 0x18,0x20,0x20,0x40,0x20,0x20,0x18,0x00, // 0x7b { + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, // 0x7c | + 0xc0,0x20,0x20,0x10,0x20,0x20,0xc0,0x00, // 0x7d } + 0x00,0x00,0x40,0xa8,0x10,0x00,0x00,0x00, // 0x7e + 0x70,0x70,0x20,0xf8,0x20,0x70,0x50,0x00, // 0x7f + }; + int c; + + memset(page, 0, CHRROM_PAGE); + for (c = 0; c < 0x60; c++) { + memcpy(page + (c + 32) * 16, &font[c * 8], 8); + memcpy(page + (c + 32) * 16 + 8, &font[c * 8], 8); + } +} + /* ** Prototypes */ @@ -2092,6 +2210,10 @@ void compile_statement(int check_for_else) while (1) { if (lex == C_NAME) { last_is_return = 0; + + /* + ** CVBasic core language + */ if (strcmp(name, "GOTO") == 0) { get_lex(); if (lex != C_NAME) { @@ -2748,114 +2870,9 @@ void compile_statement(int check_for_else) get_lex(); } } - } else if (strcmp(name, "POKE") == 0) { - struct node *address; - struct node *value; - - get_lex(); - address = evaluate_save_expression(1, TYPE_16); - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in POKE"); - value = evaluate_save_expression(1, TYPE_8); - if (target == CPU_6502) { - node_generate(value, 0); - cpu6502_noop("PHA"); - node_generate(address, 0); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); - cpu6502_noop("PLA"); - cpu6502_1op("LDY", "#0"); - cpu6502_1op("STA", "(temp),Y"); - } else if (target == CPU_9900) { - node_generate(value, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - node_generate(address, 0); - cpu9900_2op("mov", "*r10+", "r1"); - cpu9900_2op("movb","r1","*r0"); - } else { - if ((value->regs & REG_HL) == 0) { - node_generate(address, 0); - node_generate(value, 0); - } else if ((address->regs & REG_A) == 0) { - node_generate(value, 0); - node_generate(address, 0); - } else { - node_generate(address, 0); - cpuz80_1op("PUSH", "HL"); - node_generate(value, 0); - cpuz80_1op("POP", "HL"); - } - cpuz80_2op("LD", "(HL)", "A"); - } - node_delete(address); - node_delete(value); - } else if (strcmp(name, "VPOKE") == 0) { - struct node *address; - struct node *value; - - get_lex(); - address = evaluate_save_expression(1, TYPE_16); - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in VPOKE"); - value = evaluate_save_expression(1, TYPE_8); - if (target == CPU_6502) { - node_generate(value, 0); - cpu6502_noop("PHA"); - node_generate(address, 0); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); - cpu6502_noop("PLA"); - cpu6502_noop("TAX"); - cpu6502_1op("LDA", "temp"); - generic_interrupt_disable(); - cpu6502_1op("JSR", "WRTVRM"); - generic_interrupt_enable(); - } else if (target == CPU_9900) { - node_generate(value, 0); - cpu9900_1op("dect", "r10"); - cpu9900_2op("mov", "r0", "*r10"); - node_generate(address, 0); - cpu9900_2op("mov", "*r10+", "r2"); - generic_interrupt_disable(); - cpu9900_1op("bl","@JSR"); - cpu9900_1op("data", "WRTVRM"); - generic_interrupt_enable(); - } else { - if ((value->regs & REG_HL) == 0) { - node_generate(address, 0); - node_generate(value, 0); - } else if ((address->regs & REG_A) == 0) { - node_generate(value, 0); - node_generate(address, 0); - } else { - node_generate(address, 0); - cpuz80_1op("PUSH", "HL"); - node_generate(value, 0); - cpuz80_1op("POP", "HL"); - } - generic_interrupt_disable(); - cpuz80_1op("CALL", "WRTVRM"); - generic_interrupt_enable(); - } - node_delete(address); - node_delete(value); } else if (strcmp(name, "REM") == 0) { line_pos = line_size; get_lex(); - } else if (strcmp(name, "CLS") == 0) { - get_lex(); - generic_call("cls"); - } else if (strcmp(name, "WAIT") == 0) { - get_lex(); - if (machine == SORD || machine == CREATIVISION || machine == NES || machine == EINSTEIN || machine == TI994A) - generic_call("wait"); - else - cpuz80_noop("HALT"); } else if (strcmp(name, "RESTORE") == 0) { get_lex(); if (lex != C_NAME) { @@ -2902,7 +2919,7 @@ void compile_statement(int check_for_else) } else if (strcmp(name, "DATA") == 0) { struct node *tree; int c = 0; - + generic_dump(); get_lex(); if (lex == C_NAME && strcmp(name, "BYTE") == 0) { @@ -3132,89 +3149,683 @@ void compile_statement(int check_for_else) fprintf(output, "\n"); } } - } else if (strcmp(name, "OUT") == 0) { - struct node *port; - struct node *value; + } else if (strcmp(name, "SIGNED") == 0) { + struct signedness *c; get_lex(); - port = evaluate_save_expression(1, TYPE_8); - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in OUT"); - value = evaluate_save_expression(1, TYPE_8); - if (target == CPU_6502) { - emit_warning("Ignoring OUT (not supported for 6502)"); - } else if (target == CPU_9900) { - /* - ** We don't have ports (though we could map this to CRU) - ** however, since it seems OUT is the CVBasic way to directly - ** access the sound chip, we'll check for OUT $FF and map that - ** over. - */ - if (port->type == N_NUM8 && port->value == 0xff) { - node_generate(value, 0); - cpu9900_2op("movb", "r0", "@SOUND"); + while (1) { + if (lex != C_NAME) { + emit_error("missing name in SIGNED"); + break; + } + c = signed_search(name); + if (c != NULL) { + emit_error("variable already SIGNED/UNSIGNED"); } else { - emit_warning("OUT to 0xff for audio is the only supported use."); + c = signed_add(name); } - } else { - node_generate(port, 0); - cpuz80_2op("LD", "C", "A"); - if ((value->regs & REG_C) == 0) { - node_generate(value, 0); + c->sign = 1; + get_lex(); + if (lex != C_COMMA) + break; + get_lex(); + } + } else if (strcmp(name, "UNSIGNED") == 0) { + struct signedness *c; + + get_lex(); + while (1) { + if (lex != C_NAME) { + emit_error("missing name in UNSIGNED"); + break; + } + c = signed_search(name); + if (c != NULL) { + emit_error("variable already SIGNED/UNSIGNED"); } else { - cpuz80_1op("PUSH", "BC"); - node_generate(value, 0); - cpuz80_1op("POP", "BC"); + c = signed_add(name); } - cpuz80_2op("OUT", "(C)", "A"); + c->sign = 2; + get_lex(); + if (lex != C_COMMA) + break; + get_lex(); } - node_delete(port); - node_delete(value); - } else if (strcmp(name, "PRINT") == 0) { - int label; - int label2; - int c; - int start; - int cursor_value; - int cursor_pos; - struct node *tree; + } else if (strcmp(name, "CONST") == 0) { + struct constant *c; get_lex(); - label2 = 0; - start = 1; - cursor_value = 0; - cursor_pos = 0; - if (lex == C_NAME && strcmp(name, "AT") == 0) { + if (lex != C_NAME) { + emit_error("name required for constant assignment"); + return; + } + c = constant_search(name); + if (c != NULL) { + emit_error("constant redefined"); + } else { + c = constant_add(name); + } + strcpy(assigned, name);; + get_lex(); + if (lex != C_EQUAL) { + emit_error("required '=' for constant assignment"); + } else { + struct node *tree; + int type; + get_lex(); - tree = evaluate_save_expression(1, TYPE_16); - if (machine == SMS) { - tree = node_create(N_MUL16, 0, tree, node_create(N_NUM16, 2, NULL, NULL)); + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("not a constant expression in CONST"); + } else { + c->value = tree->value; } - if (target == CPU_6502) { - if (tree->type == N_NUM16) { - cursor_value = 2; - cursor_pos = tree->value; - } else { - node_generate(tree, 0); - cursor_value = 1; - } + if (target == CPU_Z80 || target == CPU_6502) { + sprintf(temp, CONST_PREFIX "%s:\tequ $%04x", assigned, c->value); + fprintf(output, "%s\n", temp); } else if (target == CPU_9900) { - node_generate(tree, 0); - cpu9900_2op("mov", "r0", "@cursor"); - } else { - node_generate(tree, 0); - cpuz80_2op("LD", "(cursor)", "HL"); + sprintf(temp, CONST_PREFIX "%s\tequ >%04x", assigned, c->value); + cpu9900_label(temp); /* Hack */ } - start = 0; + node_delete(tree); + tree = NULL; } + } else if (strcmp(name, "DIM") == 0) { + char array[MAX_LINE_SIZE]; + struct label *new_array; + struct node *tree; + int type; + int c; + while (1) { - if (!start) { - if (lex != C_COMMA) { - if (target == CPU_6502) { - if (cursor_value) { - if (cursor_value == 2) { + get_lex(); + if (lex != C_NAME) { + emit_error("missing name in DIM"); + break; + } + strcpy(array, name); + get_lex(); + if (lex == C_LPAREN) { + get_lex(); + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("not a constant expression in DIM"); + c = 10; + } else { + c = tree->value; + } + node_delete(tree); + if (lex != C_RPAREN) { + emit_error("missing right parenthesis in DIM"); + } else { + get_lex(); + } + new_array = array_search(array); + if (new_array != NULL) { + emit_error("array already defined"); + } else { + new_array = array_add(array); + new_array->length = c; + } + } else { + label = label_add(array); + if (array[0] == '#') + label->used = TYPE_16; + else + label->used = TYPE_8; + label->used |= LABEL_IS_VARIABLE; + } + if (lex != C_COMMA) + break; + } + } else if (strcmp(name, "ON") == 0) { + struct label *label; + int table; + int c; + int max_value; + int gosub; + int fast; + struct label *options[256]; + int new_label; + int type; + + get_lex(); + if (lex == C_NAME && strcmp(name, "FRAME") == 0) { /* Frame-driven games */ + get_lex(); + if (lex != C_NAME || strcmp(name, "GOSUB") != 0) { + emit_error("Bad syntax for ON FRAME GOSUB"); + } + get_lex(); + if (lex != C_NAME) { + emit_error("Missing label for ON FRAME GOSUB"); + } + if (frame_drive != NULL) { + emit_error("More than one ON FRAME GOSUB"); + } + label = label_search(name); + if (label == NULL) { + label = label_add(name); + } + label->used |= LABEL_USED; + label->used |= LABEL_CALLED_BY_GOSUB; + frame_drive = label; + get_lex(); + } else { + type = evaluate_expression(0, 0, 0); + fast = 0; + if (lex == C_NAME && strcmp(name, "FAST") == 0) { + get_lex(); + fast = 1; + } + gosub = 0; + if (lex != C_NAME || (strcmp(name, "GOTO") != 0 && strcmp(name, "GOSUB") != 0)) { + emit_error("required GOTO or GOSUB after ON"); + } else if (strcmp(name, "GOTO") == 0) { + get_lex(); + } else if (strcmp(name, "GOSUB") == 0) { + get_lex(); + gosub = 1; + } + max_value = 0; + while (1) { + if (max_value == sizeof(options) / sizeof(struct label *)) { + emit_error("too many options for ON statement"); + max_value--; + } + if (lex == C_NAME) { + label = label_search(name); + if (label == NULL) { + label = label_add(name); + } + label->used |= LABEL_USED; + if (gosub != 0) { + label->used |= LABEL_CALLED_BY_GOSUB; + } else { + label->used |= LABEL_CALLED_BY_GOTO; + } + options[max_value++] = label; + get_lex(); + } else { + options[max_value++] = NULL; + } + if (lex != C_COMMA) + break; + get_lex(); + } + table = next_local++; + new_label = next_local++; + if (fast == 0) { + if (target == CPU_6502) { + if ((type & MAIN_TYPE) == TYPE_8) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("LDY", "#0"); + cpu6502_1op("STY", "temp+1"); + sprintf(temp, "#%d", max_value); + cpu6502_1op("CMP", temp); + } else { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + sprintf(temp, "#%d", max_value); + cpu6502_1op("LDA", "temp"); + cpu6502_noop("SEC"); + cpu6502_1op("SBC", temp); + cpu6502_1op("LDA", "temp+1"); + strcat(temp, ">>8"); + cpu6502_1op("SBC", temp); + } + sprintf(temp, INTERNAL_PREFIX "%d", new_label); + cpu6502_1op("BCS.L", temp); + } else if (target == CPU_9900) { + if ((type & MAIN_TYPE) == TYPE_8) { + sprintf(temp, "%d ; %d*256", max_value*256, max_value); + cpu9900_2op("ci", "r0", temp); + } else { + sprintf(temp, "%d", max_value); + cpu9900_2op("ci", "r0", temp); + } + sprintf(temp, "@" INTERNAL_PREFIX "%d", new_label); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); + cpu9900_1op("jl", temp + 100); + cpu9900_1op("b", temp); + cpu9900_label(temp + 100); + } else { + if ((type & MAIN_TYPE) == TYPE_8) { + sprintf(temp, "%d", max_value); + cpuz80_1op("CP", temp); + } else { + sprintf(temp, "%d", max_value); + cpuz80_2op("LD", "DE", temp); + cpuz80_1op("OR", "A"); + cpuz80_2op("SBC", "HL", "DE"); + cpuz80_2op("ADD", "HL", "DE"); + } + sprintf(temp, INTERNAL_PREFIX "%d", new_label); + cpuz80_2op("JP", "NC", temp); + } + } + if (gosub) { + if (target == CPU_6502) { + sprintf(temp, "#(" INTERNAL_PREFIX "%d-1)>>8", new_label); + cpu6502_1op("LDA", temp); + cpu6502_noop("PHA"); + sprintf(temp, "#" INTERNAL_PREFIX "%d-1", new_label); + cpu6502_1op("LDA", temp); + cpu6502_noop("PHA"); + } else if (target == CPU_9900) { + sprintf(temp, INTERNAL_PREFIX "%d", new_label); + cpu9900_2op("li", "r1", temp); + cpu9900_1op("dect", "r10"); /* stack manipulation */ + cpu9900_2op("mov", "r1", "*r10"); + } else { + sprintf(temp, INTERNAL_PREFIX "%d", new_label); + cpuz80_2op("LD", "DE", temp); + cpuz80_1op("PUSH", "DE"); + } + } + if (target == CPU_6502) { + cpu6502_1op("LDA", "temp"); + cpu6502_1op("ASL", "A"); + cpu6502_1op("ROL", "temp+1"); + cpu6502_noop("CLC"); + sprintf(temp, "#" INTERNAL_PREFIX "%d", table); + cpu6502_1op("ADC", temp); + cpu6502_1op("STA", "temp"); + cpu6502_1op("LDA", "temp+1"); + strcat(temp, ">>8"); + cpu6502_1op("ADC", temp); + cpu6502_1op("STA", "temp+1"); + cpu6502_1op("LDY", "#0"); + cpu6502_1op("LDA", "(temp),Y"); + cpu6502_1op("STA", "temp2"); + cpu6502_noop("INY"); + cpu6502_1op("LDA", "(temp),Y"); + cpu6502_1op("STA", "temp2+1"); + cpu6502_1op("JMP", "(temp2)"); + } else if (target == CPU_9900) { + if ((type & MAIN_TYPE) == TYPE_8) { + cpu9900_2op("srl", "r0", "8"); + } + cpu9900_2op("sla", "r0", "1"); + cpu9900_2op("mov", "r0", "r1"); + sprintf(temp, "@" INTERNAL_PREFIX "%d(r1)", table); + cpu9900_2op("mov", temp, "r0"); + cpu9900_1op("b", "*r0"); + } else { + if ((type & MAIN_TYPE) == TYPE_8) { + cpuz80_2op("LD", "L", "A"); + if (type & TYPE_SIGNED) { + cpuz80_noop("RLA"); + cpuz80_2op("SBC", "A", "A"); + cpuz80_2op("LD", "H", "A"); + } else { + cpuz80_2op("LD", "H", "0"); + } + } + cpuz80_2op("ADD", "HL", "HL"); + sprintf(temp, INTERNAL_PREFIX "%d", table); + cpuz80_2op("LD", "DE", temp); + cpuz80_2op("ADD", "HL", "DE"); + cpuz80_2op("LD", "A", "(HL)"); + cpuz80_1op("INC", "HL"); + cpuz80_2op("LD", "H", "(HL)"); + cpuz80_2op("LD", "L", "A"); + cpuz80_1op("JP", "(HL)"); + } + sprintf(temp, INTERNAL_PREFIX "%d", table); + generic_label(temp); + for (c = 0; c < max_value; c++) { + if (options[c] != NULL) { + sprintf(temp, LABEL_PREFIX "%s", options[c]->name); + } else { + sprintf(temp, INTERNAL_PREFIX "%d", new_label); + } + if (target == CPU_6502) + cpu6502_1op("DW", temp); + else if (target == CPU_9900) + cpu9900_1op("data", temp); + else + cpuz80_1op("DW", temp); + } + sprintf(temp, INTERNAL_PREFIX "%d", new_label); + generic_label(temp); + } + } else if (strcmp(name, "OPTION") == 0) { + get_lex(); + if (lex != C_NAME) { + emit_error("required name after OPTION"); + } else if (strcmp(name, "EXPLICIT") == 0) { + get_lex(); + if (lex == C_NAME && strcmp(name, "ON") == 0) { + get_lex(); + option_explicit = 1; + } else if (lex == C_NAME && strcmp(name, "OFF") == 0) { + get_lex(); + option_explicit = 0; + } else { + option_explicit = 1; + } + } else if (strcmp(name, "WARNINGS") == 0) { + get_lex(); + if (lex == C_NAME && strcmp(name, "ON") == 0) { + get_lex(); + option_warnings = 1; + } else if (lex == C_NAME && strcmp(name, "OFF") == 0) { + get_lex(); + option_warnings = 0; + } else { + emit_error("missing ON/OFF in OPTION WARNINGS"); + } + } else { + emit_error("non-recognized OPTION"); + } + } else if (strcmp(name, "DEF") == 0) { /* Function definition (macro in CVBasic) */ + char function[MAX_LINE_SIZE]; + int total_arguments; + char *arguments[32]; + struct macro *macro; + int c; + + get_lex(); + if (lex != C_NAME || strcmp(name, "FN") != 0) { + emit_error("syntax error for DEF FN"); + } else { + get_lex(); + if (lex != C_NAME) { + emit_error("missing function name for DEF FN"); + } else if (macro_search(name) != NULL) { + emit_error("DEF FN name already defined"); + } else { + strcpy(function, name); + get_lex(); + total_arguments = 0; + if (lex == C_LPAREN) { + get_lex(); + while (1) { + if (lex != C_NAME) { + emit_error("syntax error in argument list for DEF FN"); + break; + } + if (total_arguments == 32) { + emit_error("More than 32 arguments in DEF FN"); + break; + } + arguments[total_arguments] = malloc(strlen(name) + 1); + if (arguments[total_arguments] == NULL) { + emit_error("Out of memory in DEF FN"); + break; + } + strcpy(arguments[total_arguments], name); + total_arguments++; + get_lex(); + if (lex == C_COMMA) { + get_lex(); + } else if (lex == C_RPAREN) { + get_lex(); + break; + } else { + emit_error("syntax error in argument list for DEF FN"); + break; + } + } + } + macro = macro_add(function); + macro->total_arguments = total_arguments; + if (lex != C_EQUAL) { + emit_error("missing = in DEF FN"); + } else { + get_lex(); + while (lex != C_END) { + if (lex == C_ERR) { + emit_error("bad syntax inside DEF FN replacement text"); + break; + } + if (lex == C_NAME) { + for (c = 0; c < total_arguments; c++) { + if (strcmp(arguments[c], name) == 0) + break; + } + if (c < total_arguments) { + lex = C_ERR; + value = c; + name[0] = '\0'; + } + } + if (macro->length >= macro->max_length) { + macro->definition = realloc(macro->definition, (macro->max_length + 1) * 2 * sizeof(struct macro_def)); + if (macro->definition == NULL) { + emit_error("Out of memory in DEF FN"); + break; + } + macro->max_length = (macro->max_length + 1) * 2; + } + macro->definition[macro->length].lex = lex; + if (lex == C_STRING) + value = name_size; + macro->definition[macro->length].value = value; + if (lex == C_STRING) + macro->definition[macro->length].name = malloc(name_size + 1); + else + macro->definition[macro->length].name = malloc(strlen(name) + 1); + if (macro->definition[macro->length].name == NULL) { + emit_error("Out of memory in DEF FN"); + break; + } + if (lex == C_STRING) { + if (value) + memcpy(macro->definition[macro->length].name, name, value); + } else { + strcpy(macro->definition[macro->length].name, name); + } + macro->length++; + get_lex(); + } + } + } + } + + /* + ** Non-portable language + */ + } else if (strcmp(name, "POKE") == 0) { + struct node *address; + struct node *value; + + get_lex(); + address = evaluate_save_expression(1, TYPE_16); + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in POKE"); + value = evaluate_save_expression(1, TYPE_8); + if (target == CPU_6502) { + node_generate(value, 0); + cpu6502_noop("PHA"); + node_generate(address, 0); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + cpu6502_noop("PLA"); + cpu6502_1op("LDY", "#0"); + cpu6502_1op("STA", "(temp),Y"); + } else if (target == CPU_9900) { + node_generate(value, 0); + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + node_generate(address, 0); + cpu9900_2op("mov", "*r10+", "r1"); + cpu9900_2op("movb","r1","*r0"); + } else { + if ((value->regs & REG_HL) == 0) { + node_generate(address, 0); + node_generate(value, 0); + } else if ((address->regs & REG_A) == 0) { + node_generate(value, 0); + node_generate(address, 0); + } else { + node_generate(address, 0); + cpuz80_1op("PUSH", "HL"); + node_generate(value, 0); + cpuz80_1op("POP", "HL"); + } + cpuz80_2op("LD", "(HL)", "A"); + } + node_delete(address); + node_delete(value); + } else if (strcmp(name, "VPOKE") == 0) { + struct node *address; + struct node *value; + + get_lex(); + address = evaluate_save_expression(1, TYPE_16); + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in VPOKE"); + value = evaluate_save_expression(1, TYPE_8); + if (target == CPU_6502) { + if (machine == NES) { + node_generate(value, 0); + cpu6502_noop("PHA"); + node_generate(address, 0); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + cpu6502_noop("PLA"); + cpu6502_noop("TAX"); + cpu6502_1op("LDA", "temp"); + cpu6502_1op("JSR", "WRTVRM"); + } else { + node_generate(value, 0); + cpu6502_noop("PHA"); + node_generate(address, 0); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + cpu6502_noop("PLA"); + cpu6502_noop("TAX"); + cpu6502_1op("LDA", "temp"); + generic_interrupt_disable(); + cpu6502_1op("JSR", "WRTVRM"); + generic_interrupt_enable(); + } + } else if (target == CPU_9900) { + node_generate(value, 0); + cpu9900_1op("dect", "r10"); + cpu9900_2op("mov", "r0", "*r10"); + node_generate(address, 0); + cpu9900_2op("mov", "*r10+", "r2"); + generic_interrupt_disable(); + cpu9900_1op("bl","@JSR"); + cpu9900_1op("data", "WRTVRM"); + generic_interrupt_enable(); + } else { + if ((value->regs & REG_HL) == 0) { + node_generate(address, 0); + node_generate(value, 0); + } else if ((address->regs & REG_A) == 0) { + node_generate(value, 0); + node_generate(address, 0); + } else { + node_generate(address, 0); + cpuz80_1op("PUSH", "HL"); + node_generate(value, 0); + cpuz80_1op("POP", "HL"); + } + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVRM"); + generic_interrupt_enable(); + } + node_delete(address); + node_delete(value); + } else if (strcmp(name, "CLS") == 0) { + get_lex(); + generic_call("cls"); + } else if (strcmp(name, "WAIT") == 0) { + get_lex(); + if (machine == SORD || machine == CREATIVISION || machine == NES || machine == EINSTEIN || machine == TI994A) + generic_call("wait"); + else + cpuz80_noop("HALT"); + } else if (strcmp(name, "OUT") == 0) { + struct node *port; + struct node *value; + + get_lex(); + port = evaluate_save_expression(1, TYPE_8); + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in OUT"); + value = evaluate_save_expression(1, TYPE_8); + if (target == CPU_6502) { + emit_warning("Ignoring OUT (not supported for 6502)"); + } else if (target == CPU_9900) { + /* + ** We don't have ports (though we could map this to CRU) + ** however, since it seems OUT is the CVBasic way to directly + ** access the sound chip, we'll check for OUT $FF and map that + ** over. + */ + if (port->type == N_NUM8 && port->value == 0xff) { + node_generate(value, 0); + cpu9900_2op("movb", "r0", "@SOUND"); + } else { + emit_warning("OUT to 0xff for audio is the only supported use."); + } + } else { + node_generate(port, 0); + cpuz80_2op("LD", "C", "A"); + if ((value->regs & REG_C) == 0) { + node_generate(value, 0); + } else { + cpuz80_1op("PUSH", "BC"); + node_generate(value, 0); + cpuz80_1op("POP", "BC"); + } + cpuz80_2op("OUT", "(C)", "A"); + } + node_delete(port); + node_delete(value); + } else if (strcmp(name, "PRINT") == 0) { + int label; + int label2; + int c; + int start; + int cursor_value; + int cursor_pos; + struct node *tree; + + get_lex(); + label2 = 0; + start = 1; + cursor_value = 0; + cursor_pos = 0; + if (lex == C_NAME && strcmp(name, "AT") == 0) { + get_lex(); + tree = evaluate_save_expression(1, TYPE_16); + if (machine == SMS) { + tree = node_create(N_MUL16, 0, tree, node_create(N_NUM16, 2, NULL, NULL)); + } + if (target == CPU_6502) { + if (tree->type == N_NUM16) { + cursor_value = 2; + cursor_pos = tree->value; + } else { + node_generate(tree, 0); + cursor_value = 1; + } + } else if (target == CPU_9900) { + node_generate(tree, 0); + cpu9900_2op("mov", "r0", "@cursor"); + } else { + node_generate(tree, 0); + cpuz80_2op("LD", "(cursor)", "HL"); + } + start = 0; + } + while (1) { + if (!start) { + if (lex != C_COMMA) { + if (target == CPU_6502) { + if (cursor_value) { + if (cursor_value == 2) { sprintf(temp, "#%d", cursor_pos & 0xff); cpu6502_1op("LDA", temp); sprintf(temp, "#%d", cursor_pos >> 8); @@ -3989,7 +4600,7 @@ void compile_statement(int check_for_else) } get_lex(); if (current_chrrom == -1) { - emit_error("BITMAP used without setting pattern table"); + emit_error("BITMAP used without choosing CHRROM table"); } else if (chrrom_pointer + 48 >= CHRROM_PAGE) { emit_error("More than 512 patterns"); } else { @@ -4126,9 +4737,9 @@ void compile_statement(int check_for_else) } get_lex(); if (current_chrrom == -1) { - emit_error("BITMAP used without setting pattern table"); + emit_error("BITMAP used without choosing CHRROM table"); } else if (chrrom_pointer == 8192) { - emit_error("More than 256 patterns"); + emit_error("More than 512 patterns"); } else { chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer] = value; chrrom_data[current_chrrom * CHRROM_PAGE + chrrom_pointer + 8] = value >> 8; @@ -4200,9 +4811,13 @@ void compile_statement(int check_for_else) if (lex != C_COMMA) { type = evaluate_expression(1, TYPE_8, 0); if (target == CPU_6502) { - cpu6502_1op("LDX", "#7"); - generic_interrupt_disable(); - cpu6502_1op("JSR", "WRTVDP"); + if (machine == NES) { + emit_warning("BORDER first argument ignored for NES/Famicom (use PALETTE 0)"); + } else { + cpu6502_1op("LDX", "#7"); + generic_interrupt_disable(); + cpu6502_1op("JSR", "WRTVDP"); + } } else if (target == CPU_9900) { /* this is just a lot faster inline than jumping through hoops... */ cpu9900_2op("srl","r0","8"); @@ -4242,6 +4857,7 @@ void compile_statement(int check_for_else) int type; get_lex(); + /* !!! Implement NES/Famicom support */ if (machine != SMS) emit_error("SCROLL is only available on Sega Master System"); if (lex != C_COMMA) { @@ -4265,7 +4881,7 @@ void compile_statement(int check_for_else) generic_interrupt_enable(); } } - } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System */ + } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System / NES */ int type; struct node *source; @@ -4345,6 +4961,8 @@ void compile_statement(int check_for_else) struct node *tree; int c; + if (machine != NES) + emit_error("CHRROM is only admited for NES/Famicom"); get_lex(); if (strcmp(name, "PATTERN") == 0) { get_lex(); @@ -4377,143 +4995,15 @@ void compile_statement(int check_for_else) if (p == NULL) { emit_error("Not enough memory for CHRROM"); break; - } - chrrom_data = p; - /* Reset pixel data in new space */ - memset(chrrom_data + chrrom_size * CHRROM_PAGE, 0, (c + 1 - chrrom_size) * CHRROM_PAGE); - chrrom_size = c + 1; - } - current_chrrom = c; - chrrom_pointer = 0; - } - } else if (strcmp(name, "SIGNED") == 0) { - struct signedness *c; - - get_lex(); - while (1) { - if (lex != C_NAME) { - emit_error("missing name in SIGNED"); - break; - } - c = signed_search(name); - if (c != NULL) { - emit_error("variable already SIGNED/UNSIGNED"); - } else { - c = signed_add(name); - } - c->sign = 1; - get_lex(); - if (lex != C_COMMA) - break; - get_lex(); - } - } else if (strcmp(name, "UNSIGNED") == 0) { - struct signedness *c; - - get_lex(); - while (1) { - if (lex != C_NAME) { - emit_error("missing name in UNSIGNED"); - break; - } - c = signed_search(name); - if (c != NULL) { - emit_error("variable already SIGNED/UNSIGNED"); - } else { - c = signed_add(name); - } - c->sign = 2; - get_lex(); - if (lex != C_COMMA) - break; - get_lex(); - } - } else if (strcmp(name, "CONST") == 0) { - struct constant *c; - - get_lex(); - if (lex != C_NAME) { - emit_error("name required for constant assignment"); - return; - } - c = constant_search(name); - if (c != NULL) { - emit_error("constant redefined"); - } else { - c = constant_add(name); - } - strcpy(assigned, name);; - get_lex(); - if (lex != C_EQUAL) { - emit_error("required '=' for constant assignment"); - } else { - struct node *tree; - int type; - - get_lex(); - tree = evaluate_level_0(&type); - if (tree->type != N_NUM8 && tree->type != N_NUM16) { - emit_error("not a constant expression in CONST"); - } else { - c->value = tree->value; - } - if (target == CPU_Z80 || target == CPU_6502) { - sprintf(temp, CONST_PREFIX "%s:\tequ $%04x", assigned, c->value); - fprintf(output, "%s\n", temp); - } else if (target == CPU_9900) { - sprintf(temp, CONST_PREFIX "%s\tequ >%04x", assigned, c->value); - cpu9900_label(temp); /* Hack */ - } - node_delete(tree); - tree = NULL; - } - } else if (strcmp(name, "DIM") == 0) { - char array[MAX_LINE_SIZE]; - struct label *new_array; - struct node *tree; - int type; - int c; - - while (1) { - get_lex(); - if (lex != C_NAME) { - emit_error("missing name in DIM"); - break; - } - strcpy(array, name); - get_lex(); - if (lex == C_LPAREN) { - get_lex(); - tree = evaluate_level_0(&type); - if (tree->type != N_NUM8 && tree->type != N_NUM16) { - emit_error("not a constant expression in DIM"); - c = 10; - } else { - c = tree->value; - } - node_delete(tree); - if (lex != C_RPAREN) { - emit_error("missing right parenthesis in DIM"); - } else { - get_lex(); - } - new_array = array_search(array); - if (new_array != NULL) { - emit_error("array already defined"); - } else { - new_array = array_add(array); - new_array->length = c; - } - } else { - label = label_add(array); - if (array[0] == '#') - label->used = TYPE_16; - else - label->used = TYPE_8; - label->used |= LABEL_IS_VARIABLE; + } + chrrom_data = p; + /* Reset pixel data in new space */ + for (type = chrrom_size; type < c + 1; type++) + reset_chrrom(chrrom_data + chrrom_size * CHRROM_PAGE); + chrrom_size = c + 1; } - if (lex != C_COMMA) - break; + current_chrrom = c; + chrrom_pointer = 0; } } else if (strcmp(name, "MODE") == 0) { get_lex(); @@ -4545,6 +5035,7 @@ void compile_statement(int check_for_else) } else if (strcmp(name, "SCREEN") == 0) { /* Copy screen */ struct label *array; + /* !!! Implement for NES */ get_lex(); if (lex != C_NAME) { emit_error("bad syntax for SCREEN"); @@ -4866,300 +5357,90 @@ void compile_statement(int check_for_else) } if (lex == C_MINUS) { /* Nothing to do */ - } else if (arg == 0 && strcmp(name, "REPEAT") == 0) { - get_lex(); - notes = 0xfd; - break; - } else if (arg == 0 && strcmp(name, "STOP") == 0) { - get_lex(); - notes = 0xfe; - break; - } else if (arg == 3) { - if (name[0] != 'M' || name[1] < '1' || name[1] > '3') { - emit_error("bad syntax for drum in MUSIC"); - break; - } - notes |= (name[1] - '0') << ((arg & 3) * 8); - } else if (strcmp(name, "S") == 0) { - notes |= 0x3f << ((arg & 3) * 8); - } else { - notes |= previous[arg] << ((arg & 3) * 8); - c = 0; - switch (name[c++]) { - case 'C': note = 0; break; - case 'D': note = 2; break; - case 'E': note = 4; break; - case 'F': note = 5; break; - case 'G': note = 7; break; - case 'A': note = 9; break; - case 'B': note = 11; break; - default: - note = 0; - emit_error("bad syntax for note in MUSIC"); - break; - } - switch (name[c++]) { - case '2': note += 0 * 12; break; - case '3': note += 1 * 12; break; - case '4': note += 2 * 12; break; - case '5': note += 3 * 12; break; - case '6': note += 4 * 12; break; - case '7': if (note == 0) { note += 5 * 12; break; } - default: - emit_error("bad syntax for note in MUSIC"); - break; - } - note++; - if (name[c] == '#') { - note++; - c++; - } - if (name[c] == 'W') { - previous[arg] = 0x00; - notes &= ~(0xc0 << ((arg & 3) * 8)); - notes |= previous[arg] << ((arg & 3) * 8); - } else if (name[c] == 'X') { - previous[arg] = 0x40; - notes &= ~(0xc0 << ((arg & 3) * 8)); - notes |= previous[arg] << ((arg & 3) * 8); - } else if (name[c] == 'Y') { - previous[arg] = 0x80; - notes &= ~(0xc0 << ((arg & 3) * 8)); - notes |= previous[arg] << ((arg & 3) * 8); - } else if (name[c] == 'Z') { - previous[arg] = 0xc0; - notes &= ~(0xc0 << ((arg & 3) * 8)); - notes |= previous[arg] << ((arg & 3) * 8); - } - notes |= note << ((arg & 3) * 8); - } - get_lex(); - arg++; - if (lex != C_COMMA) - break; - if (arg == 4) { - emit_error("too many arguments for MUSIC"); - break; - } - get_lex(); - } - if (target == CPU_9900) { - fprintf(output, "\tbyte >%02x,>%02x,>%02x,>%02x\n", notes & 0xff, (notes >> 8) & 0xff, (notes >> 16) & 0xff, (notes >> 24) & 0xff); - } else { - fprintf(output, "\tdb $%02x,$%02x,$%02x,$%02x\n", notes & 0xff, (notes >> 8) & 0xff, (notes >> 16) & 0xff, (notes >> 24) & 0xff); - } - } else if (strcmp(name, "ON") == 0) { - struct label *label; - int table; - int c; - int max_value; - int gosub; - int fast; - struct label *options[256]; - int new_label; - int type; - - get_lex(); - if (lex == C_NAME && strcmp(name, "FRAME") == 0) { /* Frame-driven games */ - get_lex(); - if (lex != C_NAME || strcmp(name, "GOSUB") != 0) { - emit_error("Bad syntax for ON FRAME GOSUB"); - } - get_lex(); - if (lex != C_NAME) { - emit_error("Missing label for ON FRAME GOSUB"); - } - if (frame_drive != NULL) { - emit_error("More than one ON FRAME GOSUB"); - } - label = label_search(name); - if (label == NULL) { - label = label_add(name); - } - label->used |= LABEL_USED; - label->used |= LABEL_CALLED_BY_GOSUB; - frame_drive = label; - get_lex(); - } else { - type = evaluate_expression(0, 0, 0); - fast = 0; - if (lex == C_NAME && strcmp(name, "FAST") == 0) { - get_lex(); - fast = 1; - } - gosub = 0; - if (lex != C_NAME || (strcmp(name, "GOTO") != 0 && strcmp(name, "GOSUB") != 0)) { - emit_error("required GOTO or GOSUB after ON"); - } else if (strcmp(name, "GOTO") == 0) { - get_lex(); - } else if (strcmp(name, "GOSUB") == 0) { - get_lex(); - gosub = 1; - } - max_value = 0; - while (1) { - if (max_value == sizeof(options) / sizeof(struct label *)) { - emit_error("too many options for ON statement"); - max_value--; - } - if (lex == C_NAME) { - label = label_search(name); - if (label == NULL) { - label = label_add(name); - } - label->used |= LABEL_USED; - if (gosub != 0) { - label->used |= LABEL_CALLED_BY_GOSUB; - } else { - label->used |= LABEL_CALLED_BY_GOTO; - } - options[max_value++] = label; - get_lex(); - } else { - options[max_value++] = NULL; - } - if (lex != C_COMMA) - break; - get_lex(); - } - table = next_local++; - new_label = next_local++; - if (fast == 0) { - if (target == CPU_6502) { - if ((type & MAIN_TYPE) == TYPE_8) { - cpu6502_1op("STA", "temp"); - cpu6502_1op("LDY", "#0"); - cpu6502_1op("STY", "temp+1"); - sprintf(temp, "#%d", max_value); - cpu6502_1op("CMP", temp); - } else { - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); - sprintf(temp, "#%d", max_value); - cpu6502_1op("LDA", "temp"); - cpu6502_noop("SEC"); - cpu6502_1op("SBC", temp); - cpu6502_1op("LDA", "temp+1"); - strcat(temp, ">>8"); - cpu6502_1op("SBC", temp); - } - sprintf(temp, INTERNAL_PREFIX "%d", new_label); - cpu6502_1op("BCS.L", temp); - } else if (target == CPU_9900) { - if ((type & MAIN_TYPE) == TYPE_8) { - sprintf(temp, "%d ; %d*256", max_value*256, max_value); - cpu9900_2op("ci", "r0", temp); - } else { - sprintf(temp, "%d", max_value); - cpu9900_2op("ci", "r0", temp); - } - sprintf(temp, "@" INTERNAL_PREFIX "%d", new_label); - sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); - cpu9900_1op("jl", temp + 100); - cpu9900_1op("b", temp); - cpu9900_label(temp + 100); - } else { - if ((type & MAIN_TYPE) == TYPE_8) { - sprintf(temp, "%d", max_value); - cpuz80_1op("CP", temp); - } else { - sprintf(temp, "%d", max_value); - cpuz80_2op("LD", "DE", temp); - cpuz80_1op("OR", "A"); - cpuz80_2op("SBC", "HL", "DE"); - cpuz80_2op("ADD", "HL", "DE"); - } - sprintf(temp, INTERNAL_PREFIX "%d", new_label); - cpuz80_2op("JP", "NC", temp); - } - } - if (gosub) { - if (target == CPU_6502) { - sprintf(temp, "#(" INTERNAL_PREFIX "%d-1)>>8", new_label); - cpu6502_1op("LDA", temp); - cpu6502_noop("PHA"); - sprintf(temp, "#" INTERNAL_PREFIX "%d-1", new_label); - cpu6502_1op("LDA", temp); - cpu6502_noop("PHA"); - } else if (target == CPU_9900) { - sprintf(temp, INTERNAL_PREFIX "%d", new_label); - cpu9900_2op("li", "r1", temp); - cpu9900_1op("dect", "r10"); /* stack manipulation */ - cpu9900_2op("mov", "r1", "*r10"); - } else { - sprintf(temp, INTERNAL_PREFIX "%d", new_label); - cpuz80_2op("LD", "DE", temp); - cpuz80_1op("PUSH", "DE"); - } - } - if (target == CPU_6502) { - cpu6502_1op("LDA", "temp"); - cpu6502_1op("ASL", "A"); - cpu6502_1op("ROL", "temp+1"); - cpu6502_noop("CLC"); - sprintf(temp, "#" INTERNAL_PREFIX "%d", table); - cpu6502_1op("ADC", temp); - cpu6502_1op("STA", "temp"); - cpu6502_1op("LDA", "temp+1"); - strcat(temp, ">>8"); - cpu6502_1op("ADC", temp); - cpu6502_1op("STA", "temp+1"); - cpu6502_1op("LDY", "#0"); - cpu6502_1op("LDA", "(temp),Y"); - cpu6502_1op("STA", "temp2"); - cpu6502_noop("INY"); - cpu6502_1op("LDA", "(temp),Y"); - cpu6502_1op("STA", "temp2+1"); - cpu6502_1op("JMP", "(temp2)"); - } else if (target == CPU_9900) { - if ((type & MAIN_TYPE) == TYPE_8) { - cpu9900_2op("srl", "r0", "8"); + } else if (arg == 0 && strcmp(name, "REPEAT") == 0) { + get_lex(); + notes = 0xfd; + break; + } else if (arg == 0 && strcmp(name, "STOP") == 0) { + get_lex(); + notes = 0xfe; + break; + } else if (arg == 3) { + if (name[0] != 'M' || name[1] < '1' || name[1] > '3') { + emit_error("bad syntax for drum in MUSIC"); + break; } - cpu9900_2op("sla", "r0", "1"); - cpu9900_2op("mov", "r0", "r1"); - sprintf(temp, "@" INTERNAL_PREFIX "%d(r1)", table); - cpu9900_2op("mov", temp, "r0"); - cpu9900_1op("b", "*r0"); + notes |= (name[1] - '0') << ((arg & 3) * 8); + } else if (strcmp(name, "S") == 0) { + notes |= 0x3f << ((arg & 3) * 8); } else { - if ((type & MAIN_TYPE) == TYPE_8) { - cpuz80_2op("LD", "L", "A"); - if (type & TYPE_SIGNED) { - cpuz80_noop("RLA"); - cpuz80_2op("SBC", "A", "A"); - cpuz80_2op("LD", "H", "A"); - } else { - cpuz80_2op("LD", "H", "0"); - } + notes |= previous[arg] << ((arg & 3) * 8); + c = 0; + switch (name[c++]) { + case 'C': note = 0; break; + case 'D': note = 2; break; + case 'E': note = 4; break; + case 'F': note = 5; break; + case 'G': note = 7; break; + case 'A': note = 9; break; + case 'B': note = 11; break; + default: + note = 0; + emit_error("bad syntax for note in MUSIC"); + break; } - cpuz80_2op("ADD", "HL", "HL"); - sprintf(temp, INTERNAL_PREFIX "%d", table); - cpuz80_2op("LD", "DE", temp); - cpuz80_2op("ADD", "HL", "DE"); - cpuz80_2op("LD", "A", "(HL)"); - cpuz80_1op("INC", "HL"); - cpuz80_2op("LD", "H", "(HL)"); - cpuz80_2op("LD", "L", "A"); - cpuz80_1op("JP", "(HL)"); - } - sprintf(temp, INTERNAL_PREFIX "%d", table); - generic_label(temp); - for (c = 0; c < max_value; c++) { - if (options[c] != NULL) { - sprintf(temp, LABEL_PREFIX "%s", options[c]->name); - } else { - sprintf(temp, INTERNAL_PREFIX "%d", new_label); + switch (name[c++]) { + case '2': note += 0 * 12; break; + case '3': note += 1 * 12; break; + case '4': note += 2 * 12; break; + case '5': note += 3 * 12; break; + case '6': note += 4 * 12; break; + case '7': if (note == 0) { note += 5 * 12; break; } + default: + emit_error("bad syntax for note in MUSIC"); + break; } - if (target == CPU_6502) - cpu6502_1op("DW", temp); - else if (target == CPU_9900) - cpu9900_1op("data", temp); - else - cpuz80_1op("DW", temp); + note++; + if (name[c] == '#') { + note++; + c++; + } + if (name[c] == 'W') { + previous[arg] = 0x00; + notes &= ~(0xc0 << ((arg & 3) * 8)); + notes |= previous[arg] << ((arg & 3) * 8); + } else if (name[c] == 'X') { + previous[arg] = 0x40; + notes &= ~(0xc0 << ((arg & 3) * 8)); + notes |= previous[arg] << ((arg & 3) * 8); + } else if (name[c] == 'Y') { + previous[arg] = 0x80; + notes &= ~(0xc0 << ((arg & 3) * 8)); + notes |= previous[arg] << ((arg & 3) * 8); + } else if (name[c] == 'Z') { + previous[arg] = 0xc0; + notes &= ~(0xc0 << ((arg & 3) * 8)); + notes |= previous[arg] << ((arg & 3) * 8); + } + notes |= note << ((arg & 3) * 8); } - sprintf(temp, INTERNAL_PREFIX "%d", new_label); - generic_label(temp); + get_lex(); + arg++; + if (lex != C_COMMA) + break; + if (arg == 4) { + emit_error("too many arguments for MUSIC"); + break; + } + get_lex(); + } + if (target == CPU_9900) { + fprintf(output, "\tbyte >%02x,>%02x,>%02x,>%02x\n", notes & 0xff, (notes >> 8) & 0xff, (notes >> 16) & 0xff, (notes >> 24) & 0xff); + } else { + fprintf(output, "\tdb $%02x,$%02x,$%02x,$%02x\n", notes & 0xff, (notes >> 8) & 0xff, (notes >> 16) & 0xff, (notes >> 24) & 0xff); } } else if (strcmp(name, "SOUND") == 0) { + /* !!! Implement for NES */ get_lex(); if (lex != C_NUM) { emit_error("syntax error in SOUND"); @@ -5478,139 +5759,6 @@ void compile_statement(int check_for_else) fprintf(output, "%s\n", &line[line_pos]); line_pos = line_size; get_lex(); - } else if (strcmp(name, "DEF") == 0) { /* Function definition (macro in CVBasic) */ - char function[MAX_LINE_SIZE]; - int total_arguments; - char *arguments[32]; - struct macro *macro; - int c; - - get_lex(); - if (lex != C_NAME || strcmp(name, "FN") != 0) { - emit_error("syntax error for DEF FN"); - } else { - get_lex(); - if (lex != C_NAME) { - emit_error("missing function name for DEF FN"); - } else if (macro_search(name) != NULL) { - emit_error("DEF FN name already defined"); - } else { - strcpy(function, name); - get_lex(); - total_arguments = 0; - if (lex == C_LPAREN) { - get_lex(); - while (1) { - if (lex != C_NAME) { - emit_error("syntax error in argument list for DEF FN"); - break; - } - if (total_arguments == 32) { - emit_error("More than 32 arguments in DEF FN"); - break; - } - arguments[total_arguments] = malloc(strlen(name) + 1); - if (arguments[total_arguments] == NULL) { - emit_error("Out of memory in DEF FN"); - break; - } - strcpy(arguments[total_arguments], name); - total_arguments++; - get_lex(); - if (lex == C_COMMA) { - get_lex(); - } else if (lex == C_RPAREN) { - get_lex(); - break; - } else { - emit_error("syntax error in argument list for DEF FN"); - break; - } - } - } - macro = macro_add(function); - macro->total_arguments = total_arguments; - if (lex != C_EQUAL) { - emit_error("missing = in DEF FN"); - } else { - get_lex(); - while (lex != C_END) { - if (lex == C_ERR) { - emit_error("bad syntax inside DEF FN replacement text"); - break; - } - if (lex == C_NAME) { - for (c = 0; c < total_arguments; c++) { - if (strcmp(arguments[c], name) == 0) - break; - } - if (c < total_arguments) { - lex = C_ERR; - value = c; - name[0] = '\0'; - } - } - if (macro->length >= macro->max_length) { - macro->definition = realloc(macro->definition, (macro->max_length + 1) * 2 * sizeof(struct macro_def)); - if (macro->definition == NULL) { - emit_error("Out of memory in DEF FN"); - break; - } - macro->max_length = (macro->max_length + 1) * 2; - } - macro->definition[macro->length].lex = lex; - if (lex == C_STRING) - value = name_size; - macro->definition[macro->length].value = value; - if (lex == C_STRING) - macro->definition[macro->length].name = malloc(name_size + 1); - else - macro->definition[macro->length].name = malloc(strlen(name) + 1); - if (macro->definition[macro->length].name == NULL) { - emit_error("Out of memory in DEF FN"); - break; - } - if (lex == C_STRING) { - if (value) - memcpy(macro->definition[macro->length].name, name, value); - } else { - strcpy(macro->definition[macro->length].name, name); - } - macro->length++; - get_lex(); - } - } - } - } - } else if (strcmp(name, "OPTION") == 0) { - get_lex(); - if (lex != C_NAME) { - emit_error("required name after OPTION"); - } else if (strcmp(name, "EXPLICIT") == 0) { - get_lex(); - if (lex == C_NAME && strcmp(name, "ON") == 0) { - get_lex(); - option_explicit = 1; - } else if (lex == C_NAME && strcmp(name, "OFF") == 0) { - get_lex(); - option_explicit = 0; - } else { - option_explicit = 1; - } - } else if (strcmp(name, "WARNINGS") == 0) { - get_lex(); - if (lex == C_NAME && strcmp(name, "ON") == 0) { - get_lex(); - option_warnings = 1; - } else if (lex == C_NAME && strcmp(name, "OFF") == 0) { - get_lex(); - option_warnings = 0; - } else { - emit_error("missing ON/OFF in OPTION WARNINGS"); - } - } else { - emit_error("non-recognized OPTION"); - } } else if (strcmp(name, "BANK") == 0) { get_lex(); if (lex == C_NAME && strcmp(name, "ROM") == 0) { @@ -5798,11 +5946,15 @@ void compile_statement(int check_for_else) get_lex(); type = evaluate_expression(1, TYPE_8, 0); if (target == CPU_6502) { - sprintf(temp, "#%d", vdp_reg); - cpu6502_1op("LDX", temp); - generic_interrupt_disable(); - cpu6502_1op("JSR", "WRTVDP"); - generic_interrupt_enable(); + if (machine == NES) { + emit_error("VDP not supported for NES/Famicom"); + } else { + sprintf(temp, "#%d", vdp_reg); + cpu6502_1op("LDX", temp); + generic_interrupt_disable(); + cpu6502_1op("JSR", "WRTVDP"); + generic_interrupt_enable(); + } } else if (target == CPU_9900) { /* Simpler to do inline */ sprintf(temp, "%d ; %d*256+0x8000", vdp_reg*256+0x8000, vdp_reg); diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 811bae2..8730a6b 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -6,6 +6,7 @@ ; ; Creation date: May/13/2025. ; Revision date: Jul/20/2025. Added code to load sprites and read controllers. + ; Revision date: Aug/23/2025. Support for writing VRAM and PRINT. ; CPU 6502 @@ -101,6 +102,74 @@ SPRRAM: EQU $4014 CONT1: EQU $4016 CONT2: EQU $4017 + ; + ; NES architecture prevents direct access to VRAM except + ; during the VBLANK. + ; +WRTVRM: + PHA + TXA + PHA + LDX ppu_pointer + PLA + STA PPUBUF+2,X + PLA + STA PPUBUF,X + TYA + ORA #$40 + STA PPUBUF+1,X + INX + INX + INX + STX ppu_pointer + RTS + +CLS: + LDX ppu_pointer + LDA #$20 + STA PPUBUF+3,X + LDA #$00 + STA PPUBUF+2,X + LDA #$00 + STA PPUBUF,X + LDA #$a0 + STA PPUBUF+1,X + LDA #$20 + STA PPUBUF+7,X + LDA #$00 + STA PPUBUF+6,X + LDA #$00 + STA PPUBUF+4,X + LDA #$a1 + STA PPUBUF+5,X + TXA + CLC + ADC #8 + STA ppu_pointer + JSR wait + LDX ppu_pointer + LDA #$20 + STA PPUBUF+3,X + LDA #$00 + STA PPUBUF+2,X + LDA #$00 + STA PPUBUF+0,X + LDA #$a2 + STA PPUBUF+1,X + LDA #$20 + STA PPUBUF+7,X + LDA #$00 + STA PPUBUF+6,X + LDA #$00 + STA PPUBUF+4,X + LDA #$a3 + STA PPUBUF+5,X + TXA + CLC + ADC #8 + STA ppu_pointer + RTS + update_sprite: ASL A ASL A @@ -464,6 +533,9 @@ nmi_handler: .0: LDA PPUBUF+1,X STA PPUADDR BMI .2 + ROL A + BMI .7 + LDA PPUBUF,X STA PPUADDR LDA PPUBUF+3,X @@ -488,6 +560,20 @@ nmi_handler: BNE .0 JMP .1 + ; Single byte +.7: + LDA PPUBUF,X + STA PPUADDR + LDA PPUBUF+2,X + STA PPUDATA + TXA + CLC + ADC #3 + TAX + CPX ppu_pointer + BNE .0 + JMP .1 + ; Filling data .2: LDA PPUBUF,X @@ -645,6 +731,173 @@ wait: BEQ .1 RTS +print_string_cursor_constant: + PLA + STA temp + PLA + STA temp+1 + LDY #1 + LDA (temp),Y + STA cursor + INY + LDA (temp),Y + STA cursor+1 + INY + LDA (temp),Y + STA temp2 + TYA + CLC + ADC temp + STA temp + BCC $+4 + INC temp+1 + LDA temp2 + BNE print_string.2 + +print_string_cursor: + STA cursor + STY cursor+1 +print_string: + PLA + STA temp + PLA + STA temp+1 + LDY #1 + LDA (temp),Y + STA temp2 + INC temp + BNE $+4 + INC temp+1 +.2: CLC + ADC temp + TAY + LDA #0 + ADC temp+1 + PHA + TYA + PHA + INC temp + BNE $+4 + INC temp+1 + LDX ppu_pointer + LDA cursor + STA PPUBUF,X + LDA cursor+1 + AND #$07 + ORA #$20 + STA PPUBUF+1,X + LDA temp2 + STA PPUBUF+2,X + LDA temp + STA PPUBUF+3,X + LDA temp+1 + STA PPUBUF+4,X + TXA + CLC + ADC #5 + STA ppu_pointer + LDA temp2 + CLC + ADC cursor + STA cursor + BCC .1 + INC cursor+1 +.1: + RTS + +print_number: + LDX #0 + STX temp + SEI +print_number5: + LDX #10000 + STX temp2 + LDX #10000/256 + STX temp2+1 + JSR print_digit +print_number4: + LDX #1000 + STX temp2 + LDX #1000/256 + STX temp2+1 + JSR print_digit +print_number3: + LDX #100 + STX temp2 + LDX #0 + STX temp2+1 + JSR print_digit +print_number2: + LDX #10 + STX temp2 + LDX #0 + STX temp2+1 + JSR print_digit +print_number1: + LDX #1 + STX temp2 + STX temp + LDX #0 + STX temp2+1 + JSR print_digit + CLI + RTS + +print_digit: + LDX #$2F +.2: + INX + SEC + SBC temp2 + PHA + TYA + SBC temp2+1 + TAY + PLA + BCS .2 + CLC + ADC temp2 + PHA + TYA + ADC temp2+1 + TAY + PLA + CPX #$30 + BNE .3 + LDX temp + BNE .4 + RTS + +.4: DEX + BEQ .6 + LDX temp+1 + BNE print_char +.6: + LDX #$30 +.3: PHA + LDA #1 + STA temp + PLA + +print_char: + PHA + TYA + PHA + LDA cursor+1 + AND #$07 + ORA #$20 + TAY + LDA cursor + JSR WRTVRM + INC cursor + BNE .1 + INC cursor+1 +.1: + PLA + TAY + PLA + RTS + music_init: RTS @@ -657,6 +910,20 @@ music_generate: music_hardware: RTS +mode_0: + JSR cls +clear_sprites: + LDA #$F0 + LDX #0 +.1: + STA $0200,X + INX + INX + INX + INX + BNE .1 + RTS + START: SEI CLD @@ -675,7 +942,6 @@ START: TAX .1: STA $00,X STA $0100,X - STA $0200,X STA $0300,X STA $0400,X STA $0500,X @@ -687,6 +953,8 @@ START: LDX #STACK TXS + JSR clear_sprites + ; ; The NES starts with the PPU registers write-protected. ; Around 29000 cycles must happen before these can be written. @@ -751,7 +1019,7 @@ START: JSR music_init -; JSR mode_0 + JSR mode_0 LDA #$00 STA joy1_data diff --git a/examples/happy_face_nes.bas b/examples/happy_face_nes.bas index 2d6aab0..c4096d2 100644 --- a/examples/happy_face_nes.bas +++ b/examples/happy_face_nes.bas @@ -8,9 +8,9 @@ ' Revision date: Aug/23/2025. Adapted for NES. ' -' DEFINE SPRITE 0,1,happy_face + PALETTE $13, $38 ' Yellow face -' PRINT AT 36,"Happy face!" + PRINT AT 68,"Happy face!" x = 50 y = 100 diff --git a/manual.txt b/manual.txt index f4e2947..824c559 100644 --- a/manual.txt +++ b/manual.txt @@ -22,9 +22,21 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.8.1 Jun/05/2025 o MSX: Added support for Konami mapper using -konami +v0.9.0 Aug/23/2025 o Added support for NES/Famicom using --nes + o MSX: Added support for Konami mapper using -konami o Solved bug in DEF FN precedence inside expressions. - o Corrected bug in CHR$ and DEFINE VRAM READ for TI-99/4A. + o Solved bug in > operator with 16-bit variable. + o NABU: Solved bug where compilation would warn of both + sound chips. + o TI-99/4A: Corrected bug in CHR$ and DEFINE VRAM READ. + o TI-99/4A: Solved bugs doing operations with 8-bit + variables and 16-bit values. + o TI-99/4A: Solved bug in multiplication by 1. + o TI-99/4A: Solved bug in SELECT CASE. + o TI-99/4A: Solved bug in DEFINE COLOR PLETTER. + o TI-99/4A: Optimizes more operations with constants. + o TI-99/4A: Added more optimization using register labeling, + saves many bytes, and speeds up. v0.8.0 Apr/26/2025 o Added support for Sega Master System using --sms o Added support for VDP.STATUS (for reading VDP status) @@ -86,7 +98,7 @@ v0.5.1 Jun/25/2024 o Added SIGNED and UNSIGNED keywords to tag variables >>>>>>>>>>>>>>. Description -CVBasic is an integer BASIC compiler for Colecovision, MSX, Sega SG1000, Spectravideo SVI-318/328, Sord M5, Memotech MTX, Creativision, Soundic Pencil II, Tatung Einstein, Casio PV-2000, TI-99/4A, NABU PC, and Sega Master System. +CVBasic is an integer BASIC compiler for Colecovision, MSX, Sega SG1000, Spectravideo SVI-318/328, Sord M5, Memotech MTX, Creativision, Soundic Pencil II, Tatung Einstein, Casio PV-2000, TI-99/4A, NABU PC, Sega Master System, and NES/Famicom. It works as a cross-compiler over a PC and generates assembler code that can be processed by Gasm80. @@ -117,6 +129,7 @@ Usage: cvbasic --ti994a in.bas output.a99 cvbasic --nabu in.bas output.asm cvbasic --sms in.bas output.asm + cvbasic --nes in.bas output.asm The following modules are automatically included as the prologue and epilogue of your generated code and they set important variables and helper code: @@ -133,6 +146,8 @@ The Creativision port uses cvbasic_6502_prologue.asm and cvbasic_6502_epilogue.a The TI-99/4A port uses cvbasic_9900_prologue.asm and cvbasic_9900_epilogue.asm and it should be assembled using xdt tools. (xas99 with the -R option) +The NES/Famicom port uses cvbasic_nes_prologue.asm and cvbasic_nes_epilogue.asm + The NABU port requires the gasm output file to be named 000001.nabu and you should ZIP it to test it with MAME. If you use the -cpm option you can use any .com file name. And finally, you can test the generated output.rom file using CoolCV, blueMSX, openMSX, or a Flash cartridge for real hardware. @@ -513,6 +528,8 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) + This sentence isn't supported for NES/Famicom. + DEFINE COLOR char_num,total,label DEFINE COLOR char_num,total,VARPTR array(expr) DEFINE COLOR PLETTER char_num,total,label @@ -541,6 +558,8 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) + This sentence isn't supported for NES/Famicom. + DEFINE SPRITE sprite_num,total,label DEFINE SPRITE sprite_num,total,VARPTR array(expr) DEFINE SPRITE PLETTER sprite_num,total,label @@ -564,6 +583,8 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) + This sentence isn't supported for NES/Famicom. + DEFINE VRAM address,length,label DEFINE VRAM address,length,VARPTR array(expr) DEFINE VRAM PLETTER address,length,label @@ -578,6 +599,8 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) + This sentence isn't supported for NES/Famicom. + DEFINE VRAM READ address,length,label DEFINE VRAM READ address,length,VARPTR array(expr) @@ -587,6 +610,8 @@ The following statements are available: The VARPTR expression allows choosing the origin from an offset inside an array. + This sentence isn't supported for NES/Famicom. + SOUND 0,[value 10 bits],[vol 0-15] SOUND 1,[value 10 bits],[vol 0-15] SOUND 2,[value 10 bits],[vol 0-15] @@ -633,8 +658,9 @@ The following statements are available: NOTE: USE ONLY VALUES $80-$BF FOR MIX BECAUSE ANY VALUE OUTSIDE THIS CAN BURN YOUR MSX HARDWARE. - SPRITE index,y,x,f,c - SPRITE index,y,x,f + SPRITE index,y,x,f,c (All others) + SPRITE index,y,x,f. (SMS) + SPRITE index,y,x,f,a (NES/Famicom) The first parameter indicates the number of the sprite (0-31). @@ -668,6 +694,17 @@ The following statements are available: processing starting on that very sprite. For example, SPRITE 0,$d0,0,0,0 forces sprites 1-31 to disappear even if active. + NES/Famicom notes: + + y = Vertical position - 1 ($ff, $00 - $ee = scanline 0..239) + To hide sprites use $f0 ($ef - $fe aren't displayed) + x = Horizontal position. + f = bit 7-1 = tile, bit 0 = pattern address ($0000 or $1000) + a = bit 7 = 1 = Vertical flip. + bit 6 = 1 = Horizontal flip. + bit 5 = 1 = Sprite behind background. + bit 4-2 = Reserved. + bit 1-0 = Sprite palette (0-3) SPRITE FLICKER ON SPRITE FLICKER OFF @@ -714,6 +751,10 @@ The following statements are available: PRINT AT 736,"A" ' Bottom-left corner PRINT AT 767,"A" ' Bottom-right corner + NES/Famicom allows for a 32x30 screen area (960 characters), + however, only the center area (28 rows) can be guaranteed + to be visible. + PRINT expr PRINT expr ' Right-aligned with zeroes to 'const' size. PRINT <.const>expr ' Right-aligned with spaces to 'const' size. @@ -736,6 +777,7 @@ The following statements are available: BORDER color,flags Select the border color. It can be a number from 0 to 15. + The first argument isn't available for NES/Famicom. The flags argument is available on Sega Master System. bit 0 = Set column 0 to border color. From 2b1f811eaa555a79055bcf40fc30c37c64f8b652 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 17:04:22 -0600 Subject: [PATCH 064/155] NES added sound support and Viboritas game --- cvbasic.c | 123 ++++++- cvbasic_nes_prologue.asm | 31 +- examples/viboritas_nes.bas | 731 +++++++++++++++++++++++++++++++++++++ 3 files changed, 870 insertions(+), 15 deletions(-) create mode 100644 examples/viboritas_nes.bas diff --git a/cvbasic.c b/cvbasic.c index c66c584..4b08c63 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5440,16 +5440,19 @@ void compile_statement(int check_for_else) fprintf(output, "\tdb $%02x,$%02x,$%02x,$%02x\n", notes & 0xff, (notes >> 8) & 0xff, (notes >> 16) & 0xff, (notes >> 24) & 0xff); } } else if (strcmp(name, "SOUND") == 0) { - /* !!! Implement for NES */ get_lex(); if (lex != C_NUM) { emit_error("syntax error in SOUND"); } else { - if (value < 3 && (machine == MSX || machine == SVI || machine == EINSTEIN || machine == NABU)) + if (value < 10 && machine == NES) { + emit_warning("using SOUND 0-9 with NES/Famicom target"); + } else if (value >= 0 && value <= 4 && (machine == MSX || machine == SVI || machine == EINSTEIN || machine == NABU)) { emit_warning("using SOUND 0-3 with AY-3-8910 target"); - else if (value >= 5 && machine != MSX && machine != COLECOVISION_SGM && machine != SVI && machine != SORD && machine != MEMOTECH && machine != NABU) + } else if (value >= 5 && value <= 9 && machine != MSX && machine != COLECOVISION_SGM && machine != SVI && machine != SORD && machine != MEMOTECH && machine != NABU) { emit_warning("using SOUND 5-9 with SN76489 target"); + } switch (value) { + /* Sound handling for SN76489 */ case 0: get_lex(); if (lex != C_COMMA) { @@ -5567,6 +5570,7 @@ void compile_statement(int check_for_else) generic_call("sn76489_vol"); } break; + /* Sound handling for AY-3-8910 */ case 5: get_lex(); if (lex != C_COMMA) { @@ -5729,6 +5733,119 @@ void compile_statement(int check_for_else) } } break; + /* Sound handling for NES */ + case 10: + get_lex(); + if (lex != C_COMMA) { + emit_error("missing comma in sound"); + } else { + get_lex(); + } + if (lex != C_COMMA) { + type = evaluate_expression(1, TYPE_16, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4002"); + cpu6502_1op("STY", "$4003"); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4000"); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4001"); + } + } + break; + case 11: + get_lex(); + if (lex != C_COMMA) { + emit_error("missing comma in sound"); + } else { + get_lex(); + } + if (lex != C_COMMA) { + type = evaluate_expression(1, TYPE_16, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4006"); + cpu6502_1op("STY", "$4007"); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4004"); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4005"); + } + } + break; + case 12: + get_lex(); + if (lex != C_COMMA) { + emit_error("missing comma in sound"); + } else { + get_lex(); + } + if (lex != C_COMMA) { + type = evaluate_expression(1, TYPE_16, 0); + if (machine == NES) { + cpu6502_1op("STA", "$400a"); + cpu6502_1op("STY", "$400b"); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4008"); + } + } + break; + case 14: + get_lex(); + if (lex != C_COMMA) { + emit_error("missing comma in sound"); + } else { + get_lex(); + } + if (lex != C_COMMA) { + type = evaluate_expression(1, TYPE_16, 0); + if (machine == NES) { + cpu6502_1op("STA", "$400e"); + cpu6502_1op("STY", "$400f"); + } + } + if (lex == C_COMMA) { + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$400c"); + } + } + break; + case 15: + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (machine == NES) { + cpu6502_1op("STA", "$4015"); + } + break; + default: + emit_error("SOUND with unhandled channel number"); + break; } } } else if (strcmp(name, "CALL") == 0) { /* Call assembly language */ diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 8730a6b..c818ae7 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -122,7 +122,10 @@ WRTVRM: INX INX STX ppu_pointer + BMI .1 RTS +.1: + JMP wait CLS: LDX ppu_pointer @@ -566,10 +569,9 @@ nmi_handler: STA PPUADDR LDA PPUBUF+2,X STA PPUDATA - TXA - CLC - ADC #3 - TAX + INX + INX + INX CPX ppu_pointer BNE .0 JMP .1 @@ -594,6 +596,13 @@ nmi_handler: .1: LDA #0 STA ppu_pointer + ; Final settings for PPU + LDA #0 + STA PPUADDR + STA PPUADDR + STA PPUSCROLL ; !!! For scrolling + STA PPUSCROLL + ; Read controllers LDA #$01 STA CONT1 @@ -682,13 +691,6 @@ nmi_handler: PLA STA temp+0 - ; Final settings for PPU - LDA #0 - STA PPUADDR - STA PPUADDR - STA PPUSCROLL ; !!! For scrolling - STA PPUSCROLL - PLA TAY PLA @@ -932,8 +934,13 @@ START: LDA #$40 STA $4017 + LDA #$10 + STA $4000 ; Channel 1 silent + STA $4004 ; Channel 2 silent + STA $400C ; Channel 4 silent + LDA #$0b + STA $4015 ; Enable channel 1, 2 and 4. LDA #$00 - STA $4015 STA $4010 STA PPUCTRL diff --git a/examples/viboritas_nes.bas b/examples/viboritas_nes.bas new file mode 100644 index 0000000..52befb0 --- /dev/null +++ b/examples/viboritas_nes.bas @@ -0,0 +1,731 @@ + ' + ' Viboritas (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Oct/1990. + ' Revision date: Feb/29/2024. Ported to CVBasic. + ' Revision date: Aug/23/2025. Adapted to NES. + ' + + ' The original game was made in Z80 assembler, + ' you can see it here: https://nanochess.org/viboritas.html + + ' It is easier to understand in CVBasic ;) + + DIM #ladders(15) + +restart_game: + lives = 2 + level = 1 +restart_level: + + PRINT AT 780,"Lives: ",lives + PRINT AT 841,"nanochess 1990" + + ' Palette for the player + PALETTE 17,$12 + PALETTE 18,$2c + PALETTE 19,$36 + + ' Palette for snakes + PALETTE 21,$0F + PALETTE 22,$30 + PALETTE 23,$2a + +next_level: + GOSUB draw_level + + x_player = 8 + y_player = 16 + player_frame = 0 + + x_enemy1 = random(128) + 64 + y_enemy1 = 56 + enemy1_frame = 24 + x_enemy2 = random(128) + 80 + y_enemy2 = 96 + enemy2_frame = 32 + x_enemy3 = random(128) + 48 + y_enemy3 = 136 + enemy3_frame = 24 + + enemy_speed = 0 + + GOSUB start_song + +game_loop: + WHILE 1 + WAIT + GOSUB play_song + + SPRITE 0, y_player + 23, x_player, player_frame + 1, 0 + SPRITE 1, y_player + 23, x_player + 8, player_frame + 3, 0 + SPRITE 2, y_enemy1 + 23, x_enemy1, enemy1_frame + 1, 1 + SPRITE 3, y_enemy1 + 23, x_enemy1 + 8, enemy1_frame + 3, 1 + SPRITE 4, y_enemy2 + 23, x_enemy2, enemy2_frame + 1, 1 + SPRITE 5, y_enemy2 + 23, x_enemy2 + 8, enemy2_frame + 3, 1 + SPRITE 6, y_enemy3 + 23, x_enemy3, enemy3_frame + 1, 1 + SPRITE 7, y_enemy3 + 23, x_enemy3 + 8, enemy3_frame + 3, 1 + + GOSUB move_player + + c = $50 + level * 4 + enemy_speed = enemy_speed + c + WHILE enemy_speed >= $40 + enemy_speed = enemy_speed - $40 + GOSUB move_enemies + WEND + IF cont1.button THEN + IF x_player > 232 AND x_player < 248 AND y_player = 136 THEN + GOSUB sound_off + + FOR c = 1 to 10 + WAIT +' SOUND 10, 200 - c * 10, 13 + 16 + NEXT c + + level = level + 1 + IF level = 6 THEN + GOSUB sound_off + PRINT AT 267," YOU WIN! " + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + level = 1 + GOTO restart_level + END IF + GOTO next_level + END IF + END IF + IF ABS(y_player + 1 - y_enemy1) < 8 THEN + IF ABS(x_player + 1 - x_enemy1) < 8 THEN GOTO player_dies + END IF + IF ABS(y_player + 1 - y_enemy2) < 8 THEN + IF ABS(x_player + 1 - x_enemy2) < 8 THEN GOTO player_dies + END IF + IF ABS(y_player + 1 - y_enemy3) < 8 THEN + IF ABS(x_player + 1 - x_enemy3) < 8 THEN GOTO player_dies + END IF + WEND + +player_dies: + GOSUB sound_off + + SOUND 10,640,13 + 48 + SOUND 11,320,13 + 48 + + player_frame = 0 + FOR c = 0 TO 30 + WAIT + WAIT + player_frame = player_frame XOR 8 + SPRITE 0, y_player + 23, x_player, player_frame + 1, 0 + SPRITE 1, y_player + 23, x_player + 8, player_frame + 3, 0 + NEXT c + + GOSUB sound_off + + DO + WAIT + SOUND 10,200 - y_player,13 + 48 + player_frame = player_frame XOR 8 + SPRITE 0, y_player + 23, x_player, player_frame + 1, 0 + SPRITE 1, y_player + 23, x_player + 8, player_frame + 3, 0 + y_player = y_player + 2 + LOOP WHILE y_player < 160 + + GOSUB sound_off + + IF lives = 0 THEN + PRINT AT 267," GAME OVER " + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + GOTO restart_game + END IF + lives = lives - 1 + GOTO restart_level + + ' + ' Draw the current level. + ' +draw_level: PROCEDURE + + FOR c = 0 TO 63 + SPRITE c, $f0, 0, 0, 0 + NEXT c + + ' Clean the screen in a curtain to hide palette change + FOR #c = $2060 TO $207F + FOR #d = #c TO #c + $280 STEP 32 + VPOKE #d, 32 + NEXT #d + WAIT + NEXT #c + + c = (level - 1) * 4 + PALETTE 4, palette_screens(c) + PALETTE 5, palette_screens(c + 1) + PALETTE 6, palette_screens(c + 2) + PALETTE 7, palette_screens(c + 3) + + ' Select palette 1 for game tiles + ' Indicators in the bottom are still in palette 0 + FOR #c = $23c0 TO $23ef + VPOKE #c, $55 + NEXT #c + + ' Get the base character to draw the level. + base_character = 128 + (level - 1) * 4 + + ' Draw the background. + FOR #c = $2060 TO $22DC STEP 4 + VPOKE #c, base_character + VPOKE #c + 1, base_character + VPOKE #c + 2, base_character + VPOKE #c + 3, base_character + 1 + NEXT #c + + ' Draw over the floors. + FOR #c = $20e0 TO $22c0 STEP 160 + FOR #d = #c TO #c + 31 + VPOKE #d, base_character + 2. + NEXT #d + NEXT #c + + ' Draw the ladders. + ladders = 6 - level + + next_ladder = 0 + + FOR #c = $20e0 TO $2220 STEP 160 + FOR d = 1 TO ladders + e = (RANDOM(28) + 2) + #ladders(next_ladder) = #c + e + next_ladder = next_ladder + 1 + VPOKE #c + e, base_character + 3. + VPOKE #c + e + 32, base_character + 3. + VPOKE #c + e + 64, base_character + 3. + VPOKE #c + e + 96, base_character + 3. + VPOKE #c + e + 128, base_character + 3. + NEXT d + NEXT #c + + ' Draw the "exit". + VPOKE $22be, 148 + + END + + ' + ' Move the player + ' +move_player: PROCEDURE + IF cont1.left THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor + IF x_player > 0 THEN x_player = x_player - 1 + IF FRAME AND 4 THEN player_frame = 8 ELSE player_frame = 12 + END IF + END IF + IF cont1.right THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor + IF x_player < 240 THEN x_player = x_player + 1 + IF FRAME AND 4 THEN player_frame = 0 ELSE player_frame = 4 + END IF + END IF + IF cont1.up THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor. + column = (x_player + 7) /8 + row = (y_player + 8) / 8 + #c = $2060 + row * 32 + column + FOR c = 0 TO next_ladder - 1 + IF #c >= #ladders(c) THEN + #d = #c - #ladders(c) + IF (#d AND $1F) = 0 THEN ' Centered horizontally? + IF #d < $a0 THEN ' Over ladder? + y_player = y_player - 1 + END IF + END IF + END IF + NEXT c + ELSE + IF FRAME AND 4 THEN player_frame = 16 ELSE player_frame = 20 + y_player = y_player - 1 + END IF + END IF + IF cont1.down THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor. + column = (x_player + 7) /8 + row = (y_player + 16) / 8 + #c = $2060 + row * 32 + column + FOR c = 0 TO next_ladder - 1 + IF #c >= #ladders(c) THEN + #d = #c - #ladders(c) + IF (#d AND $1F) = 0 THEN ' Centered horizontally? + IF #d < $a0 THEN ' Over ladder? + y_player = y_player + 1 + END IF + END IF + END IF + NEXT c + ELSE + IF FRAME AND 4 THEN player_frame = 16 ELSE player_frame = 20 + y_player = y_player + 1 + END IF + END IF + END + + ' + ' Move the enemies. + ' +move_enemies: PROCEDURE + IF enemy1_frame < 32 THEN + x_enemy1 = x_enemy1 - 1. + IF x_enemy1 = 0 THEN enemy1_frame = 32 + ELSE + x_enemy1 = x_enemy1 + 1. + IF x_enemy1 = 240 THEN enemy1_frame = 24 + END IF + enemy1_frame = (enemy1_frame AND $f8) + (FRAME AND 4) + + IF enemy2_frame < 32 THEN + x_enemy2 = x_enemy2 - 1. + IF x_enemy2 = 0 THEN enemy2_frame = 32 + ELSE + x_enemy2 = x_enemy2 + 1. + IF x_enemy2 = 240 THEN enemy2_frame = 24 + END IF + enemy2_frame = (enemy2_frame AND $f8) + (FRAME AND 4) + + IF enemy3_frame < 32 THEN + x_enemy3 = x_enemy3 - 1. + IF x_enemy3 = 0 THEN enemy3_frame = 32 + ELSE + x_enemy3 = x_enemy3 + 1. + IF x_enemy3 = 240 THEN enemy3_frame = 24 + END IF + enemy3_frame = (enemy3_frame AND $f8) + (FRAME AND 4) + END + +palette_screens: + DATA BYTE $0F,$2A,$2C,$28 + DATA BYTE $0F,$02,$12,$10 + DATA BYTE $0F,$07,$17,$12 + DATA BYTE $0F,$17,$27,$10 + DATA BYTE $0F,$16,$2A,$10 + + CHRROM 0 + + CHRROM PATTERN 128 + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "111..111" + BITMAP "111..111" + BITMAP "111..111" + BITMAP "111..111" + BITMAP "111..111" + BITMAP "111..111" + BITMAP "111..111" + BITMAP "111..111" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "........" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "........" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP ".2....2." + BITMAP ".2....2." + BITMAP ".222222." + BITMAP ".2....2." + BITMAP ".2....2." + BITMAP ".222222." + BITMAP ".2....2." + BITMAP ".2....2." + + BITMAP "22222221" + BITMAP "21111121" + BITMAP "21222121" + BITMAP "21212121" + BITMAP "21222121" + BITMAP "21111121" + BITMAP "22222221" + BITMAP "11111111" + + BITMAP "2.222.2." + BITMAP "2.222.2." + BITMAP "2.222.2." + BITMAP "2.222.2." + BITMAP "2.222.2." + BITMAP "2.222.2." + BITMAP "2.222.2." + BITMAP "2.222.2." + + BITMAP "333.333." + BITMAP "........" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".1....1." + BITMAP ".1....1." + BITMAP ".111111." + BITMAP ".1....1." + BITMAP ".1....1." + BITMAP ".111111." + BITMAP ".1....1." + BITMAP ".1....1." + + BITMAP "11121111" + BITMAP "11121111" + BITMAP "11121111" + BITMAP "22222222" + BITMAP "11111112" + BITMAP "11111112" + BITMAP "11111112" + BITMAP "22222222" + + BITMAP ".222222." + BITMAP ".222222." + BITMAP ".222222." + BITMAP "........" + BITMAP ".22.222." + BITMAP ".22.222." + BITMAP ".22.222." + BITMAP "........" + + BITMAP "........" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "3.3.3.3." + BITMAP ".3...3.." + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".3....3." + BITMAP ".3....3." + BITMAP ".333333." + BITMAP ".3....3." + BITMAP ".3....3." + BITMAP ".333333." + BITMAP ".3....3." + BITMAP ".3....3." + + BITMAP "111.111." + BITMAP "111.111." + BITMAP "111.111." + BITMAP "........" + BITMAP "111.111." + BITMAP "111.111." + BITMAP "111.111." + BITMAP "........" + + BITMAP ".2......" + BITMAP "..22...." + BITMAP "....22.." + BITMAP "......22" + BITMAP "....22.." + BITMAP "..22...." + BITMAP ".2......" + BITMAP ".2......" + + BITMAP "........" + BITMAP "33333333" + BITMAP "........" + BITMAP "1.1.1.1." + BITMAP ".1.1.1.1" + BITMAP "........" + BITMAP "33333333" + BITMAP "........" + + BITMAP "3......3" + BITMAP "3......3" + BITMAP "33....33" + BITMAP "3.3333.3" + BITMAP "3......3" + BITMAP "3......3" + BITMAP "33....33" + BITMAP "3.3333.3" + + BITMAP "1......1" + BITMAP ".1.11..." + BITMAP "..11.111" + BITMAP ".1...111" + BITMAP "..111..1" + BITMAP "..1..111" + BITMAP ".1..1..1" + BITMAP "..1..111" + + BITMAP ".2...222" + BITMAP ".2..2..2" + BITMAP "..2..222" + BITMAP ".2......" + BITMAP "..2.2..." + BITMAP "...2.2.2" + BITMAP "...2..2." + BITMAP "..2..222" + + BITMAP "........" + BITMAP "11111113" + BITMAP "11111113" + BITMAP "33333333" + BITMAP "11131111" + BITMAP "11131111" + BITMAP "33333333" + BITMAP "........" + + BITMAP "....22.." + BITMAP "....22.." + BITMAP "...22..." + BITMAP "...22..." + BITMAP "..22...." + BITMAP "..22...." + BITMAP "...22..." + BITMAP "...22..." + + BITMAP ".3.3.3.." + BITMAP "3333333." + BITMAP ".3.3.3.." + BITMAP "3333333." + BITMAP ".3.3.3.." + BITMAP "3333333." + BITMAP ".3.3.3.." + BITMAP "........" + + CHRROM PATTERN 256 + + BITMAP ".......1.1.1...." + BITMAP ".....11111311..." + BITMAP "....111333331..." + BITMAP ".....11333331..." + BITMAP "....113333131..." + BITMAP ".....11313331..." + BITMAP "....122311131..." + BITMAP "..1222213331...." + BITMAP ".122122211111..." + BITMAP "12211222212221.." + BITMAP "12221222212221.." + BITMAP "1222121111111..." + BITMAP ".111112222111..." + BITMAP "...12221222221.." + BITMAP "...122211222221." + BITMAP "...12222111111.." + + BITMAP "......11111111.." + BITMAP ".....111333331.." + BITMAP "......11333331.." + BITMAP ".....113333131.." + BITMAP "......13313331.." + BITMAP ".....122311131.." + BITMAP ".....12213331..." + BITMAP "....12222111...." + BITMAP "....1222221....." + BITMAP "....12212221...." + BITMAP "....12212221...." + BITMAP "....1222111....." + BITMAP ".....122221....." + BITMAP ".....1221......." + BITMAP ".....122221....." + BITMAP ".....1222221...." + + BITMAP "....1.1.1......." + BITMAP "...11111111....." + BITMAP "...133333111...." + BITMAP "...13333311....." + BITMAP "...131333311...." + BITMAP "...13331311....." + BITMAP "...131113321...." + BITMAP "....1333122221.." + BITMAP ".....1112221221." + BITMAP "..12221222211221" + BITMAP "..12221222212221" + BITMAP "...111.111212221" + BITMAP "...111222211111." + BITMAP "..12222212221..." + BITMAP ".122222112221..." + BITMAP "..11111122221..." + + BITMAP "..11111111......" + BITMAP "..133333111....." + BITMAP "..13333311......" + BITMAP "..131333311....." + BITMAP "..13331311......" + BITMAP "..131113311....." + BITMAP "...13331221....." + BITMAP "....11122221...." + BITMAP ".....1222221...." + BITMAP "....12221221...." + BITMAP "....12221221...." + BITMAP ".....1112221...." + BITMAP ".....122221....." + BITMAP "......11221....." + BITMAP ".....122221....." + BITMAP "....1222221....." + + BITMAP "...111111111...." + BITMAP "....1111111....." + BITMAP "...111111111...." + BITMAP "...111111111111." + BITMAP "....111111112221" + BITMAP "....111111112221" + BITMAP ".....1333112211." + BITMAP "...1221112221..." + BITMAP ".11221222211...." + BITMAP "12221.1111......" + BITMAP "12221122221....." + BITMAP ".111.12112211..." + BITMAP "....1221.12221.." + BITMAP "...11221.122221." + BITMAP "..122221..1111.." + BITMAP ".1222221........" + + BITMAP "....111111111..." + BITMAP ".....1111111...." + BITMAP "....111111111..." + BITMAP ".111111111111..." + BITMAP "122211111111...." + BITMAP "122211111111...." + BITMAP ".11221133311...." + BITMAP "...1222111221..." + BITMAP "....11222212211." + BITMAP "......1111.12221" + BITMAP ".....12222112221" + BITMAP "...11221121.111." + BITMAP "..12221.1221...." + BITMAP ".12221..12211..." + BITMAP "..111...122221.." + BITMAP "........1222221." + + BITMAP "..1331311......." + BITMAP ".13233211......." + BITMAP ".13233211......." + BITMAP ".1331311........" + BITMAP ".11333311......." + BITMAP "1233331311......" + BITMAP "2113313311....1." + BITMAP "...1113311...131" + BITMAP "...133311....131" + BITMAP "..1333311...1311" + BITMAP ".1333311....1311" + BITMAP ".133311.11.13311" + BITMAP ".13331113311311." + BITMAP ".13333333331311." + BITMAP "..1333333333311." + BITMAP "...11111111111.." + + BITMAP "....11.11......." + BITMAP "...1331311......" + BITMAP "..13233211......" + BITMAP "..13233211......" + BITMAP "..1331311......." + BITMAP "...1333311......" + BITMAP ".1133331311....." + BITMAP "12133313311....." + BITMAP "12211113311..1.." + BITMAP ".111333311..131." + BITMAP "..13333111.1311." + BITMAP "..13331131.1311." + BITMAP "..133311311311.." + BITMAP "..133333333311.." + BITMAP "...13333313311.." + BITMAP "....111111111..." + + BITMAP ".......1131331.." + BITMAP ".......11233231." + BITMAP ".......11233231." + BITMAP "........1131331." + BITMAP ".......11333311." + BITMAP "......1131333321" + BITMAP ".1....1133133112" + BITMAP "131...1133111..." + BITMAP "131....113331..." + BITMAP "1131...1133331.." + BITMAP "1131....1133331." + BITMAP "11331.11.113331." + BITMAP ".11311331113331." + BITMAP ".11313333333331." + BITMAP ".1133333333331.." + BITMAP "..11111111111..." + + BITMAP ".......11.11...." + BITMAP "......1131331..." + BITMAP "......11233231.." + BITMAP "......11233231.." + BITMAP ".......1131331.." + BITMAP "......1133331..." + BITMAP ".....113133331.." + BITMAP ".....11331333121" + BITMAP "..1..11331111221" + BITMAP ".131..1133331..." + BITMAP ".1131.11133331.." + BITMAP ".1131133113331.." + BITMAP "..113133113331.." + BITMAP "..113333333331.." + BITMAP "..11331333331..." + BITMAP "...111111111...." + +start_song: PROCEDURE + tick_note = 8 + song_note = 47 + END + +play_song: PROCEDURE + tick_note = tick_note + 1. + IF tick_note = 16. THEN + tick_note = 0. + song_note = song_note + 1. + IF song_note = 48. THEN song_note = 0. + note = song_notes(song_note) + SOUND 10, #note_freq(note - 1) + END IF + SOUND 10, , volume_effect(tick_note) + 48 + END + +sound_off: PROCEDURE + SOUND 10,,16 + SOUND 11,,16 + END + +volume_effect: + DATA BYTE 11,12,13,12,12,11,11,10 + DATA BYTE 10,9,9,10,10,9,9,8 + +song_notes: + DATA BYTE 1,2,3,4,5,4,3,2 + DATA BYTE 1,2,3,4,5,4,3,2 + DATA BYTE 6,4,7,8,9,8,7,4 + DATA BYTE 6,4,7,8,9,8,7,4 + DATA BYTE 3,12,8,10,11,10,8,12 + DATA BYTE 6,4,7,8,9,8,7,4 + +#note_freq: + DATA $01AC + DATA $0153 + DATA $011D + DATA $00FE + DATA $00F0 + DATA $0140 + DATA $00D6 + DATA $00BE + DATA $00B4 + DATA $00AA + DATA $00A0 + DATA $00E2 From 892ae6743bf57136e88a7695dd95963b44ef3249 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 18:24:00 -0600 Subject: [PATCH 065/155] NES now works in real hardware --- cvbasic_nes_prologue.asm | 119 +++++++++++++++++-------------------- examples/viboritas.bas | 1 + examples/viboritas_nes.bas | 2 +- 3 files changed, 56 insertions(+), 66 deletions(-) diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index c818ae7..15c2aac 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -109,9 +109,7 @@ CONT2: EQU $4017 WRTVRM: PHA TXA - PHA LDX ppu_pointer - PLA STA PPUBUF+2,X PLA STA PPUBUF,X @@ -122,55 +120,43 @@ WRTVRM: INX INX STX ppu_pointer - BMI .1 + CPX #$40 + BCS .1 RTS .1: JMP wait CLS: + LDA #$80 +.1: + PHA LDX ppu_pointer LDA #$20 STA PPUBUF+3,X - LDA #$00 + LDA #$40 STA PPUBUF+2,X LDA #$00 STA PPUBUF,X - LDA #$a0 + PLA STA PPUBUF+1,X - LDA #$20 - STA PPUBUF+7,X - LDA #$00 - STA PPUBUF+6,X - LDA #$00 - STA PPUBUF+4,X - LDA #$a1 - STA PPUBUF+5,X - TXA + PHA CLC - ADC #8 - STA ppu_pointer + ROR PPUBUF+1,X + ROR PPUBUF,X + SEC + ROR PPUBUF+1,X + ROR PPUBUF,X + INX + INX + INX + INX + STX ppu_pointer JSR wait - LDX ppu_pointer - LDA #$20 - STA PPUBUF+3,X - LDA #$00 - STA PPUBUF+2,X - LDA #$00 - STA PPUBUF+0,X - LDA #$a2 - STA PPUBUF+1,X - LDA #$20 - STA PPUBUF+7,X - LDA #$00 - STA PPUBUF+6,X - LDA #$00 - STA PPUBUF+4,X - LDA #$a3 - STA PPUBUF+5,X - TXA + PLA CLC - ADC #8 - STA ppu_pointer + ADC #1 + CMP #$90 + BNE .1 RTS update_sprite: @@ -519,7 +505,7 @@ nmi_handler: BNE .5 ; No, jump. LDA flicker CLC - ADC #28 + ADC #32 STA flicker JMP .6 .5: @@ -530,22 +516,27 @@ nmi_handler: STA SPRRAM ; Use DMA for sprite loading ; Screen changes - LDX #$00 - CPX ppu_pointer ; Any change? + LDA ppu_pointer ; Any change? BEQ .1 ; No, jump. -.0: LDA PPUBUF+1,X + LDX #$00 +.0: LDY PPUBUF,X + INX + LDA PPUBUF,X + INX STA PPUADDR - BMI .2 ROL A + STY PPUADDR + BCS .2 BMI .7 - LDA PPUBUF,X - STA PPUADDR - LDA PPUBUF+3,X + LDA PPUBUF+1,X STA ppu_source - LDA PPUBUF+4,X - STA ppu_source+1 LDA PPUBUF+2,X + STA ppu_source+1 + LDA PPUBUF,X + INX + INX + INX STX ppu_temp TAX LDY #0 @@ -555,46 +546,37 @@ nmi_handler: INY DEX BNE .4 - LDA ppu_temp - CLC - ADC #5 - TAX + LDX ppu_temp CPX ppu_pointer BNE .0 - JMP .1 + JMP .11 ; Single byte .7: LDA PPUBUF,X - STA PPUADDR - LDA PPUBUF+2,X - STA PPUDATA - INX - INX INX + STA PPUDATA CPX ppu_pointer BNE .0 - JMP .1 + JMP .11 ; Filling data .2: + LDY PPUBUF,X + INX LDA PPUBUF,X - STA PPUADDR - LDY PPUBUF+2,X - LDA PPUBUF+3,X + INX .3: STA PPUDATA DEY BNE .3 - TXA - CLC - ADC #4 - TAX CPX ppu_pointer BNE .0 -.1: LDA #0 +.11: + LDA #0 STA ppu_pointer +.1: ; Final settings for PPU LDA #0 @@ -943,6 +925,7 @@ START: LDA #$00 STA $4010 + LDA #0 STA PPUCTRL STA PPUMASK @@ -969,9 +952,15 @@ START: BIT PPUSTATUS BPL $-3 + LDA #0 + STA PPUCTRL + STA PPUMASK ; About 27384 cycles passed at this time. BIT PPUSTATUS BPL $-3 + LDA #0 + STA PPUCTRL + STA PPUMASK ; About 57165 cycles passed at this time. ; Clear 2K of pattern memory diff --git a/examples/viboritas.bas b/examples/viboritas.bas index 0e0c1bf..4bd712d 100644 --- a/examples/viboritas.bas +++ b/examples/viboritas.bas @@ -21,6 +21,7 @@ restart_game: lives = 2 level = 1 restart_level: + WAIT PRINT AT 684,"Lives: ",lives PRINT AT 745,"nanochess 1990" diff --git a/examples/viboritas_nes.bas b/examples/viboritas_nes.bas index 52befb0..fb7b793 100644 --- a/examples/viboritas_nes.bas +++ b/examples/viboritas_nes.bas @@ -83,7 +83,7 @@ game_loop: FOR c = 1 to 10 WAIT -' SOUND 10, 200 - c * 10, 13 + 16 + SOUND 10, 200 - c * 10, 13 + 16 NEXT c level = level + 1 From ac46733d582fee813cb1ca0bd33bea172ce56d15 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 23 Aug 2025 18:41:50 -0600 Subject: [PATCH 066/155] Updated README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 24747f6..40075e1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CVBasic compiler v0.8.0 +# CVBasic compiler v0.9.0 *(c) Copyright 2024-2025 Óscar Toledo Gutiérrez* *https://nanochess.org/* @@ -20,7 +20,7 @@ Later it was extended to support the following platforms: * Hanimex/Soundic Pencil II. * NABU PC. * Sega Master System (supporting bank switching with Sega mapper) -* NES/Famicom (preliminary, currently only CHRROM/SPRITE support) +* NES/Famicom (preliminary, currently doesn't have music player, SCREEN and SCROLL) One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. @@ -204,7 +204,7 @@ The current official version is v0.8.0. All platforms have been tested in emulation. -* Colecovision and MSX have been tested in real hardware by myself. +* Colecovision, MSX, and NES have been tested in real hardware by myself. * Sega SG1000/SC3000 tested in real hardware by aotta. * Spectravideo SVI-318/328 tested in real hardware by Tony Cruise. * Creativision / Dick Smith's Wizzard tested in real hardware by Scouter3d. @@ -234,7 +234,7 @@ The TI-99/4A can only generate non-banked binaries up to 24 kb. When banking, th The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1 (<||| is the primary button and |||> is the secondary button), and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. -The NES support is highly experimental, currently only 32K ROM, CHRROM definition, SPRITE, and controller support are implemented (this is great if you want to make a silent game :P ) +The NES support is highly experimental, currently only 32K ROM. Three demos have been ported and are functional (happy_face, face_joystick, and Viboritas) Missing music player, SCREEN, SCROLL, and image converter. Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) From 6fcd20fddaad906973ebfe3815d76b109ddca087 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 24 Aug 2025 15:30:47 -0600 Subject: [PATCH 067/155] NES added SCROLL and SCREEN, also space_attack_nes.bas --- cvbasic.c | 50 ++- cvbasic_nes_prologue.asm | 107 ++++++- examples/space_attack_nes.bas | 561 ++++++++++++++++++++++++++++++++++ 3 files changed, 704 insertions(+), 14 deletions(-) create mode 100644 examples/space_attack_nes.bas diff --git a/cvbasic.c b/cvbasic.c index 4b08c63..5e1337d 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -4838,9 +4838,9 @@ void compile_statement(int check_for_else) if (lex == C_COMMA) { get_lex(); type = evaluate_expression(1, TYPE_8, 0); - if (machine != SMS) { - emit_error("The 2nd BORDER argument only available on Sega Master System"); - } else { + if (machine != SMS && machine != NES) { + emit_error("The 2nd BORDER argument only available on Sega Master System or NES/Famicom"); + } else if (machine == SMS) { cpuz80_1op("AND", "$07"); cpuz80_1op("OR", "$20"); cpuz80_noop("RRCA"); @@ -4851,34 +4851,51 @@ void compile_statement(int check_for_else) generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); generic_interrupt_enable(); + } else if (machine == NES) { + cpu6502_1op("ASL", "A"); + cpu6502_1op("AND", "#$06"); + cpu6502_noop("PHA"); + cpu6502_1op("LDA", "ppu_mask"); + cpu6502_1op("AND", "#$f9"); + cpu6502_1op("STA", "ppu_mask"); + cpu6502_noop("PLA"); + cpu6502_1op("ORA", "ppu_mask"); + cpu6502_1op("STA", "ppu_mask"); } } } else if (strcmp(name, "SCROLL") == 0) { /* Sega Master System */ int type; get_lex(); - /* !!! Implement NES/Famicom support */ - if (machine != SMS) - emit_error("SCROLL is only available on Sega Master System"); + if (machine != SMS && machine != NES) + emit_error("SCROLL is only available on Sega Master System or NES/Famicom"); if (lex != C_COMMA) { - type = evaluate_expression(1, TYPE_8, 0); if (machine == SMS) { + type = evaluate_expression(1, TYPE_8, 0); cpuz80_2op("LD", "B", "A"); cpuz80_2op("LD", "C", "8"); generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); generic_interrupt_enable(); + } else { + type = evaluate_expression(1, TYPE_16, 0); + cpu6502_1op("STA", "scroll_x"); + cpu6502_1op("STY", "scroll_x+1"); } } if (lex == C_COMMA) { get_lex(); - type = evaluate_expression(1, TYPE_8, 0); if (machine == SMS) { + type = evaluate_expression(1, TYPE_8, 0); cpuz80_2op("LD", "B", "A"); cpuz80_2op("LD", "C", "9"); generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); generic_interrupt_enable(); + } else { + type = evaluate_expression(1, TYPE_16, 0); + cpu6502_1op("STA", "scroll_y"); + cpu6502_1op("STY", "scroll_y+1"); } } } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System / NES */ @@ -5035,7 +5052,6 @@ void compile_statement(int check_for_else) } else if (strcmp(name, "SCREEN") == 0) { /* Copy screen */ struct label *array; - /* !!! Implement for NES */ get_lex(); if (lex != C_NAME) { emit_error("bad syntax for SCREEN"); @@ -5066,6 +5082,7 @@ void compile_statement(int check_for_else) struct node *final; struct node *addr; int type; + int c; get_lex(); addr = node_create(N_ADDR, 0, NULL, NULL); @@ -5098,7 +5115,13 @@ void compile_statement(int check_for_else) final = node_create((type & TYPE_SIGNED) ? N_EXTEND8S : N_EXTEND8, 0, final, NULL); if (machine == SMS) final = node_create(N_MUL16, 0, final, node_create(N_NUM16, 2, NULL, NULL)); - final = node_create(N_PLUS16, 0, node_create(N_NUM16, (machine == SMS ? 0x3800 : 0x1800), NULL, NULL), final); + if (machine == SMS) + c = 0x3800; + else if (machine == NES) + c = 0x2000; + else + c = 0x1800; + final = node_create(N_PLUS16, 0, node_create(N_NUM16, c, NULL, NULL), final); node_label(final); node_generate(final, 0); node_delete(final); @@ -5198,18 +5221,21 @@ void compile_statement(int check_for_else) generic_call("CPYBLK"); } else { if (target == CPU_6502) { + if (machine == NES) { + emit_error("full screen SCREEN not allowed with NES/Famicom"); + } sprintf(temp, "#%s", assigned); cpu6502_1op("LDA", temp); strcat(temp, ">>8"); cpu6502_1op("LDY", temp); cpu6502_1op("STA", "temp"); cpu6502_1op("STY", "temp+1"); - cpu6502_1op("LDA", "#0"); + cpu6502_1op("LDA", (machine == NES) ? "#$c0" : "#0"); cpu6502_1op("LDY", "#3"); cpu6502_1op("STA", "temp2"); cpu6502_1op("STY", "temp2+1"); cpu6502_1op("LDA", "#0"); - cpu6502_1op("LDY", "#24"); + cpu6502_1op("LDY", (machine == NES) ? "#32" : "#24"); cpu6502_1op("STA", "pointer"); cpu6502_1op("STY", "pointer+1"); generic_interrupt_disable(); diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 15c2aac..3149fcb 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -7,6 +7,7 @@ ; Creation date: May/13/2025. ; Revision date: Jul/20/2025. Added code to load sprites and read controllers. ; Revision date: Aug/23/2025. Support for writing VRAM and PRINT. + ; Revision date: Aug/24/2025. Support for scrolling, SCREEN, and DISABLE/ENABLE. ; CPU 6502 @@ -32,6 +33,11 @@ cursor: equ $0c ppu_pointer: equ $0e ppu_temp: equ $0f ; Used in NMI to save X +scroll_x: equ $10 +scroll_y: equ $12 +ppu_ctrl: equ $14 +ppu_mask: equ $15 + joy1_data: equ $20 joy2_data: equ $21 key1_data: equ $22 @@ -126,7 +132,86 @@ WRTVRM: .1: JMP wait -CLS: +LDIRVM: + LDX ppu_pointer + LDA pointer + STA PPUBUF,X + LDA pointer+1 + STA PPUBUF+1,X + LDA temp2 + STA PPUBUF+2,X + LDA temp,X + STA PPUBUF+3,X + LDA temp+1,X + STA PPUBUF+4,X + TXA + CLC + ADC #5 + STA ppu_pointer + RTS + +ENASCR: + LDA ppu_mask + ORA #$18 + STA ppu_mask + RTS + +DISSCR: + LDA ppu_mask + AND #$E7 + STA ppu_mask + RTS + +CPYBLK: +.1: + LDA temp2 + PHA + LDA temp2+1 + PHA + TXA + PHA + TYA + PHA + LDA temp + PHA + LDA temp+1 + PHA + LDA #0 + STA temp2+1 + JSR LDIRVM + PLA + STA temp+1 + PLA + STA temp + PLA + STA temp2+1 + PLA + STA temp2 + LDA temp + CLC + ADC temp2 + STA temp + LDA temp+1 + ADC temp2+1 + STA temp+1 + LDX temp2 + LDY temp2+1 + PLA + STA temp2+1 + PLA + STA temp2 + LDA pointer + CLC + ADC #$20 ; !!! Variation for scrolling + STA pointer + LDA pointer+1 + ADC #$00 + STA pointer+1 + DEC temp2+1 + BNE .1 + RTS + +cls: LDA #$80 .1: PHA @@ -582,8 +667,24 @@ nmi_handler: LDA #0 STA PPUADDR STA PPUADDR - STA PPUSCROLL ; !!! For scrolling + LDA scroll_x + STA PPUSCROLL + LDA scroll_y STA PPUSCROLL + LDA ppu_ctrl + LSR A + LSR A + STA ppu_temp + LDA scroll_y+1 + ROR A + ROL ppu_temp + LDA scroll_x+1 + ROR A + ROL ppu_temp + LDA ppu_temp + STA PPUCTRL + LDA ppu_mask + STA PPUMASK ; Read controllers LDA #$01 @@ -1010,7 +1111,9 @@ START: BPL $-3 LDA #$1e ; Color normal, Sprites visible, Background visible, No clipping, Color. STA PPUMASK + STA ppu_mask LDA #$A8 ; Enable NMI, 8x16 sprites, BG=$0000, SPR=$1000, NAME=$2000 + STA ppu_ctrl STA PPUCTRL JSR music_init diff --git a/examples/space_attack_nes.bas b/examples/space_attack_nes.bas new file mode 100644 index 0000000..6222aac --- /dev/null +++ b/examples/space_attack_nes.bas @@ -0,0 +1,561 @@ + ' + ' Space Attack (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Feb/29/2024. + ' Revision date: Nov/13/2024. Added pixel stars background and double-speed enemies. + ' Revision date: Aug/24/2025. Adapted for NES/Famicom. + ' + + DIM enemy_x(8) + DIM enemy_y(8) + DIM enemy_s(8) + +restart_game: + CLS + PALETTE LOAD game_palette + + #score = 0 + + player_x = 120 + player_y = 192 + bullet_y = 0 + FOR c = 0 TO 7 + enemy_s(c) = 0 + NEXT c + + SCREEN DISABLE + + ' Draw the stars background + ' + ' We make a vertical strip using 8 characters (numbers 16 to 23) + ' and we repeat it continuously (24 rows / 8 characters = 3 repetitions) + ' + FOR d = 0 TO 31 ' For each column + FOR #c = 0 TO 928 STEP 32 + e = RANDOM(8) + 16 + VPOKE $2000 + #c + d, e ' Put strip character. + VPOKE $2800 + #c + d, e ' Put strip character. + NEXT #c + NEXT d + + SCREEN ENABLE + + GOSUB update_score + +game_loop: + WAIT + + ' + ' Displace stars pixel by pixel + ' + scroll_y = scroll_y - 1 + IF scroll_y = $ff THEN scroll_y = $ef + SCROLL 0, scroll_y + + ' Background "music" (two tones alternating each 16 video frames) + #c = 960 + IF FRAME AND 32 THEN #c = 1023 + d = (FRAME AND 31) / 2 + SOUND 10, #c, 15 - d + 16 + + ' Setup player sprite + SPRITE 0,player_y-1,player_x,0+1,0 + SPRITE 1,player_y-1,player_x+8,2+1,0 + + ' Setup bullet sprite + IF bullet_y = 0 THEN ' Active? + SPRITE 2,$f0,0,0,0 ' No, remove sprites. + SPRITE 3,$f0,0,0,0 + SOUND 11,,16 ' Disable sound. + ELSE + SPRITE 2,bullet_y-1,bullet_x,8+1,2 ' Setup sprites. + SPRITE 3,bullet_y-1,bullet_x+8,10+1,2 ' + bullet_y = bullet_y - 4 ' Displace bullet. + SOUND 11,bullet_y+16,11+16 ' Make sound. + END IF + + ' + ' Display and move the enemies. + ' + FOR c = 0 TO 7 + IF enemy_s(c) = 0 THEN ' No enemy + SPRITE 4 + c * 2, $f0, 0, 0, 0 + SPRITE 5 + c * 2, $f0, 0, 0, 0 + ' Create one + enemy_x(c) = RANDOM(232) + 4 + enemy_y(c) = $f0 + RANDOM(16) + enemy_s(c) = RANDOM(2) + 1 + ELSEIF enemy_s(c) < 3 THEN ' Enemy moving. + SPRITE 4 + c * 2, enemy_y(c) - 1, enemy_x(c), 4+1, 1 + SPRITE 5 + c * 2, enemy_y(c) - 1, enemy_x(c) + 8, 6+1, 1 + + ' Slowly drift towards the player. + IF (FRAME AND 3) = 0 THEN + IF player_x < enemy_x(c) THEN + enemy_x(c) = enemy_x(c) - 1 + ELSE + enemy_x(c) = enemy_x(c) + 1 + END IF + END IF + ' Move down. + IF enemy_s(c) = 1 THEN + enemy_y(c) = enemy_y(c) + 2 + ELSE + enemy_y(c) = enemy_y(c) + 3 + END IF + IF enemy_y(c) >= $e8 AND enemy_y(c) <= $ef THEN ' Reached bottom. + enemy_x(c) = RANDOM(168) + 4 + enemy_y(c) = $f2 ' Reset enemy. + enemy_s(c) = RANDOM(2) + 1 + END IF + + ' + ' Check if bullet has been launched. + ' + IF bullet_y <> 0 THEN ' Is bullet launched? + IF ABS(bullet_x + 1 - enemy_x(c)) < 8 THEN + IF ABS(bullet_y + 1 - enemy_y(c)) < 8 THEN + enemy_s(c) = 3 ' Enemy explodes + #score = #score + 1 + GOSUB update_score + bullet_y = 0 + SOUND 14,$E7,13+16 ' Start enemy explosion sound + END IF + END IF + END IF + + ' + ' Check if player is hit by enemy. + ' + IF ABS(player_y + 1 - enemy_y(c)) < 8 THEN + IF ABS(player_x + 1 - enemy_x(c)) < 8 THEN + GOTO player_dies + END IF + END IF + ELSE + ' Enemy explosion. + IF FRAME AND 4 THEN + SPRITE 4 + c * 2, $f0, 0, 0, 0 + SPRITE 5 + c * 2, $f0, 0, 0, 0 + ELSE + SPRITE 4 + c * 2, enemy_y(c) - 1, enemy_x(c), 12+1, 3 + SPRITE 5 + c * 2, enemy_y(c) - 1, enemy_x(c) + 8, 14+1, 3 + END IF + + ' Displace explosion slowly. + IF FRAME AND 1 THEN + IF enemy_y(c) < $c0 THEN enemy_y(c) = enemy_y(c) + 1 + END IF + + ' Explosion sound. + SOUND 14,enemy_s(c) + enemy_s(c) = enemy_s(c) + 1 + IF enemy_s(c) = 80 THEN ' Time reached. + SOUND 14,,0+16 + enemy_x(c) = RANDOM(232) + 4 + enemy_y(c) = $f2 + enemy_s(c) = 1 ' Bring back enemy. + END IF + END IF + NEXT c + + ' + ' Movement of the player. + ' + IF cont1.left THEN IF player_x > 0 THEN player_x = player_x - 2 + IF cont1.right THEN IF player_x < 240 THEN player_x = player_x + 2 + IF cont1.button THEN ' Fire! + IF bullet_y = 0 THEN ' Only if no bullet active. + bullet_y = player_y - 8 + bullet_x = player_x + END IF + END IF + GOTO game_loop + + ' + ' Player dies. + ' +player_dies: + ' + ' Explosion effect and sound. + ' + SOUND 10,,0+16 + SOUND 11,,0+16 + FOR c = 0 TO 120 + WAIT + SOUND 14,$E4 + (c AND 3),13+16 + e = player_y - 1 + RANDOM(5) - 2 + d = player_x + RANDOM(5) - 2 + SPRITE 0, e, d, 12+1, 3 + SPRITE 1, e, d + 8, 14+1, 3 + NEXT c + SOUND 14,,0+16 + + ' + ' Remove enemies. + ' + FOR c = 2 TO 19 + SPRITE c, $f0, 0, 0, 0 + NEXT c + + CLS + SCROLL 0,0 + WAIT + + PRINT AT 250,"GAME" + PRINT AT 282,"OVER" + + ' + ' Big delay. + ' + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + + GOTO restart_game + + ' + ' Update the score on the screen. + ' +update_score: PROCEDURE + SPRITE 32, 16, $c0, #score / 10000 % 10 * 2 + 128, 0 + SPRITE 33, 16, $c8, #score / 1000 % 10 * 2 + 128, 0 + SPRITE 34, 16, $d0, #score / 100 % 10 * 2 + 128, 0 + SPRITE 35, 16, $d8, #score / 10 % 10 * 2 + 128, 0 + SPRITE 36, 16, $e0, #score % 10 * 2 + 128, 0 + SPRITE 37, 16, $e8, 128, 0 + END + +game_palette: + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$30,$30,$30 + DATA BYTE $0F,$16,$10,$30 + DATA BYTE $0F,$12,$16,$24 + DATA BYTE $0F,$12,$10,$30 + DATA BYTE $0F,$16,$27,$30 + + CHRROM 0 + + CHRROM PATTERN 16 + ' + ' Pixel scrolling stars + ' + BITMAP ".1......" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP ".....1.." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "...1...." + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP ".1......" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "......1." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "......1." + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "....1..." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP ".1......" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + CHRROM PATTERN 128 + + BITMAP "3333333." + BITMAP "3.....3." + BITMAP "3.....3." + BITMAP "3....33." + BITMAP "3....33." + BITMAP "3....33." + BITMAP "3333333." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "....3..." + BITMAP "....3..." + BITMAP "....3..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "3333333." + BITMAP "3.....3." + BITMAP "......3." + BITMAP "3333333." + BITMAP "33......" + BITMAP "33......" + BITMAP "3333333." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "3333333." + BITMAP "3.....3." + BITMAP "......3." + BITMAP ".333333." + BITMAP ".....33." + BITMAP "3....33." + BITMAP "3333333." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "3......." + BITMAP "3......." + BITMAP "3.....3." + BITMAP "3.....3." + BITMAP "3333333." + BITMAP ".....33." + BITMAP ".....33." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "3333333." + BITMAP "3.....3." + BITMAP "3......." + BITMAP "3333333." + BITMAP ".....33." + BITMAP "3....33." + BITMAP "3333333." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "33333..." + BITMAP "3...3..." + BITMAP "3......." + BITMAP "3333333." + BITMAP "3....33." + BITMAP "3....33." + BITMAP "3333333." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "3333333." + BITMAP "......3." + BITMAP "......3." + BITMAP ".....33." + BITMAP ".....33." + BITMAP ".....33." + BITMAP ".....33." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".33333.." + BITMAP ".3...3.." + BITMAP ".3...3.." + BITMAP "3333333." + BITMAP "3.....3." + BITMAP "3.....3." + BITMAP "3333333." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP "3333333." + BITMAP "3.....3." + BITMAP "3.....3." + BITMAP "3333333." + BITMAP ".....33." + BITMAP ".....33." + BITMAP ".....33." + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + CHRROM PATTERN 256 + + BITMAP ".......33......." + BITMAP ".......33......." + BITMAP "......3333......" + BITMAP "......3333......" + BITMAP "......3333......" + BITMAP ".....333333....." + BITMAP ".....333333....." + BITMAP ".....332233....." + BITMAP ".....322223....." + BITMAP "..332333333233.." + BITMAP ".33323333332333." + BITMAP ".33333222233333." + BITMAP "3322333332332233" + BITMAP "3332333333333233" + BITMAP "3333.333333.3333" + BITMAP ".11..11..11..11." + + BITMAP "....33333333...." + BITMAP "...3........3..." + BITMAP "..3.33....33.3.." + BITMAP ".3...333333...3." + BITMAP ".3...323323...3." + BITMAP ".3...333333...3." + BITMAP ".3....3333 ...3." + BITMAP ".3..22.33.22..3." + BITMAP ".3222.2222.2223." + BITMAP "311..211112..113" + BITMAP "..333333333333.." + BITMAP "3331111331111333" + BITMAP "3133331331333313" + BITMAP "3113313333133113" + BITMAP "3331133..3311333" + BITMAP "..3333....3333.." + + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP ".......31......." + BITMAP "......3221......" + BITMAP "......3221......" + BITMAP "......3221......" + BITMAP "......3221......" + BITMAP "....33322221...." + BITMAP "...2222222221..." + BITMAP "......2111......" + BITMAP ".....21...21...." + BITMAP "................" + BITMAP "................" + BITMAP "................" + + BITMAP "................" + BITMAP "................" + BITMAP ".......1........" + BITMAP ".......12......." + BITMAP "1......112......" + BITMAP "111.....111...11" + BITMAP "11112..1121..121" + BITMAP "...11211221112.." + BITMAP ".....11222221..." + BITMAP "......122221...." + BITMAP ".....11122211..." + BITMAP "....111.112211.." + BITMAP "...121.....1111." + BITMAP "...12........111" + BITMAP "..11............" + BITMAP "................" From f7069750fec31edf32cb48066e9f52d0ef46bfe5 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 24 Aug 2025 19:30:05 -0600 Subject: [PATCH 068/155] NES now with music player --- cvbasic_nes_prologue.asm | 461 ++++++++++++++++++++++++++++++++++++++- examples/music.bas | 2 +- utility/notes.c | 50 ++++- 3 files changed, 492 insertions(+), 21 deletions(-) diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 3149fcb..3428487 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -8,6 +8,7 @@ ; Revision date: Jul/20/2025. Added code to load sprites and read controllers. ; Revision date: Aug/23/2025. Support for writing VRAM and PRINT. ; Revision date: Aug/24/2025. Support for scrolling, SCREEN, and DISABLE/ENABLE. + ; Added music player. ; CPU 6502 @@ -76,7 +77,7 @@ audio_vol2: EQU $49 audio_vol3: EQU $4a audio_vol4hw: EQU $4b audio_noise: EQU $4c -audio_control: EQU $4d +music_tick: EQU $4d music_mode: EQU $4e ENDIF @@ -731,6 +732,16 @@ nmi_handler: INC lfsr INC lfsr if CVBASIC_MUSIC_PLAYER + LDA ntsc + BEQ .12 + LDX music_tick + INX + CPX #6 + BNE .14 + LDX #0 +.14: STX music_tick + BEQ .9 +.12: LDA music_mode BEQ .9 JSR music_generate @@ -983,32 +994,457 @@ print_char: PLA RTS +mode_0: + JSR cls +clear_sprites: + LDA #$F0 + LDX #0 +.1: + STA $0200,X + INX + INX + INX + INX + BNE .1 + RTS + music_init: + LDA #$40 + STA $4017 + LDA #$10 + STA $4000 ; Channel 1 silent + STA $4004 ; Channel 2 silent + STA $400C ; Channel 4 silent + LDA #$0b + STA $4015 ; Enable channel 1, 2 and 4. + LDA #$00 + STA $4010 + if CVBASIC_MUSIC_PLAYER + else RTS + endif + if CVBASIC_MUSIC_PLAYER + LDA #music_silence + LDY #music_silence>>8 + ; + ; Play music. + ; YA = Pointer to music. + ; music_play: + SEI + STA music_pointer + STY music_pointer+1 + LDY #0 + STY music_note_counter + LDA (music_pointer),Y + STA music_timing + INY + STY music_playing + INC music_pointer + BNE $+4 + INC music_pointer+1 + LDA music_pointer + LDY music_pointer+1 + STA music_start + STY music_start+1 + CLI RTS + ; + ; Generates music + ; music_generate: + LDA #$10 + STA audio_vol1 + STA audio_vol2 + STA audio_vol3 + STA audio_vol4hw + LDA music_note_counter + BEQ .1 + JMP .2 +.1: + LDY #0 + LDA (music_pointer),Y + CMP #$fe ; End of music? + BNE .3 ; No, jump. + LDA #0 ; Keep at same place. + STA music_playing RTS -music_hardware: - RTS +.3: CMP #$fd ; Repeat music? + BNE .4 + LDA music_start + LDY music_start+1 + STA music_pointer + STY music_pointer+1 + JMP .1 + +.4: LDA music_timing + AND #$3f ; Restart note time. + STA music_note_counter + + LDA (music_pointer),Y + CMP #$3F ; Sustain? + BEQ .5 + AND #$C0 + STA music_instrument_1 + LDA (music_pointer),Y + AND #$3F + ASL A + STA music_note_1 + LDA #0 + STA music_counter_1 +.5: + INY + LDA (music_pointer),Y + CMP #$3F ; Sustain? + BEQ .6 + AND #$C0 + STA music_instrument_2 + LDA (music_pointer),Y + AND #$3F + ASL A + STA music_note_2 + LDA #0 + STA music_counter_2 +.6: + INY + LDA (music_pointer),Y + CMP #$3F ; Sustain? + BEQ .7 + AND #$C0 + STA music_instrument_3 + LDA (music_pointer),Y + AND #$3F + ASL A + STA music_note_3 + LDA #0 + STA music_counter_3 +.7: + INY + LDA (music_pointer),Y + STA music_drum + LDA #0 + STA music_counter_4 + LDA music_pointer + CLC + ADC #4 + STA music_pointer + LDA music_pointer+1 + ADC #0 + STA music_pointer+1 +.2: + LDY music_note_1 + BEQ .8 + LDA music_instrument_1 + LDX music_counter_1 + JSR music_note2freq + STA audio_freq1 + STY audio_freq1+1 + STX audio_vol1 +.8: + LDY music_note_2 + BEQ .9 + LDA music_instrument_2 + LDX music_counter_2 + JSR music_note2freq + STA audio_freq2 + STY audio_freq2+1 + STX audio_vol2 +.9: + LDY music_note_3 + BEQ .10 + LDA music_instrument_3 + LDX music_counter_3 + JSR music_note2freq + STA audio_freq3 + STY audio_freq3+1 + STX audio_vol3 +.10: + LDA music_drum + BEQ .11 + CMP #1 ; 1 - Long drum. + BNE .12 + LDA music_counter_4 + CMP #3 + BCS .11 +.15: + LDA #$08 + STA audio_noise + LDA #$9c + STA audio_vol4hw + JMP .11 -mode_0: - JSR cls -clear_sprites: - LDA #$F0 - LDX #0 -.1: - STA $0200,X - INX +.12: CMP #2 ; 2 - Short drum. + BNE .14 + LDA music_counter_4 + CMP #0 + BNE .11 + LDA #$04 + STA audio_noise + LDA #$9c + STA audio_vol4hw + JMP .11 + +.14: ;CMP #3 ; 3 - Roll. + ;BNE + LDA music_counter_4 + CMP #2 + BCC .15 + ASL A + SEC + SBC music_timing + BCC .11 + CMP #4 + BCC .15 +.11: + LDX music_counter_1 INX + CPX #$18 + BNE $+4 + LDX #$10 + STX music_counter_1 + + LDX music_counter_2 INX + CPX #$18 + BNE $+4 + LDX #$10 + STX music_counter_2 + + LDX music_counter_3 INX + CPX #$18 + BNE $+4 + LDX #$10 + STX music_counter_3 + + INC music_counter_4 + DEC music_note_counter + RTS + +music_flute: + LDA music_notes_table,Y + CLC + ADC .2,X + PHA + LDA music_notes_table+1,Y + ADC #0 + TAY + LDA .1,X + TAX + PLA + RTS + +.1: + db $9a,$9c,$9d,$9d,$9c,$9c,$9c,$9c + db $9b,$9b,$9b,$9b,$9a,$9a,$9a,$9a + db $9b,$9b,$9b,$9b,$9a,$9a,$9a,$9a + +.2: + db 0,0,0,0,0,1,1,1 + db 0,1,1,1,0,1,1,1 + db 0,1,1,1,0,1,1,1 + + ; + ; Converts note to frequency. + ; Input: + ; A = Instrument. + ; Y = Note (1-62) + ; X = Instrument counter. + ; Output: + ; YA = Frequency. + ; X = Volume. + ; +music_note2freq: + CMP #$40 + BCC music_piano + BEQ music_clarinet + CMP #$80 + BEQ music_flute + ; + ; Bass instrument + ; +music_bass: + LDA music_notes_table,Y + ASL A + PHA + LDA music_notes_table+1,Y + ROL A + TAY + LDA .1,X + TAX + PLA + RTS + +.1: + db $9d,$9d,$9c,$9c,$9b,$9b,$9a,$9a + db $99,$99,$98,$98,$97,$97,$96,$96 + db $95,$95,$94,$94,$93,$93,$92,$92 + +music_piano: + LDA music_notes_table,Y + PHA + LDA music_notes_table+1,Y + TAY + LDA .1,X + TAX + PLA + RTS + +.1: + db $dc,$db,$db,$da,$da,$d9,$d9,$d8 + db $d8,$d7,$d7,$d6,$d6,$d5,$d5,$d4 + db $d4,$d4,$d5,$d5,$d4,$d4,$d3,$d3 + +music_clarinet: + LDA music_notes_table,Y + CLC + ADC .2,X + PHA + LDA .2,X + BMI .3 + LDA #$00 + DB $2C +.3: LDA #$ff + ADC music_notes_table+1,Y + LSR A + TAY + LDA .1,X + TAX + PLA + ROR A + RTS + +.1: + db $1d,$1e,$1e,$1d,$1d,$1c,$1c,$1c + db $1b,$1b,$1b,$1b,$1c,$1c,$1c,$1c + db $1b,$1b,$1b,$1b,$1c,$1c,$1c,$1c + +.2: + db 0,0,0,0,-1,-1,-1,0 + db 1,1,1,0,-1,-1,-1,0 + db 1,1,1,0,-1,-1,-1,0 + + ; + ; Musical notes table. + ; +music_notes_table: + ; Silence - 0 + dw 0 + ; Values for 1.79 mhz. / 16, offset 0 + ; 2nd octave - Index 1 + dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 + ; 3rd octave - Index 13 + dw 855,807,762,719,679,641,605,571,539,508,480,453 + ; 4th octave - Index 25 + dw 428,404,381,360,339,320,302,285,269,254,240,226 + ; 5th octave - Index 37 + dw 214,202,190,180,170,160,151,143,135,127,120,113 + ; 6th octave - Index 49 + dw 107,101,95,90,85,80,76,71,67,64,60,57 + ; 7th octave - Index 61 + dw 53,50,48 + + ; + ; When the frequency upper byte is rewritten, the + ; output phase is reset, and it creates glitches. + ; So it doesn't rewrite frequency unless the note + ; changes. + ; +music_hardware: + LDA music_mode + CMP #4 ; PLAY SIMPLE? + BCC .9 ; Yes, jump. + LDA audio_vol2 + AND #$0F + BNE .9 + LDA audio_vol3 + AND #$0F + BEQ .9 + LDA audio_vol3 + STA audio_vol2 + LDA #$10 + STA audio_vol3 + LDA audio_freq3 + LDY audio_freq3+1 + STA audio_freq2 + STY audio_freq2+1 +.9: + LDA audio_freq1 + STA $4002 + LDA music_counter_1 + CMP #1 + BNE .3 + LDA audio_freq1+1 + ORA #$08 ; Keeps tone enabled + STA $4003 +.3: LDA audio_vol1 + STA $4000 + LDA #0 + STA $4001 + + LDA audio_freq2 + STA $4006 + LDA music_counter_2 + CMP #1 + BNE .4 + LDA audio_freq2+1 + ORA #$08 ; Keeps tone enabled + STA $4007 +.4: LDA audio_vol2 + STA $4004 + LDA #0 + STA $4005 + + LDA music_mode + CMP #4 ; PLAY SIMPLE? + BCC .6 ; Yes, jump. + + LSR audio_freq3+1 + ROR audio_freq3 + LDA audio_freq3 + STA $400A + LDA music_counter_3 + CMP #1 + BNE .5 + LDA audio_freq3+1 + ORA #$08 ; Keeps tone enabled + STA $400B +.5: + LDA #$20 + STA $4008 + LDA audio_vol3 + AND #$0F BNE .1 + LDA #$0B + JMP .2 + +.1: LDA #$0F +.2: STA $4015 + +.6: LDA music_mode + LSR A ; NO DRUMS? + BCC .8 + LDA music_counter_4 + CMP #1 + BNE .7 + LDA audio_noise + STA $400E + ORA #$08 ; Keeps tone enabled + STA $400F +.7: LDA audio_vol4hw + STA $400C +.8: RTS +music_silence: + db 8 + db 0,0,0,0 + db -2 + endif + START: SEI CLD @@ -1116,6 +1552,9 @@ START: STA ppu_ctrl STA PPUCTRL + LDA #1 ; !!! Detect NTSC + STA ntsc + JSR music_init JSR mode_0 diff --git a/examples/music.bas b/examples/music.bas index 7107917..642223f 100644 --- a/examples/music.bas +++ b/examples/music.bas @@ -32,7 +32,7 @@ play_1: repeat: WAIT IF CONT1.BUTTON2 THEN V=15 - SOUND 2,300,V +REM SOUND 2,300,V IF V>0 THEN V=V-1 IF MUSIC.PLAYING THEN GOTO repeat GOTO wait_key diff --git a/utility/notes.c b/utility/notes.c index 74dd68a..5545b45 100644 --- a/utility/notes.c +++ b/utility/notes.c @@ -50,38 +50,69 @@ int main(int argc, char *argv[]) int d; int e; int base_freq; + double divisor; + int offset; int max; int value; if (argc == 1) { fprintf(stderr, "\n"); fprintf(stderr, "Usage:\n"); - fprintf(stderr, " notes [-sn] 3579545 >source.asm\n"); + fprintf(stderr, " notes 3579545 32 0 >source.asm\n"); + fprintf(stderr, " notes -sn 3579545 32 0 >source.asm\n"); + fprintf(stderr, " notes -n 1789773 16 -1 >source.asm\n"); fprintf(stderr, "\n"); fprintf(stderr, "It will generate an assembler note table for the given\n"); fprintf(stderr, "frequency. This is useful in my CVBasic compiler\n"); fprintf(stderr, "because I need 3 tables: 3.58 mhz, 4.00 mhz, and 2.00 mhz.\n"); fprintf(stderr, "Of course, doing these tables manually is a chore.\n"); fprintf(stderr, "\n"); + fprintf(stderr, "The second number is the frequency divisor (32 for\n"); + fprintf(stderr, "AY-3-8910, SN76489, and the triangle in NES/Famicom, or\n"); + fprintf(stderr, "16 for the rectangle channels in NES/Famicom)"); + fprintf(stderr, "\n"); + fprintf(stderr, "The third number is the offset to the final value\n"); + fprintf(stderr, "(0 for AY-3-8910 and SN76489, or -1 for NES/Famicom)\n"); + fprintf(stderr, "\n"); fprintf(stderr, "The values are valid for AY-3-8910 or SN76489 chips.\n"); fprintf(stderr, "\n"); - fprintf(stderr, "It will warn you if the final value exceeds 4095 or\n"); - fprintf(stderr, "1023 (if the -sn option is used).\n"); + fprintf(stderr, "It will warn you if the final value exceeds 4095, or\n"); + fprintf(stderr, "1023 (-sn option), or 2047 (-n option)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Base musical frequencies are output in stderr, and\n"); fprintf(stderr, "assembler code in stdout.\n"); fprintf(stderr, "\n"); exit(1); } - fprintf(stderr, "Notes v0.1.0 Aug/07/2024 by Oscar Toledo G. https://nanochess.org\n"); + fprintf(stderr, "Notes v0.2.0 Aug/24/2025 by Oscar Toledo G. https://nanochess.org\n"); - if (argv[1][0] == '-' && tolower(argv[1][1] == 's') && tolower(argv[1][2]) == 'n') { - base_freq = atoi(argv[2]); + c = 1; + if (argv[c][0] == '-' && tolower(argv[c][1]) == 's' && tolower(argv[c][2]) == 'n') { + c++; max = 1023; + } else if (argv[c][0] == '-' && tolower(argv[c][1]) == 'n') { + c++; + max = 2047; } else { - base_freq = atoi(argv[1]); max = 4095; } + if (c >= argc) { + fprintf(stderr, "Missing base frequency.\n"); + exit(1); + } + base_freq = atoi(argv[c]); + c++; + if (c >= argc) { + fprintf(stderr, "Missing divisor.\n"); + exit(1); + } + divisor = atoi(argv[c]); + c++; + if (c >= argc) { + fprintf(stderr, "Missing offset.\n"); + exit(1); + } + offset = atoi(argv[c]); fprintf(stdout, "\t;\n"); fprintf(stdout, "\t; Musical notes table.\n"); fprintf(stdout, "\t;\n"); @@ -91,7 +122,8 @@ int main(int argc, char *argv[]) for (c = 2; c < 8; c++) { switch (c) { case 2: - fprintf(stdout, "\t; Values for %4.2f mhz.\n", base_freq / 1e6); + fprintf(stdout, "\t; Values for %4.2f mhz. / %d, offset %d\n", + base_freq / 1e6, (int) divisor, (int) offset); fprintf(stdout, "\t; 2nd octave - Index 1\n"); break; case 3: @@ -118,7 +150,7 @@ int main(int argc, char *argv[]) fprintf(stdout, "\tdw "); for (d = 0; d < e; d++) { fprintf(stderr, "%4.1f%s", frequencies[d], (d == e - 1) ? "\n" : ","); - value = (int) (base_freq / 32.0 / frequencies[d] + 0.5); + value = (int) (base_freq / divisor / frequencies[d] + 0.5) + offset; if (value > max) fprintf(stderr, "Warning: Exceeded range for octave %d, note %d\n", c, d); fprintf(stdout, "%d%c", value, (d == e - 1) ? '\n' : ','); From 195428d8a3974f79c29a322aef27a2e668ee3b96 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 24 Aug 2025 19:32:44 -0600 Subject: [PATCH 069/155] NES updated README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40075e1..33a852d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Later it was extended to support the following platforms: * Hanimex/Soundic Pencil II. * NABU PC. * Sega Master System (supporting bank switching with Sega mapper) -* NES/Famicom (preliminary, currently doesn't have music player, SCREEN and SCROLL) +* NES/Famicom (preliminary) One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. @@ -234,7 +234,7 @@ The TI-99/4A can only generate non-banked binaries up to 24 kb. When banking, th The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1 (<||| is the primary button and |||> is the secondary button), and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. -The NES support is highly experimental, currently only 32K ROM. Three demos have been ported and are functional (happy_face, face_joystick, and Viboritas) Missing music player, SCREEN, SCROLL, and image converter. +The NES support is highly experimental, currently only 32K ROM. Five demos have been ported and are functional: face_joystick, happy_face, music, Space Attack, and Viboritas. Missing image converter. Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) From e1b77e8a9a9f9293f022b636c518152052ca9880 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 24 Aug 2025 19:44:40 -0600 Subject: [PATCH 070/155] NES added PAL/NTSC detection --- cvbasic_nes_prologue.asm | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 3428487..4cf29bf 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -1170,7 +1170,7 @@ music_generate: CMP #3 BCS .11 .15: - LDA #$08 + LDA #$06 STA audio_noise LDA #$9c STA audio_vol4hw @@ -1181,7 +1181,7 @@ music_generate: LDA music_counter_4 CMP #0 BNE .11 - LDA #$04 + LDA #$02 STA audio_noise LDA #$9c STA audio_vol4hw @@ -1487,17 +1487,40 @@ START: ; Around 29000 cycles must happen before these can be written. ; + ; lidnariq code for detecting NTSC/PAL/Dendy system + ; From: https://forums.nesdev.org/viewtopic.php?p=163258#p163258 + LDX #0 + LDY #0 BIT PPUSTATUS BPL $-3 - LDA #0 - STA PPUCTRL - STA PPUMASK +.5: + INX + BNE .6 + INY +.6: ; About 27384 cycles passed at this time. BIT PPUSTATUS - BPL $-3 + BPL .5 LDA #0 STA PPUCTRL STA PPUMASK + + TYA + CMP #16 + BCC .7 + LSR A +.7: CLC + ADC #$F7 + CMP #3 + BCC .8 + LDA #3 ; Bad + ; 0=NTSC, 1=Pal, 2=Dendy, 3=Bad +.8: + CMP #0 ; Pass NTSC unchanged + BEQ .9 + LDA #1 ; All other PAL +.9: EOR #1 + STA ntsc ; About 57165 cycles passed at this time. ; Clear 2K of pattern memory @@ -1552,9 +1575,6 @@ START: STA ppu_ctrl STA PPUCTRL - LDA #1 ; !!! Detect NTSC - STA ntsc - JSR music_init JSR mode_0 From 5fd70df3c9b5ec88f9c18f48c565549930d13c65 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 24 Aug 2025 20:17:11 -0600 Subject: [PATCH 071/155] NES adapted brinquitos_nes.bas --- cvbasic.c | 5 + examples/brinquitos_nes.bas | 377 ++++++++++++++++++++++++++++++++++++ manual.txt | 16 ++ 3 files changed, 398 insertions(+) create mode 100644 examples/brinquitos_nes.bas diff --git a/cvbasic.c b/cvbasic.c index 5e1337d..1e0cb00 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5864,6 +5864,11 @@ void compile_statement(int check_for_else) break; case 15: get_lex(); + if (lex != C_COMMA) { + emit_error("missing comma in sound"); + } else { + get_lex(); + } type = evaluate_expression(1, TYPE_8, 0); if (machine == NES) { cpu6502_1op("STA", "$4015"); diff --git a/examples/brinquitos_nes.bas b/examples/brinquitos_nes.bas new file mode 100644 index 0000000..35fe684 --- /dev/null +++ b/examples/brinquitos_nes.bas @@ -0,0 +1,377 @@ + ' + ' Brinquitos: Demo game + ' + ' by Oscar Toledo Gutiérrez + ' https://nanochess.org/ + ' + ' Creation date: Oct/06/2024. + ' Revision date: Aug/24/2025. Adapted to NES/Famicom. + ' + + CONST MAX_CLOUDS = 4 + + ' + ' Cloud information + ' + DIM cloud_x(MAX_CLOUDS) ' X-coordinate + DIM cloud_y(MAX_CLOUDS) ' Y-coordinate + DIM cloud_e(MAX_CLOUDS) ' State + + PALETTE LOAD game_palette + + ' + ' Restart game + ' +restart_game: + ' Clear the screen + CLS + + ' Green letters in the center + VPOKE $23C8,$55 + VPOKE $23C9,$55 + VPOKE $23CA,$55 + VPOKE $23CB,$55 + VPOKE $23CC,$55 + VPOKE $23CD,$55 + VPOKE $23CE,$55 + VPOKE $23CF,$55 + + #puntos = 0 + + ' Setup initial clouds + cloud_y(3) = 176 + cloud_y(2) = 126 + cloud_y(1) = 76 + cloud_y(0) = 26 + + cloud_x(3) = 128 + cloud_e(3) = 0 + + c = 2 + GOSUB setup_cloud + c = 1 + GOSUB setup_cloud + c = 0 + GOSUB setup_cloud + + ' Setup player + x = 128 ' X-coordinate + y = 160 ' Y-coordinate + jump_state = 0 ' Jump state + standing_on = 3 ' Standing on cloud 3 + + PLAY SIMPLE + PLAY music_gladiators + + ' + ' Main loop + ' +main_loop: + + ' + ' Jump sound effect. + ' + IF jump_state >= 33 THEN ' Jumping + f = 4 + SOUND 12, $0800 + y + SOUND 15, 15 + ELSEIF jump_state THEN ' Falling + f = 8 + SOUND 12, $0800 + y + SOUND 15, 15 + ELSE ' Standing + f = 0 + SOUND 15, 11 + END IF + + ' Show the player sprite + SPRITE 0, y - 1, x - 8, f + 1, 0 + SPRITE 1, y - 1, x, f + 3, 0 + + ' Show sprites for clouds + FOR c = 0 TO 3 + SPRITE c * 2 + 2, cloud_y(c) - 1, cloud_x(c) - 8, 12 + 1, 1 + SPRITE c * 2 + 3, cloud_y(c) - 1, cloud_x(c), 14 + 1, 1 + NEXT c + + ' Video synchronization + WAIT + + ' Update score + PRINT AT 65,<>#puntos + + ' Detect if it should do vertical displacement... + ' ...of the screen. + IF y < 110 AND jump_state = 0 THEN + y = y + 1 + FOR c = 0 TO MAX_CLOUDS - 1 + cloud_y(c) = cloud_y(c) + 1 + IF cloud_y(c) = 192 THEN + cloud_y(c) = -8 + GOSUB setup_cloud + END IF + NEXT c + END IF + + ' Detect if the player stands on a cloud + IF jump_state <> 0 AND jump_state < 33 AND standing_on = 255 THEN + FOR c = 0 TO MAX_CLOUDS - 1 + IF ABS(cloud_x(c) + 1 - x) < 8 AND ABS(cloud_y(c) - 16 - y) < 3 THEN + jump_state = 0 + y = cloud_y(c) - 16 + standing_on = c + IF was_on <> standing_on THEN + #puntos = #puntos + 1 + END IF + END IF + NEXT c + END IF + + ' Move the clouds + FOR c = 0 TO MAX_CLOUDS - 1 + IF cloud_e(c) = 1 THEN ' 1- Left + IF standing_on = c THEN x = x - 2 + cloud_x(c) = cloud_x(c) - 2 + IF cloud_x(c) < 18 THEN cloud_e(c) = 2 + ELSEIF cloud_e(c) = 2 THEN ' 2- Right + IF standing_on = c THEN x = x + 2 + cloud_x(c) = cloud_x(c) + 2 + IF cloud_x(c) > 238 THEN cloud_e(c) = 1 + END IF + NEXT c + + ' Handle jumping. + IF jump_state THEN + IF jump_state >= 33 THEN + jump_state = jump_state - 1 + y = y - 2 + ELSE + y = y + 2 + IF y = 242 OR y = 243 THEN GOTO end_of_game + END IF + END IF + + ' Jump if button pressed + IF cont.button THEN + IF jump_state = 0 THEN + jump_state = 64 + was_on = standing_on + standing_on = 255 + END IF + END IF + + GOTO main_loop + + ' + ' End of game + ' +end_of_game: + ' Turn off jumping sound effect + SOUND 15, 11 + + ' Final music + PLAY music_end + + PRINT AT 168,"G A M E O V E R" + + FOR c = 1 TO 240 + WAIT + NEXT c + + GOTO restart_game + + ' + ' Setup a cloud + ' +setup_cloud: PROCEDURE + + ' + ' Choose a position with margin of 32 pixels at each side. + ' Make sure the minimum distance of 64 pixels... + ' ...against the next cloud so the jump is possible. + ' + DO + cloud_x(c) = RANDOM(96) * 2 + 32 + LOOP WHILE ABS(cloud_x(c) + 1 - cloud_x((c + 1) % MAX_CLOUDS)) < 64 + + ' Assign a movement direction. + cloud_e(c) = RANDOM(2) + 1 + END + +game_palette: + DATA BYTE $02,$27,$27,$27 + DATA BYTE $02,$27,$27,$2A + DATA BYTE $02,$27,$27,$27 + DATA BYTE $02,$27,$27,$27 + DATA BYTE $02,$27,$16,$12 + DATA BYTE $02,$0F,$10,$30 + DATA BYTE $02,$27,$27,$27 + DATA BYTE $02,$27,$27,$27 + + ' + ' Game sprites + ' + CHRROM 0 + + CHRROM PATTERN 256 + + BITMAP "................" ' Standing + BITMAP "................" + BITMAP "................" + BITMAP "......1111......" + BITMAP ".....111111....." + BITMAP "....11111111...." + BITMAP "...1133113311..." + BITMAP "...1133113311..." + BITMAP "..111111111111.." + BITMAP ".11111311311111." + BITMAP "11.1..1111..1.11" + BITMAP "11.11......11.11" + BITMAP "11.1111111111.11" + BITMAP "222..11..11..222" + BITMAP "....222..222...." + BITMAP "...2222..2222..." + + BITMAP ".22..........22." ' Jumping + BITMAP "222..........222" + BITMAP "111...1111...111" + BITMAP ".11..111111..11." + BITMAP ".11.13311331.11." + BITMAP ".1.1133113311.1." + BITMAP ".1.1111111111.1." + BITMAP "..111131131111.." + BITMAP "...1..1111..1..." + BITMAP "...11..11..11..." + BITMAP "...111....111..." + BITMAP "...1111111111..." + BITMAP ".....11..11....." + BITMAP ".....11..11....." + BITMAP ".....22..22....." + BITMAP "....222..222...." + + BITMAP ".22..........22." ' Falling + BITMAP "222...1111...222" + BITMAP ".11..111111..11." + BITMAP ".11.13311331.11." + BITMAP ".1.1133113311.1." + BITMAP ".1.1111111111.1." + BITMAP "..111131131111.." + BITMAP "...1111331111..." + BITMAP "...11......11..." + BITMAP "...111....111..." + BITMAP "...1111111111..." + BITMAP ".....11..11....." + BITMAP ".....11..11....." + BITMAP ".....22..22....." + BITMAP ".....22..22....." + BITMAP "....222..222...." + + BITMAP "..333133313....." ' Cloud + BITMAP ".333321332132..." + BITMAP ".3322331332132.." + BITMAP "33211331332132.." + BITMAP "22133311223112.." + BITMAP ".133313311132..." + BITMAP ".3333133213332.." + BITMAP ".33331332133332." + BITMAP "..2222..22..22.." + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + BITMAP "................" + + ' + ' Gladiators music (circus entry) + ' +music_gladiators: + DATA BYTE 7 + MUSIC C5,C3,-,- + MUSIC S,S,-,- + MUSIC B4,G3,-,- + MUSIC S,S,-,- + MUSIC A4#,G2,-,- + MUSIC B4,S,-,- + MUSIC A4#,G3,-,- + MUSIC A4,S,-,- + + MUSIC G4#,C3,-,- + MUSIC S,S,-,- + MUSIC G4,G3,-,- + MUSIC S,S,-,- + MUSIC F4#,G2,-,- + MUSIC S,S,-,- + MUSIC G4,G3,-,- + MUSIC S,S,-,- + + MUSIC A4,C3,-,- + MUSIC S,S,-,- + MUSIC G4#,G3,-,- + MUSIC S,S,-,- + MUSIC G4,G2,-,- + MUSIC G4#,S,-,- + MUSIC G4,G3,-,- + MUSIC F4#,S,-,- + + MUSIC F4,C3,-,- + MUSIC S,S,-,- + MUSIC E4,G3,-,- + MUSIC S,S,-,- + MUSIC D4#,G2,-,- + MUSIC S,S,-,- + MUSIC E4,G3,-,- + MUSIC S,S,-,- + + MUSIC G4,B2,-,- + MUSIC S,S,-,- + MUSIC F4,G3,-,- + MUSIC F4,S,-,- + MUSIC C4#,G2,-,- + MUSIC S,S,-,- + MUSIC D4,G3,-,- + MUSIC S,S,-,- + + MUSIC G4,B2,-,- + MUSIC S,S,-,- + MUSIC F4,G3,-,- + MUSIC F4,S,-,- + MUSIC C4#,G2,-,- + MUSIC S,S,-,- + MUSIC D4,G3,-,- + MUSIC S,S,-,- + + MUSIC B3,B2,-,- + MUSIC C4,S,-,- + MUSIC C4S,G3,-,- + MUSIC D4,S,-,- + MUSIC D4S,G2,-,- + MUSIC E4,S,-,- + MUSIC F4,G3,-,- + MUSIC F4S,S,-,- + + MUSIC G4,B2,-,- + MUSIC G4S,S,-,- + MUSIC A4,G3,-,- + MUSIC B4,S,-,- + MUSIC A4,G2,-,- + MUSIC S,S,-,- + MUSIC G4,G3,-,- + MUSIC S,S,-,- + + MUSIC REPEAT + + ' + ' Music for end of game. + ' +music_end: + DATA BYTE 20 + MUSIC C4,-,-,- + MUSIC G3,-,-,- + MUSIC C3,-,-,- + MUSIC S,-,-,- + MUSIC S,-,-,- + MUSIC S,-,-,- + MUSIC STOP + diff --git a/manual.txt b/manual.txt index 824c559..1543607 100644 --- a/manual.txt +++ b/manual.txt @@ -792,6 +792,8 @@ The following statements are available: PALETTE LOAD array_data_byte PALETTE LOAD VARPTR array_data_byte(0) + For the Sega Master System: + Sets a single palette register (0-31) to the color (0-63). Color bits are specified in a single byte as 00BBGGRR (two bits each for red, green, and blue). @@ -802,6 +804,20 @@ The following statements are available: Alternatively, you can load a full 32 entries palette using PALETTE LOAD. The array should be specified with DATA BYTE. + For the NES/Famicom: + + Registers + 0-3 palette 0 for background tiles. + 4-7 palette 1 for background tiles. + 8-11 palette 2 for background tiles. + 12-15 palette 3 for background tiles. + 16-19 palette 0 for sprites (16 unused because it is transparent) + 20-23 palette 1 for sprites (20 unused because it is transparent) + 24-27 palette 2 for sprites (24 unused because it is transparent) + 28-31 palette 3 for sprites (28 unused because it is transparent) + + For the palette colors see https://www.nesdev.org/wiki/PPU_palettes#2C02 + MODE 0 Select the video mode 0. In this mode, the 32x24 screen grid can have one From e7c6bb32fd7a7da23f75b9626c01860036a8e922 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 24 Aug 2025 20:18:01 -0600 Subject: [PATCH 072/155] Adjustments --- manual.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manual.txt b/manual.txt index 1543607..6dafd1f 100644 --- a/manual.txt +++ b/manual.txt @@ -811,10 +811,10 @@ The following statements are available: 4-7 palette 1 for background tiles. 8-11 palette 2 for background tiles. 12-15 palette 3 for background tiles. - 16-19 palette 0 for sprites (16 unused because it is transparent) - 20-23 palette 1 for sprites (20 unused because it is transparent) - 24-27 palette 2 for sprites (24 unused because it is transparent) - 28-31 palette 3 for sprites (28 unused because it is transparent) + 16-19 palette 0 for sprites + 20-23 palette 1 for sprites + 24-27 palette 2 for sprites + 28-31 palette 3 for sprites For the palette colors see https://www.nesdev.org/wiki/PPU_palettes#2C02 From 6aef2f6ab2b1834f13c9c5f402f1302ccbec31a0 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 25 Aug 2025 11:33:07 -0600 Subject: [PATCH 073/155] NES updated manual --- cvbasic.c | 2 +- manual.txt | 97 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 1e0cb00..1a2a78b 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -4863,7 +4863,7 @@ void compile_statement(int check_for_else) cpu6502_1op("STA", "ppu_mask"); } } - } else if (strcmp(name, "SCROLL") == 0) { /* Sega Master System */ + } else if (strcmp(name, "SCROLL") == 0) { /* Sega Master System / NES/Famicom */ int type; get_lex(); diff --git a/manual.txt b/manual.txt index 6dafd1f..716408e 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Apr/26/2025 +Last revision: Aug/25/2025 >>>>>>>>>>>>>> Legal notice @@ -22,7 +22,7 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.0 Aug/23/2025 o Added support for NES/Famicom using --nes +v0.9.0 Aug/25/2025 o Added support for NES/Famicom using --nes o MSX: Added support for Konami mapper using -konami o Solved bug in DEF FN precedence inside expressions. o Solved bug in > operator with 16-bit variable. @@ -421,6 +421,20 @@ The following statements are available: Poke VRAM with data. + For NES/Famicom: + + Any write to VRAM (VPOKE, PRINT, SCREEN) is buffered, this means it doesn't + happen immediately, but instead when the next vertical refresh happens on + the screen. This also means there is a limit to how much data you can + update in a single frame (typically around 96-128 bytes). + + The internal buffer can get filled (22 VPOKE or number digits from PRINT, + 12 strings PRINT, or 12 SCREEN lines), and it will trigger automatically a + WAIT so it doesn't overflow. + + If you are writing more than 96-128 bytes per frame, you can use + SCREEN DISABLE and SCREEN ENABLE. + WAIT Waits for the next frame interruption (1/60 of a second for NTSC or 1/50 @@ -503,7 +517,7 @@ The following statements are available: DEFINE CHAR char_num,total,VARPTR array(expr) DEFINE CHAR PLETTER char_num,total,label - Loads graphics into VRAM. + Loads graphics into VRAM. This sentence isn't used on NES/Famicom. "char_num" valid values are between 0 and 255. @@ -534,7 +548,8 @@ The following statements are available: DEFINE COLOR char_num,total,VARPTR array(expr) DEFINE COLOR PLETTER char_num,total,label - Loads color into VRAM. This sentence isn't used on Sega Master System. + Loads color into VRAM. This sentence isn't used on Sega Master System nor + NES/Famicom. "char_num" valid values are between 0 and 255. @@ -558,13 +573,11 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) - This sentence isn't supported for NES/Famicom. - DEFINE SPRITE sprite_num,total,label DEFINE SPRITE sprite_num,total,VARPTR array(expr) DEFINE SPRITE PLETTER sprite_num,total,label - Loads sprites into VRAM + Loads sprites into VRAM. This sentence isn't used on NES/Famicom. "sprite_num" valid values are between 0 and 63 (127 for Sega Master System) @@ -583,14 +596,12 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) - This sentence isn't supported for NES/Famicom. - DEFINE VRAM address,length,label DEFINE VRAM address,length,VARPTR array(expr) DEFINE VRAM PLETTER address,length,label - Copies data from "label" into VRAM address "address". - The total of bytes is defined by "length". + Copies data from "label" into VRAM address "address". The total of bytes + is defined by "length". This sentence isn't supported for NES/Famicom. The VARPTR expression allows choosing the origin from an offset inside an array so you can do animation easily. @@ -599,19 +610,15 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) - This sentence isn't supported for NES/Famicom. - DEFINE VRAM READ address,length,label DEFINE VRAM READ address,length,VARPTR array(expr) - Copies data from VRAM address "address" into "label". - The total of bytes is defined by "length". + Copies data from VRAM address "address" into "label". The total of bytes + is defined by "length". This sentence isn't supported for NES/Famicom. The VARPTR expression allows choosing the origin from an offset inside an array. - This sentence isn't supported for NES/Famicom. - SOUND 0,[value 10 bits],[vol 0-15] SOUND 1,[value 10 bits],[vol 0-15] SOUND 2,[value 10 bits],[vol 0-15] @@ -658,6 +665,41 @@ The following statements are available: NOTE: USE ONLY VALUES $80-$BF FOR MIX BECAUSE ANY VALUE OUTSIDE THIS CAN BURN YOUR MSX HARDWARE. + SOUND 10,[freq 16 bits],[vol 8 bits],[sweep 8 bits] + SOUND 11,[freq 16 bits],[vol 8 bits],[sweep 8 bits] + SOUND 12,[freq 16 bits],[linear counter] + SOUND 14,[freq 16 bits],[vol 8 bits] + SOUND 15,[setting 8 bits] + + Allows to generate tones on the NES/Famicom Audio Processing Unit (APU). + + For SOUND 10, 11, and 12, the frequency is a 11-bit number, and it has a + duration. For starters you can add $0800 so you can make sure the tone + will have the maximum duration (127 frames). + + For SOUND 14 the frequency is a 4-bit number, also you need to add $0800. + + The volume is a number from zero (silent) to fifteen (highest volume). + + Bit 4 means the volume is fixed (you probably willl always use this by + adding $10), else it uses an envelope decay (in combination with bit 5) + + Bits 7-6 indicate the duty cycle (0= 12.5%, 1= 25%, 2= 50%, 3= 75%) + + Sweep + bit 7: 0=disable, 1=enable + bit 6-4: Sweep update rate NTSC = 120hz / (n + 1), PAL = 96 hz / (n + 1) + bit 3: 0=+increase, 1=-decrease + bit 2-0: Sweep right shift amount (1 means one bit to right) + until frequency value becomes zero. + + As SOUND 12 doesn't have a volume register, you should turn it on using + SOUND 15, 15, and turn it off using SOUND 15, 11. + + Don't update the frequency if it is the same, or otherwise the output + phase will reset and generate glitches in the audio output. + + SPRITE index,y,x,f,c (All others) SPRITE index,y,x,f. (SMS) SPRITE index,y,x,f,a (NES/Famicom) @@ -777,17 +819,25 @@ The following statements are available: BORDER color,flags Select the border color. It can be a number from 0 to 15. - The first argument isn't available for NES/Famicom. - The flags argument is available on Sega Master System. + The first argument isn't available for NES/Famicom, the small border around + is always black. + + The flags argument for Sega Master System. bit 0 = Set column 0 to border color. bit 1 = Horizontal scrolling disabled on rows 0-1. bit 2 = Vertical scrolling disabled on columns 24-31. + The flags argument for NES/Famicom. + bit 0 = Background clipping (0 = hide left 8-pixel column, 1 = no clipping) + bit 1 = Sprite clipping (0 = hide left 8-pixel column, 1 = no clipping) + SCROLL x, y Sets the pixel scrolling for Sega Master System background. + Sets the pixel scrolling for NES/Famicom background. + PALETTE register, color PALETTE LOAD array_data_byte PALETTE LOAD VARPTR array_data_byte(0) @@ -818,6 +868,11 @@ The following statements are available: For the palette colors see https://www.nesdev.org/wiki/PPU_palettes#2C02 + When you update the full palette the 32 bytes are written into the palette + memory, and because how the NES/Famicom palette memory is implemented, + the value at the offset 16 will be written over the offset 0 (the background + color) + MODE 0 Select the video mode 0. In this mode, the 32x24 screen grid can have one @@ -836,6 +891,8 @@ The following statements are available: 6 - Dark red. e - Gray. 7 - Cyan. f - White. + For NES/Famicom, it simply clears the screen and erases the sprites. + MODE 1 Select the video mode 1. This is a high-resolution video mode where @@ -1076,6 +1133,8 @@ The following statements are available: Sets the VDP register to the expression value. + Not supported for NES/Famicom. + CALL NAME Calls assembly function NAME without arguments. Note CVBasic will put the From 31d8b9da88f7570f2ec9fc6dd7708dfaacd3c6bd Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 25 Aug 2025 11:48:33 -0600 Subject: [PATCH 074/155] NES added VRAM notes (also for SMS) --- manual.txt | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/manual.txt b/manual.txt index 716408e..7460436 100644 --- a/manual.txt +++ b/manual.txt @@ -421,8 +421,22 @@ The following statements are available: Poke VRAM with data. + For Sega Master System: + + All the VRAM $0000-$3fff can be used for tiles. Each 8x8 tile uses 32 bytes. + Each 8 bytes cover a color bit from least significant bit to most significant + bit. + + However the area $3800-$3dff contains the screen pattern data. The even bytes + contain the pattern number, and the odd bytes contain the bit 8 of pattern + number. See the SCREEN statement for further details on the flags. + For NES/Famicom: + Only the VRAM area $2000-$27ff can be accessed. By default the full screen is + displayed from the area $2000-$23ff. The remaining is used when the SCROLL + statement is used. + Any write to VRAM (VPOKE, PRINT, SCREEN) is buffered, this means it doesn't happen immediately, but instead when the next vertical refresh happens on the screen. This also means there is a limit to how much data you can @@ -435,6 +449,27 @@ The following statements are available: If you are writing more than 96-128 bytes per frame, you can use SCREEN DISABLE and SCREEN ENABLE. + These are the palette assignment bytes for the main screen. + + $23c0 = XX XX XX XX XX XX XX XX + $23c8 = XX XX XX XX XX XX XX XX + $23d0 = XX XX XX XX XX XX XX XX + $23d8 = XX XX XX XX XX XX XX XX + $23e0 = XX XX XX XX XX XX XX XX + $23e8 = XX XX XX XX XX XX XX XX + $23f0 = XX XX XX XX XX XX XX XX + $23f8 = XX XX XX XX XX XX XX XX + + Where each byte covers a 4x4 area: + + 2 cols 2 cols + |-------|-------| + |bit 1-0|bit 3-2| 2 rows + |-------|-------| + |bit 5-4|bit 7-6| 2 rows + |-------|-------| + + WAIT Waits for the next frame interruption (1/60 of a second for NTSC or 1/50 @@ -741,7 +776,10 @@ The following statements are available: y = Vertical position - 1 ($ff, $00 - $ee = scanline 0..239) To hide sprites use $f0 ($ef - $fe aren't displayed) x = Horizontal position. - f = bit 7-1 = tile, bit 0 = pattern address ($0000 or $1000) + f = bit 7-1 = pattern number, bit 0 = pattern address ($0000 or $1000) + An address of $0000 means the sprite will access the + patterns 0-254, and an address of $1000 means the sprite + will access the patterns 256-510. a = bit 7 = 1 = Vertical flip. bit 6 = 1 = Horizontal flip. bit 5 = 1 = Sprite behind background. @@ -969,6 +1007,20 @@ The following statements are available: bit 3 - Uses sprite palette if set. bit 4 - The tile will be drawn on top of sprites. + + CHRROM number + CHRROM PATTERN number + + For NES/Famicom the graphic data are saved into CHRROM banks of 8K. + + You should specify the CHRROM bank before putting any BITMAP statement. + Currently only CHRROM 0 is supported. + + CVBasic will predefine an ASCII charset with color 3 in the patterns 32-127. + + You can choose the pattern number (0-511) for the following BITMAP statements. + + BITMAP "00000000" BITMAP "00001111" @@ -994,6 +1046,8 @@ The following statements are available: The colors for each pixel are specified by using hexadecimal digits 1 to 9, and A to F. + For the NES/Famicom, the sprites are composed by 8x16 pixels. The colors for + each pixel are specified by the digits 1 to 3. PLAY SIMPLE PLAY SIMPLE NO DRUMS From 7d2fc1e5a0d63ccc032241b33128105dd8715bc3 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 26 Aug 2025 10:40:19 +0200 Subject: [PATCH 075/155] Update target check --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index ebf61bf..8d2ff67 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,8 @@ cvbasic: cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o check: cvbasic @./$< examples/viboritas.bas /tmp/viboritas.asm + @./$< --sms examples/viboritas_sms.bas /tmp/viboritas_sms.asm + @./$< --nes examples/viboritas_nes.bas /tmp/viboritas_nes.asm clean: @rm cvbasic cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o From f3cf3234d3b7c4ff34f6738103db96653340a3bf Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 26 Aug 2025 11:30:02 +0200 Subject: [PATCH 076/155] Fixed minor typo --- manual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual.txt b/manual.txt index 7460436..a3db910 100644 --- a/manual.txt +++ b/manual.txt @@ -716,7 +716,7 @@ The following statements are available: The volume is a number from zero (silent) to fifteen (highest volume). - Bit 4 means the volume is fixed (you probably willl always use this by + Bit 4 means the volume is fixed (you probably will always use this by adding $10), else it uses an envelope decay (in combination with bit 5) Bits 7-6 indicate the duty cycle (0= 12.5%, 1= 25%, 2= 50%, 3= 75%) From 89eb0b8c9657d333be5b831e4a10472d63b813ff Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 11:11:50 -0600 Subject: [PATCH 077/155] NES added bank-switching, bank_nes.bas, demo_nes.bas, oscar_nes.bas --- README.md | 4 +- cpu6502.c | 2 +- cvbasic.c | 236 +++++-- cvbasic_nes_prologue.asm | 163 ++++- examples/bank_nes.bas | 1287 ++++++++++++++++++++++++++++++++++++++ examples/demo_nes.bas | 707 +++++++++++++++++++++ examples/hello.bas | 15 - examples/oscar_nes.bas | 1099 ++++++++++++++++++++++++++++++++ manual.txt | 54 +- 9 files changed, 3460 insertions(+), 107 deletions(-) create mode 100644 examples/bank_nes.bas create mode 100644 examples/demo_nes.bas delete mode 100644 examples/hello.bas create mode 100644 examples/oscar_nes.bas diff --git a/README.md b/README.md index 33a852d..81ca7a0 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Later it was extended to support the following platforms: * Hanimex/Soundic Pencil II. * NABU PC. * Sega Master System (supporting bank switching with Sega mapper) -* NES/Famicom (preliminary) +* NES/Famicom (preliminary, supporting bank switching using UNROM 512) One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. @@ -234,7 +234,7 @@ The TI-99/4A can only generate non-banked binaries up to 24 kb. When banking, th The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1 (<||| is the primary button and |||> is the secondary button), and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. -The NES support is highly experimental, currently only 32K ROM. Five demos have been ported and are functional: face_joystick, happy_face, music, Space Attack, and Viboritas. Missing image converter. +The NES support is highly experimental. Five demos have been ported and are functional: face_joystick, happy_face, music, Space Attack, and Viboritas. Missing image converter. Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) diff --git a/cpu6502.c b/cpu6502.c index 9ed6b8e..6e975bb 100644 --- a/cpu6502.c +++ b/cpu6502.c @@ -197,7 +197,7 @@ void cpu6502_1op(char *mnemonic, char *operand) if (cpu6502_y[0] != '#') cpu6502_y[0] = '\0'; cpu6502_flag_z_valid = 0; - } else if (strcmp(mnemonic, "JSR") == 0 || strcmp(mnemonic, "JMP") == 0) { + } else if (strcmp(mnemonic, "JSR") == 0 || strcmp(mnemonic, "JMP") == 0 || strcmp(mnemonic, "ORG") == 0 || strcmp(mnemonic, "FORG") == 0) { cpu6502_a[0] = '\0'; cpu6502_x[0] = '\0'; cpu6502_y[0] = '\0'; diff --git a/cvbasic.c b/cvbasic.c index 1a2a78b..8a55ad8 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -12,6 +12,7 @@ ** RESTORE/READ/DATA. Added small local optimization. ** Revision date: Aug/23/2024. Added TI-99/4A. ** Revision date: Apr/26/2025. Added Sega Master System. + ** Revision date: Aug/23/2025. Added NES/Famicom. */ #include @@ -32,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.0 Aug/23/2025" +#define VERSION "v0.9.0 Aug/25/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -243,6 +244,7 @@ int current_chrrom; int chrrom_pointer; int chrrom_size; unsigned char *chrrom_data; +int nes_nametable; void reset_chrrom(unsigned char *page) { @@ -441,6 +443,15 @@ void bank_finish(void) fprintf(output, "\tTIMES $bfff-$ DB $ff\n"); } fprintf(output, "\tDB $%02x\n", bank_konami ? bank_current * 2 : bank_current); + } else if (machine == NES) { + if (bank_current == 0) { + fprintf(output, "BANK_0_FREE:\tEQU $fffa-$\n"); + fprintf(output, "\tTIMES $fffa-$ DB $ff\n"); + } else { + fprintf(output, "BANK_%d_FREE:\tEQU $bfff-$\n", bank_current); + fprintf(output, "\tTIMES $bfff-$ DB $ff\n"); + } + fprintf(output, "\tDB $%02x\n", (bank_current - 1) & 0x1f); } else if (machine == TI994A) { if (bank_current == 0) { // bank 0 is copied to RAM so is 24k @@ -1457,6 +1468,8 @@ struct node *evaluate_level_7(int *type) return tree; } if (strcmp(name, "VPEEK") == 0) { + if (machine == NES) + emit_error("VPEEK cannot be used in NES/Famicom"); get_lex(); if (lex != C_LPAREN) { emit_error("missing left parenthesis in VPEEK"); @@ -4951,7 +4964,7 @@ void compile_statement(int check_for_else) } else if (machine == NES) { cpu6502_1op("LDX", "ppu_pointer"); cpu6502_1op("STA", "PPUBUF,X"); - cpu6502_1op("LDA", "#$bf"); + cpu6502_1op("LDA", "#$7f"); cpu6502_1op("STA", "PPUBUF+1,X"); } if (lex != C_COMMA) @@ -4964,39 +4977,67 @@ void compile_statement(int check_for_else) generic_interrupt_enable(); } else if (machine == NES) { cpu6502_1op("LDX", "ppu_pointer"); - cpu6502_1op("STA", "PPUBUF+3,X"); - cpu6502_1op("LDA", "#1"); cpu6502_1op("STA", "PPUBUF+2,X"); - cpu6502_noop("TXA"); - cpu6502_noop("CLC"); - cpu6502_1op("ADC", "#4"); - cpu6502_1op("STA", "ppu_pointer"); + cpu6502_noop("INX"); + cpu6502_noop("INX"); + cpu6502_noop("INX"); + cpu6502_1op("STX", "ppu_pointer"); } } - } else if (strcmp(name, "CHRROM") == 0) { /* Select CHRROM */ + } else if (strcmp(name, "NAMETABLE") == 0) { /* Select nametable arrangement */ int type; struct node *tree; int c; if (machine != NES) - emit_error("CHRROM is only admited for NES/Famicom"); + emit_error("CHRRAM is only allowed for NES/Famicom"); + else if (bank_switching == 0) + emit_error("It is required a BANK ROM sentence to enable CHRRAM"); get_lex(); - if (strcmp(name, "PATTERN") == 0) { - get_lex(); - tree = evaluate_level_0(&type); - if (tree->type != N_NUM8 && tree->type != N_NUM16) { - emit_error("Not a constant expression in CHRROM"); - c = 0; - } else { - c = tree->value; - } - node_delete(tree); - if (c < 0 || c > 511) { - emit_error("CHRROM PATTERN out of range 0-511"); - c = 0; - } - chrrom_pointer = c * 16; + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("Not a constant expression in CHRRAM"); + c = 0; + } else { + c = tree->value; + } + node_delete(tree); + if (c < 0 || c > 3) + emit_error("NAMETABLE value outside of range 0-3"); + nes_nametable = c; + } else if (strcmp(name, "CHRRAM") == 0) { /* Select CHRRAM */ + int type; + struct node *tree; + int c; + + if (machine != NES) + emit_error("CHRRAM is only allowed for NES/Famicom"); + else if (bank_switching == 0) + emit_error("It is required a BANK ROM sentence to enable CHRRAM"); + get_lex(); + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("Not a constant expression in CHRRAM"); + c = 0; } else { + c = tree->value; + } + node_delete(tree); + if (c < 0 || c > 7) + emit_error("CHRRAM value outside of range 0-7"); + c = c << 5; + sprintf(temp, "#%d", c); + cpu6502_1op("LDA", temp); + cpu6502_1op("STA", "CHRRAM_BANK"); + } else if (strcmp(name, "CHRROM") == 0) { /* Select CHRROM */ + int type; + struct node *tree; + int c; + + if (machine != NES) + emit_error("CHRROM is only allowed for NES/Famicom"); + get_lex(); + if (lex != C_NAME || strcmp(name, "PATTERN") != 0) { tree = evaluate_level_0(&type); if (tree->type != N_NUM8 && tree->type != N_NUM16) { emit_error("Not a constant expression in CHRROM"); @@ -5022,6 +5063,22 @@ void compile_statement(int check_for_else) current_chrrom = c; chrrom_pointer = 0; } + if (lex == C_NAME && strcmp(name, "PATTERN") == 0) { + get_lex(); + tree = evaluate_level_0(&type); + if (tree->type != N_NUM8 && tree->type != N_NUM16) { + emit_error("Not a constant expression in CHRROM"); + c = 0; + } else { + c = tree->value; + } + node_delete(tree); + if (c < 0 || c > 511) { + emit_error("CHRROM PATTERN out of range 0-511"); + c = 0; + } + chrrom_pointer = c * 16; + } } else if (strcmp(name, "MODE") == 0) { get_lex(); if (lex != C_NUM || (value != 0 && value != 1 && value != 2 && value != 4)) { @@ -5222,24 +5279,40 @@ void compile_statement(int check_for_else) } else { if (target == CPU_6502) { if (machine == NES) { - emit_error("full screen SCREEN not allowed with NES/Famicom"); + sprintf(temp, "#%s", assigned); + cpu6502_1op("LDA", temp); + strcat(temp, ">>8"); + cpu6502_1op("LDY", temp); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + cpu6502_1op("LDA", "#$f0"); + cpu6502_1op("LDY", "#0"); + cpu6502_1op("STA", "temp2"); + cpu6502_1op("STY", "temp2+1"); + cpu6502_1op("LDA", "#$00"); + cpu6502_1op("LDY", "#$20"); + cpu6502_1op("STA", "pointer"); + cpu6502_1op("STY", "pointer+1"); + cpu6502_1op("JSR", "LDIRVM4"); + } else { + sprintf(temp, "#%s", assigned); + cpu6502_1op("LDA", temp); + strcat(temp, ">>8"); + cpu6502_1op("LDY", temp); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + cpu6502_1op("LDA", "#0"); + cpu6502_1op("LDY", "#3"); + cpu6502_1op("STA", "temp2"); + cpu6502_1op("STY", "temp2+1"); + cpu6502_1op("LDA", "#$00"); + cpu6502_1op("LDY", "#$18"); + cpu6502_1op("STA", "pointer"); + cpu6502_1op("STY", "pointer+1"); + generic_interrupt_disable(); + cpu6502_1op("JSR", "LDIRVM"); + generic_interrupt_enable(); } - sprintf(temp, "#%s", assigned); - cpu6502_1op("LDA", temp); - strcat(temp, ">>8"); - cpu6502_1op("LDY", temp); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); - cpu6502_1op("LDA", (machine == NES) ? "#$c0" : "#0"); - cpu6502_1op("LDY", "#3"); - cpu6502_1op("STA", "temp2"); - cpu6502_1op("STY", "temp2+1"); - cpu6502_1op("LDA", "#0"); - cpu6502_1op("LDY", (machine == NES) ? "#32" : "#24"); - cpu6502_1op("STA", "pointer"); - cpu6502_1op("STY", "pointer+1"); - generic_interrupt_disable(); - cpu6502_1op("JSR", "LDIRVM"); } else if (target == CPU_9900) { cpu9900_2op("li","r0",">1800"); cpu9900_2op("li","r2",assigned); @@ -5247,14 +5320,15 @@ void compile_statement(int check_for_else) generic_interrupt_disable(); cpu9900_1op("bl","@jsr"); cpu9900_1op("data","LDIRVM"); + generic_interrupt_enable(); } else { cpuz80_2op("LD", "HL", assigned); cpuz80_2op("LD", "DE", (machine == SMS ? "$3800" : "$1800")); cpuz80_2op("LD", "BC", (machine == SMS ? "$0600" : "$0300")); generic_interrupt_disable(); cpuz80_1op("CALL", "LDIRVM"); + generic_interrupt_enable(); } - generic_interrupt_enable(); } } } else if (strcmp(name, "PLAY") == 0) { @@ -5921,8 +5995,10 @@ void compile_statement(int check_for_else) emit_error("BANK ROM used twice"); get_lex(); } else { - if (machine == SVI || machine == SORD || machine == MEMOTECH || machine == CREATIVISION || machine == NES || machine == EINSTEIN || machine == PV2000) { + if (machine == SVI || machine == SORD || machine == MEMOTECH || machine == CREATIVISION || machine == EINSTEIN || machine == PV2000) { emit_error("Bank-switching not supported with current platform"); + } else if (machine == NES && (value == 128 || value == 1024)) { + emit_error("NES/Famicom only supports 256 or 512 k ROM size"); } else { bank_switching = 1; bank_rom_size = value; @@ -5966,21 +6042,28 @@ void compile_statement(int check_for_else) } else { if (machine == COLECOVISION || machine == COLECOVISION_SGM) c--; - if (bank_rom_size == 128) - c &= 0x07; - else if (bank_rom_size == 256) - c &= 0x0f; - else if (bank_rom_size == 512) - c &= 0x1f; - else - c &= 0x3f; + if (machine == NES) { + c = (c & 0xe0) | ((c - 1) & 0x1f); + if ((bank_rom_size == 256 && (c & 0x0f) >= 0x0d) || (bank_rom_size == 512 && (c & 0x1f) >= 0x1d)) { + emit_warning("Selecting bank reserved for CHRROM data"); + } + } else { + if (bank_rom_size == 128) + c &= 0x07; + else if (bank_rom_size == 256) + c &= 0x0f; + else if (bank_rom_size == 512) + c &= 0x1f; + else + c &= 0x3f; + } if (machine == SG1000 || machine == SMS) { - sprintf(temp, "%d", c & 0x3f); + sprintf(temp, "%d", c); cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "($fffe)", "A"); } else if (machine == MSX) { if (bank_konami) { - sprintf(temp, "%d", (c & 0x3f) * 2); + sprintf(temp, "%d", c * 2); cpuz80_noop("DI"); cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "($8000)", "A"); @@ -5988,10 +6071,15 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "($a000)", "A"); cpuz80_noop("EI"); } else { - sprintf(temp, "%d", c & 0x3f); + sprintf(temp, "%d", c); cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "($7000)", "A"); } + } else if (machine == NES) { + sprintf(temp, "#%d", c); + cpu6502_1op("LDA", temp); + cpu6502_1op("ORA", "CHRRAM_BANK"); + cpu6502_1op("STA", "BANKSEL"); } else { if (bank_rom_size == 128) c |= 0xfff8; @@ -6042,10 +6130,10 @@ void compile_statement(int check_for_else) cpu9900_1op("bank", temp); cpu9900_empty(); } else { - if (machine == COLECOVISION || machine == COLECOVISION_SGM) + if (machine == COLECOVISION || machine == COLECOVISION_SGM || machine == NES) c--; if (machine == TI994A) - c+=2; /* reserving 3 banks (0,1,2) for 'fixed' space */ + c += 2; /* reserving 3 banks (0,1,2) for 'fixed' space */ if (bank_rom_size == 128) c &= 0x07; else if (bank_rom_size == 256) @@ -6055,13 +6143,25 @@ void compile_statement(int check_for_else) else c &= 0x3f; bank_finish(); - sprintf(temp, "$%05x", c << 14); - cpuz80_1op("FORG", temp); + if (machine == NES) { + if ((bank_rom_size == 256 && c >= 0x0d) || (bank_rom_size == 512 && c >= 0x1d)) { + emit_error("Using bank reserved for CHRROM data"); + } + sprintf(temp, "$%05x", (c << 14) + 0x0010); + } else { + sprintf(temp, "$%05x", c << 14); + } if (machine == SG1000 || machine == SMS) { + cpuz80_1op("FORG", temp); cpuz80_1op("ORG", "$4000"); } else if (machine == MSX) { + cpuz80_1op("FORG", temp); cpuz80_1op("ORG", "$8000"); + } else if (machine == NES) { + cpu6502_1op("FORG", temp); + cpu6502_1op("ORG", "$8000"); } else { + cpuz80_1op("FORG", temp); cpuz80_1op("ORG", "$c000"); } cpuz80_empty(); @@ -6639,6 +6739,7 @@ int main(int argc, char *argv[]) chrrom_pointer = 0; /* Only NES */ chrrom_size = 0; /* Only NES */ chrrom_data = NULL; /* Only NES */ + nes_nametable = 0; /* Only NES */ compile_basic(); if (loops != NULL) @@ -6715,8 +6816,12 @@ int main(int argc, char *argv[]) fprintf(output, "NABU:\tequ %d\n", (machine == NABU) ? 1 : 0); fprintf(output, "SMS:\tequ %d\n", (machine == SMS) ? 1 : 0); if (machine == NES) { - fprintf(output, "NES_PRG_BANKS:\tequ 2\t; Each one 16K.\n"); + if (bank_switching) + fprintf(output, "NES_PRG_BANKS:\tequ %d\t; Each one 16K.\n", bank_rom_size / 16); + else + fprintf(output, "NES_PRG_BANKS:\tequ 2\t; Each one 16K.\n"); fprintf(output, "NES_CHR_BANKS:\tequ %d\t; Each one 4K.\n", chrrom_size); + fprintf(output, "NES_NAMETABLE:\tequ %d\n", (nes_nametable & 1) | ((nes_nametable & 2) << 2)); } fprintf(output, "\n"); fprintf(output, "CVBASIC_MUSIC_PLAYER:\tequ %d\n", music_used); @@ -6838,6 +6943,17 @@ int main(int argc, char *argv[]) ** NES CHRROM output */ if (machine == NES) { + if (bank_switching) { + if (chrrom_size > 4) { + fprintf(stderr, "ERROR: More than 4 CHRROM pages for bank-switched cartridge.\n"); + } + if (bank_rom_size == 256) { + fprintf(output, "\nFORG $34000\n"); + } else { + fprintf(output, "\nFORG $74000\n"); + } + fprintf(output, "\nORG $8000\n"); + } fprintf(output, "\n; CHR data\n"); for (c = 0; c < chrrom_size * CHRROM_PAGE; c += 8) { fprintf(output, "\tdb $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 4cf29bf..61e7ca9 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -9,6 +9,8 @@ ; Revision date: Aug/23/2025. Support for writing VRAM and PRINT. ; Revision date: Aug/24/2025. Support for scrolling, SCREEN, and DISABLE/ENABLE. ; Added music player. + ; Revision date: Aug/25/2025. Added support for 256K and 512K ROM. + ; Revision date: Aug/26/2025. Added support for CHRRAM selection. ; CPU 6502 @@ -31,29 +33,31 @@ pointer: equ $08 read_pointer: equ $0a cursor: equ $0c -ppu_pointer: equ $0e -ppu_temp: equ $0f ; Used in NMI to save X - -scroll_x: equ $10 -scroll_y: equ $12 -ppu_ctrl: equ $14 -ppu_mask: equ $15 +mode: equ $0e +ntsc: equ $0f + +vdp_status: equ $10 +flicker: equ $11 +frame: equ $12 +ppu_pointer: equ $14 +ppu_temp: equ $15 ; Used in NMI to save X +ppu_ctrl: equ $16 +ppu_mask: equ $17 +scroll_x: equ $18 +scroll_y: equ $1a +CHRRAM_BANK: equ $1c +cont_bits: equ $1d +lfsr: equ $1e joy1_data: equ $20 joy2_data: equ $21 key1_data: equ $22 key2_data: equ $23 -frame: equ $24 -lfsr: equ $26 -mode: equ $28 -cont_bits: equ $29 -sprite_data: equ $2a -ntsc: equ $2e -flicker: equ $2f -vdp_status: equ $30 +sprite_data: equ $24 IF CVBASIC_MUSIC_PLAYER music_playing: EQU $4f +music_bank: EQU $30 music_timing: EQU $31 music_start: EQU $32 music_pointer: EQU $34 @@ -82,21 +86,39 @@ music_mode: EQU $4e ENDIF SPRITE_PAGE: EQU $02 -PPUBUF: EQU $0100 +PPUBUF: EQU $0100 +BANKSEL: EQU $C000 FORG $0000 ; The ORG address doesn't matter here ; iNES cartridge header DB "NES",$1A DB NES_PRG_BANKS + if CVBASIC_BANK_SWITCHING + DB 0 ; It has CHRRAM + DB $e2|NES_NAMETABLE ; Cartridge type LSB + DB $10 ; Cartridge type MSB + DB $00 ; Number of 8K RAM pages. + else DB NES_CHR_BANKS - DB $00 ; Cartridge type LSB !!! - DB $00 ; Cartridge type MSB !!! + DB $00|NES_NAMETABLE ; Cartridge type LSB + DB $00 ; Cartridge type MSB DB $00 ; Number of 8K RAM pages. + endif DB $00,$00,$00,$00,$00,$00,$00 ; Reserved + if CVBASIC_BANK_SWITCHING + if CVBASIC_BANK_ROM_SIZE-512 + FORG $3c010 + ORG $c000 + else + FORG $7c010 + ORG $c000 + endif + else FORG $0010 ORG $8000 + endif PPUCTRL: EQU $2000 PPUMASK: EQU $2001 @@ -133,6 +155,24 @@ WRTVRM: .1: JMP wait +LDIRVM4: + JSR LDIRVM2 + JSR LDIRVM2 + JSR LDIRVM2 + JSR LDIRVM2 + RTS + +LDIRVM2: + JSR LDIRVM + LDA pointer + CLC + ADC temp2 + STA pointer + BCC .1 + INC pointer+1 +.1: + RTS + LDIRVM: LDX ppu_pointer LDA pointer @@ -141,15 +181,19 @@ LDIRVM: STA PPUBUF+1,X LDA temp2 STA PPUBUF+2,X - LDA temp,X + LDA temp STA PPUBUF+3,X - LDA temp+1,X + LDA temp+1 STA PPUBUF+4,X TXA CLC ADC #5 STA ppu_pointer + CMP #$40 + BCS .1 RTS +.1: + JMP wait ENASCR: LDA ppu_mask @@ -217,8 +261,13 @@ cls: .1: PHA LDX ppu_pointer - LDA #$20 - STA PPUBUF+3,X + CMP #$8F + BNE .2 + LDA #$00 + BEQ .3 + +.2: LDA #$20 +.3: STA PPUBUF+3,X LDA #$40 STA PPUBUF+2,X LDA #$00 @@ -582,6 +631,10 @@ nmi_handler: TYA PHA + if CVBASIC_BANK_SWITCHING + LDA $BFFF + PHA + endif LDA PPUSTATUS ; VDP interruption clear. STA vdp_status @@ -785,6 +838,11 @@ nmi_handler: PLA STA temp+0 + if CVBASIC_BANK_SWITCHING + PLA + ORA CHRRAM_BANK + STA BANKSEL + endif PLA TAY PLA @@ -1048,6 +1106,10 @@ music_play: LDY music_pointer+1 STA music_start STY music_start+1 + if CVBASIC_BANK_SWITCHING + LDA $BFFF + STA music_bank + endif CLI RTS @@ -1064,6 +1126,11 @@ music_generate: BEQ .1 JMP .2 .1: + if CVBASIC_BANK_SWITCHING + LDA music_bank + ORA CHRRAM_BANK + STA BANKSEL + endif LDY #0 LDA (music_pointer),Y CMP #$fe ; End of music? @@ -1445,6 +1512,32 @@ music_silence: db -2 endif + + IF CVBASIC_BANK_SWITCHING +copy_chrram: + LDA #$00 + STA PPUADDR + STA PPUADDR + STA temp + STX temp+1 + LDX #32 +.1: + JSR copy_page + DEX + BNE .1 + RTS + +copy_page: + LDY #0 +.1: + LDA (temp),Y + STA PPUDATA + INY + BNE .1 + INC temp+1 + RTS + ENDIF + START: SEI CLD @@ -1523,6 +1616,32 @@ START: STA ntsc ; About 57165 cycles passed at this time. + IF CVBASIC_BANK_SWITCHING + ; Copy CHRROM to CHRRAM + LDA #$1D + STA $C000 + LDX #$80 + JSR copy_chrram + + LDA #$3D + STA $C000 + LDX #$A0 + JSR copy_chrram + + LDA #$1E + STA $C000 + LDX #$80 + JSR copy_chrram + + LDA #$3E + STA $C000 + LDX #$A0 + JSR copy_chrram + + LDA #$00 ; BANK SELECT 1 + STA $C000 + ENDIF + ; Clear 2K of pattern memory LDA #$20 STA PPUADDR diff --git a/examples/bank_nes.bas b/examples/bank_nes.bas new file mode 100644 index 0000000..cfbba0a --- /dev/null +++ b/examples/bank_nes.bas @@ -0,0 +1,1287 @@ + rem + rem Bank-switching example for NES/Famicom + rem by Oscar Toledo G. http://nanochess.org + rem Aug/26/2025 + rem + + BANK ROM 256 ' Select a 256KB target ROM size. + ' Now it is in bank 0. + + PLAY FULL + BANK SELECT 1 ' Select bank 1 to access. + PLAY tune_1 + + ' Display image. + PALETTE 0,$0F + PALETTE 1,$16 + PALETTE 2,$27 + PALETTE 3,$38 + WAIT + SCREEN DISABLE + SCREEN image_pattern,0,0,12,16,12 + WAIT + SCREEN ENABLE + + BANK SELECT 2 ' Select bank 2 to access. + + GOSUB display_some_text + + WHILE 1: WEND + + BANK 1 ' Start of bank 1 data + + ' Bach Invention 8 (BWV779) + ' Fragment +tune_1: DATA BYTE 7 + MUSIC F4,- + MUSIC S,- + MUSIC A4,- + MUSIC S,- + MUSIC F4,- + MUSIC S,- + MUSIC C5,- + MUSIC S,- + MUSIC F4,- + MUSIC S,- + + MUSIC F5,- + MUSIC S,- + MUSIC E5,F3 + MUSIC D5,S + MUSIC C5,A3 + MUSIC D5,S + MUSIC C5,F3 + MUSIC A4#,S + MUSIC A4,C4 + MUSIC A4#,S + MUSIC A4,F3 + MUSIC G4,S + + MUSIC F4,F4 + MUSIC S,S + MUSIC A4,E4 + MUSIC S,D4 + MUSIC C5,C4 + MUSIC S,D4 + MUSIC A4,C4 + MUSIC S,A3# + MUSIC F5,A3 + MUSIC S,A3# + MUSIC C5,A3 + MUSIC S,G3 + + MUSIC A5,F3 + MUSIC C6,S + MUSIC A5#,A3 + MUSIC C6,S + MUSIC A5,C4 + MUSIC C6,S + MUSIC A5#,A3 + MUSIC C6,S + MUSIC A5,F4 + MUSIC C6,S + MUSIC A5#,C4 + MUSIC C6,S + + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + + MUSIC B4,D3 + MUSIC S,F3 + MUSIC G4,E3 + MUSIC S,F3 + MUSIC D5,D3 + MUSIC S,F3 + MUSIC B4,E3 + MUSIC S,F3 + MUSIC F5,D3 + MUSIC S,F3 + MUSIC D5,E3 + MUSIC S,F3 + + MUSIC G5,B3 + MUSIC A5,S + MUSIC G5,G3 + MUSIC F5,S + MUSIC E5,C4 + MUSIC F5,S + MUSIC E5,G3 + MUSIC D5,S + MUSIC C5,E4 + MUSIC D5,S + MUSIC C5,C4 + MUSIC A4#,S + + MUSIC A4,F4 + MUSIC S,G4 + MUSIC D5,F4 + MUSIC C5,E4 + MUSIC B4,D4 + MUSIC C5,E4 + MUSIC B4,D4 + MUSIC A4,C4 + MUSIC G4,B3 + MUSIC A4,C4 + MUSIC G4,B3 + MUSIC F4,A3 + + MUSIC E4,G3 + MUSIC F4,S + MUSIC E4,C4 + MUSIC D4,B3 + MUSIC C4,A3 + MUSIC S,B3 + MUSIC C5,A3 + MUSIC B4,G3 + MUSIC C5,F3 + MUSIC S,G3 + MUSIC E4,F3 + MUSIC S,E3 + + MUSIC F4,D3 + MUSIC S,E3 + MUSIC C5,D3 + MUSIC S,C3 + MUSIC E4,G3 + MUSIC S,F3 + MUSIC C5,E3 + MUSIC S,F3 + MUSIC D4,G3 + MUSIC S,S + MUSIC B4,G2 + MUSIC S,S + + MUSIC C5,C4 + MUSIC S,S + MUSIC S,S + MUSIC S,S + MUSIC STOP + + BANK 2 + +display_some_text: PROCEDURE + + PRINT AT $0210,"Hi!" + + PRINT AT $0250,"This is bank-" + + PRINT AT $0270,"switching demo." + + PRINT AT $02B0,":)" + + END + + ' CHRROM is technically outside of the ROM, but for + ' the purposes of UNROM 512 bank-switching it is saved + ' in reserved banks and copied to CHRRAM on boot. + + ' TMSColor 3.2 Aug/26/2025 + ' Command: ./tmscolor -nes -p1 -t128 -b yo.png yo.bas + ' Created: Tue Aug 26 10:07:21 2025 + + ' Start tile = 128. Total_tiles = 118 + CHRROM 0 PATTERN 128 + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "12222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222233" + BITMAP "22223333" + BITMAP "22333333" + + BITMAP "22222223" + BITMAP "22222333" + BITMAP "23223333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22233333" + BITMAP "22333333" + + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + + BITMAP "22333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22223333" + BITMAP "22233333" + BITMAP "22233333" + BITMAP "22333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333322" + BITMAP "33332222" + BITMAP "33322211" + BITMAP "33222111" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33323333" + BITMAP "22222222" + BITMAP "11111111" + BITMAP "11100111" + BITMAP "11111111" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "22333333" + BITMAP "11112333" + BITMAP "11111223" + + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22223333" + BITMAP "22233333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333332" + BITMAP "33333332" + BITMAP "33333322" + BITMAP "33333322" + + BITMAP "33221111" + BITMAP "32211111" + BITMAP "22211111" + BITMAP "22111111" + BITMAP "21111111" + BITMAP "21111112" + BITMAP "11112222" + BITMAP "11122222" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "22222221" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "11111112" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "22111111" + BITMAP "22221111" + + BITMAP "22333333" + BITMAP "11122333" + BITMAP "11000233" + BITMAP "11100023" + BITMAP "11100001" + BITMAP "11100000" + BITMAP "11100000" + BITMAP "11110000" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "13333333" + BITMAP "01333333" + BITMAP "00233333" + + BITMAP "22233333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "23333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333321" + BITMAP "33333321" + BITMAP "33333321" + BITMAP "33333212" + BITMAP "33333212" + BITMAP "33333222" + BITMAP "33333222" + BITMAP "33333222" + + BITMAP "11222222" + BITMAP "12222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22221111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222211" + BITMAP "22222221" + BITMAP "22222221" + BITMAP "22222221" + BITMAP "22222221" + + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111100" + + BITMAP "00033333" + BITMAP "00023333" + BITMAP "00003333" + BITMAP "00002333" + BITMAP "00002333" + BITMAP "00001333" + BITMAP "00000333" + BITMAP "00000233" + + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222223" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222333" + + BITMAP "33332122" + BITMAP "33332122" + BITMAP "33332122" + BITMAP "33332222" + BITMAP "33333122" + BITMAP "33333122" + BITMAP "33332111" + BITMAP "33332111" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222232" + BITMAP "22232233" + BITMAP "22222222" + BITMAP "11122222" + BITMAP "11112222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22233333" + BITMAP "22233222" + BITMAP "22222111" + BITMAP "22221110" + BITMAP "22221112" + + BITMAP "22222221" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "32222111" + BITMAP "22221111" + BITMAP "01111111" + BITMAP "11222211" + BITMAP "33333222" + + BITMAP "11111100" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11110000" + BITMAP "11110001" + + BITMAP "00000233" + BITMAP "00000232" + BITMAP "00000132" + BITMAP "00000122" + BITMAP "01110122" + BITMAP "11000112" + BITMAP "00001111" + BITMAP "00001122" + + BITMAP "33333333" + BITMAP "22233333" + BITMAP "22222233" + BITMAP "22222223" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "23333333" + BITMAP "23333333" + + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22223333" + + BITMAP "33332111" + BITMAP "33222122" + BITMAP "32321222" + BITMAP "32101211" + BITMAP "10233110" + BITMAP "12333111" + BITMAP "33333112" + BITMAP "33233122" + + BITMAP "11111122" + BITMAP "22222112" + BITMAP "22212111" + BITMAP "11110111" + BITMAP "22000111" + BITMAP "22111101" + BITMAP "22222211" + BITMAP "22222212" + + BITMAP "22211222" + BITMAP "22211221" + BITMAP "22111211" + BITMAP "22111121" + BITMAP "22111122" + BITMAP "22111122" + BITMAP "22211122" + BITMAP "22211122" + + BITMAP "33332112" + BITMAP "12231001" + BITMAP "23110110" + BITMAP "22211221" + BITMAP "21222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "20011111" + BITMAP "11111111" + BITMAP "11222111" + BITMAP "11222111" + BITMAP "21222211" + BITMAP "21222211" + BITMAP "21222211" + BITMAP "12222111" + + BITMAP "10000222" + BITMAP "10001221" + BITMAP "10000221" + BITMAP "10001121" + BITMAP "11001121" + BITMAP "11111121" + BITMAP "11111121" + BITMAP "11101111" + + BITMAP "23333333" + BITMAP "23333333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "22233333" + BITMAP "22233333" + BITMAP "22223333" + + BITMAP "22223333" + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22223333" + + BITMAP "33232122" + BITMAP "33322122" + BITMAP "33332122" + BITMAP "33333211" + BITMAP "33333222" + BITMAP "33333322" + BITMAP "33333322" + BITMAP "33333322" + + BITMAP "22222112" + BITMAP "22222122" + BITMAP "22221122" + BITMAP "12122222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22221112" + BITMAP "22211111" + BITMAP "22211112" + BITMAP "22211111" + BITMAP "22211111" + BITMAP "22221211" + BITMAP "32222221" + BITMAP "22111111" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222232" + BITMAP "22223332" + BITMAP "12222332" + BITMAP "12222222" + BITMAP "12222222" + BITMAP "22222222" + + BITMAP "12222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22221111" + BITMAP "22221111" + + BITMAP "11101211" + BITMAP "11112222" + BITMAP "11111112" + BITMAP "11111222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222223" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "22333333" + + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222333" + + BITMAP "33333332" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22222222" + BITMAP "22222212" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "32222222" + BITMAP "32222111" + BITMAP "33222211" + BITMAP "33222222" + + BITMAP "22112222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222211" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22111222" + BITMAP "11112222" + BITMAP "11222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22221211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222111" + + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11101222" + + BITMAP "22233333" + BITMAP "22223333" + BITMAP "22222233" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "22333333" + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222233" + + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + + BITMAP "33322222" + BITMAP "33322222" + BITMAP "33332222" + BITMAP "33332122" + BITMAP "33333222" + BITMAP "33333212" + BITMAP "33333322" + BITMAP "33333332" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222112" + BITMAP "22221112" + BITMAP "22211111" + BITMAP "22211111" + + BITMAP "22222111" + BITMAP "22221111" + BITMAP "22211111" + BITMAP "22111111" + BITMAP "21111111" + BITMAP "11111112" + BITMAP "11211132" + BITMAP "11112321" + + BITMAP "11001222" + BITMAP "11001222" + BITMAP "10101222" + BITMAP "11102212" + BITMAP "21112112" + BITMAP "11022022" + BITMAP "01132022" + BITMAP "10231132" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "12222222" + BITMAP "00122222" + + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222233" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333321" + BITMAP "33333100" + BITMAP "33321010" + + BITMAP "33333332" + BITMAP "33333211" + BITMAP "33321002" + BITMAP "32100112" + BITMAP "20011122" + BITMAP "00111123" + BITMAP "10110232" + BITMAP "01111322" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22111111" + BITMAP "22111111" + BITMAP "22122222" + BITMAP "22112222" + BITMAP "21012222" + BITMAP "21012222" + + BITMAP "22111111" + BITMAP "21111111" + BITMAP "11111222" + BITMAP "12222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222233" + + BITMAP "11223311" + BITMAP "22223201" + BITMAP "22232110" + BITMAP "22331102" + BITMAP "23321113" + BITMAP "33211023" + BITMAP "33110233" + BITMAP "32011332" + + BITMAP "02320231" + BITMAP "13311320" + BITMAP "23202310" + BITMAP "33013201" + BITMAP "31033101" + BITMAP "20232010" + BITMAP "11331010" + BITMAP "02320110" + + BITMAP "00012222" + BITMAP "00012222" + BITMAP "00000112" + BITMAP "00000001" + BITMAP "00000000" + BITMAP "11000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "12222222" + BITMAP "01222222" + BITMAP "00122222" + BITMAP "00012222" + BITMAP "00000112" + + BITMAP "22222223" + BITMAP "22222223" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333331" + BITMAP "33333210" + BITMAP "23333111" + BITMAP "22232111" + BITMAP "22331110" + + BITMAP "33200100" + BITMAP "32011001" + BITMAP "10110011" + BITMAP "01110011" + BITMAP "11100111" + BITMAP "11101110" + BITMAP "01011111" + BITMAP "11111101" + + BITMAP "11102322" + BITMAP "11112322" + BITMAP "01123322" + BITMAP "11123222" + BITMAP "11132222" + BITMAP "21022222" + BITMAP "21122222" + BITMAP "20022122" + + BITMAP "21012222" + BITMAP "21012222" + BITMAP "21011222" + BITMAP "21011222" + BITMAP "21011222" + BITMAP "11011222" + BITMAP "22011222" + BITMAP "22101232" + + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22233332" + BITMAP "22333331" + BITMAP "23333311" + BITMAP "22223211" + BITMAP "22222110" + BITMAP "22221112" + + BITMAP "21102320" + BITMAP "11023310" + BITMAP "01133202" + BITMAP "10232013" + BITMAP "02331023" + BITMAP "13320233" + BITMAP "23301331" + BITMAP "33102320" + + BITMAP "13201001" + BITMAP "33101000" + BITMAP "32011000" + BITMAP "31010000" + BITMAP "20100010" + BITMAP "01100110" + BITMAP "01000000" + BITMAP "11001100" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "00000001" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "22222222" + BITMAP "01222222" + BITMAP "00122222" + BITMAP "00012222" + BITMAP "00001222" + BITMAP "00000122" + BITMAP "00000112" + BITMAP "00000000" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "11222222" + + BITMAP "22321110" + BITMAP "22321100" + BITMAP "22321100" + BITMAP "22311100" + BITMAP "23311101" + BITMAP "23310101" + BITMAP "23310111" + BITMAP "23320111" + + BITMAP "10111102" + BITMAP "01111112" + BITMAP "11111112" + BITMAP "11111112" + BITMAP "11111022" + BITMAP "11111121" + BITMAP "11111121" + BITMAP "11111111" + + BITMAP "20023112" + BITMAP "10013212" + BITMAP "10001222" + BITMAP "00001222" + BITMAP "00001222" + BITMAP "00001222" + BITMAP "00012223" + BITMAP "00012233" + + BITMAP "22201322" + BITMAP "22201322" + BITMAP "22222223" + BITMAP "22222333" + BITMAP "22222332" + BITMAP "32222322" + BITMAP "33212221" + BITMAP "33202101" + + BITMAP "22221113" + BITMAP "22211023" + BITMAP "22111233" + BITMAP "21111332" + BITMAP "11103331" + BITMAP "11023310" + BITMAP "10233201" + BITMAP "02332013" + + BITMAP "32013310" + BITMAP "31133201" + BITMAP "20233011" + BITMAP "01331011" + BITMAP "03320111" + BITMAP "23311110" + BITMAP "33211000" + BITMAP "32111111" + + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11110000" + BITMAP "11000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000001" + BITMAP "00000001" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "11000000" + BITMAP "11000000" + BITMAP "11100000" + BITMAP "11100000" + + BITMAP "00012222" + BITMAP "00000122" + BITMAP "00000002" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "23310111" + BITMAP "23301111" + BITMAP "23201111" + BITMAP "23111111" + BITMAP "22111111" + BITMAP "22011111" + BITMAP "21111111" + BITMAP "21111111" + + BITMAP "11111111" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "11011100" + BITMAP "11011100" + BITMAP "10011100" + + BITMAP "00012333" + BITMAP "00123333" + BITMAP "00123333" + BITMAP "01223333" + BITMAP "01223333" + BITMAP "01233333" + BITMAP "12233333" + BITMAP "12333332" + + BITMAP "33201110" + BITMAP "33201102" + BITMAP "33111123" + BITMAP "32111122" + BITMAP "21111100" + BITMAP "21111011" + BITMAP "11123201" + BITMAP "11133311" + + BITMAP "23331122" + BITMAP "33201110" + BITMAP "32111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "10111111" + BITMAP "11111111" + BITMAP "11101111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "10000001" + BITMAP "11100001" + BITMAP "11111001" + BITMAP "11111001" + BITMAP "11111001" + BITMAP "11111011" + BITMAP "11110011" + BITMAP "11100011" + + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111100" + BITMAP "11111100" + + BITMAP "00000000" + BITMAP "00000001" + BITMAP "00000012" + BITMAP "00000222" + BITMAP "00002322" + BITMAP "00013332" + BITMAP "00023333" + BITMAP "00133333" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222221" + BITMAP "22222221" + BITMAP "22222210" + BITMAP "22222211" + + BITMAP "21111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111110" + BITMAP "11111110" + + BITMAP "10111001" + BITMAP "11111001" + BITMAP "11111012" + BITMAP "11110012" + BITMAP "11110122" + BITMAP "11110122" + BITMAP "11101222" + BITMAP "11001123" + + BITMAP "23333222" + BITMAP "23332232" + BITMAP "23223331" + BITMAP "32233321" + BITMAP "22333321" + BITMAP "23333321" + BITMAP "33332211" + BITMAP "33332211" + + BITMAP "11133311" + BITMAP "11112101" + BITMAP "11110111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11110111" + BITMAP "11100111" + BITMAP "11101111" + BITMAP "11001111" + BITMAP "10011111" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "11100011" + BITMAP "11000111" + BITMAP "11000111" + BITMAP "11000111" + BITMAP "11000111" + BITMAP "11001111" + BITMAP "10001111" + BITMAP "10001111" + + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "10000000" + BITMAP "10000000" + BITMAP "10000000" + BITMAP "11000000" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00100000" + BITMAP "00100001" + BITMAP "00101102" + + BITMAP "00233333" + BITMAP "01333323" + BITMAP "02333323" + BITMAP "13333223" + BITMAP "23333223" + BITMAP "23333223" + BITMAP "33332233" + BITMAP "33332233" + + + ' Width = 12, height = 16 +image_pattern: + DATA BYTE $80,$81,$81,$81,$82,$83,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$81,$81,$85,$86,$84,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$81,$87,$88,$84,$84,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$81,$89,$8a,$8b,$8c,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$8d,$8e,$8f,$90,$91,$92,$93,$84,$84,$84,$84 + DATA BYTE $81,$94,$95,$96,$81,$97,$98,$99,$84,$84,$84,$84 + DATA BYTE $9a,$84,$9b,$9c,$9d,$9e,$9f,$a0,$a1,$a2,$84,$84 + DATA BYTE $a3,$84,$a4,$a5,$a6,$a7,$a8,$a9,$81,$aa,$84,$84 + DATA BYTE $ab,$84,$ac,$ad,$ae,$af,$b0,$b1,$81,$b2,$b3,$84 + DATA BYTE $b4,$84,$b5,$b6,$b7,$b8,$b9,$ba,$81,$81,$bb,$bc + DATA BYTE $bd,$84,$84,$be,$81,$bf,$c0,$c1,$c2,$81,$81,$81 + DATA BYTE $c3,$84,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$81,$81 + DATA BYTE $cc,$cd,$ce,$cf,$d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7 + DATA BYTE $81,$d8,$d9,$da,$db,$dc,$dd,$de,$df,$d4,$d4,$e0 + DATA BYTE $81,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$d4,$d4,$e9 + DATA BYTE $ea,$eb,$ec,$ed,$ee,$ef,$f0,$f1,$f2,$f3,$f4,$f5 diff --git a/examples/demo_nes.bas b/examples/demo_nes.bas new file mode 100644 index 0000000..565b4b9 --- /dev/null +++ b/examples/demo_nes.bas @@ -0,0 +1,707 @@ + ' + ' Demo of graphics for CVBasic + ' + ' by Oscar Toledo G. + ' + ' Creation date: Mar/08/2024. + ' Revision date: Aug/06/2024. Added endless loop. + ' Revision date: Aug/26/2025. Adapted for NES. + ' + + DIM x(32),y(32),col(32),col2(32) + + PALETTE LOAD demo_palette + + WHILE 1 + + CLS + + SCREEN portrait_pattern,0,260,8,8,8 + + GOSUB small_wait + + RESTORE message_1 + + GOSUB show_message + + GOSUB small_wait + + FOR c = 0 TO 7 + WAIT + WAIT + #c = 260 + c * 32 + SCREEN spaces,0,#c,8,1 + SCREEN portrait_pattern,0,#c+32,8,8,8 + NEXT c + + FOR c = 0 TO 7 + WAIT + WAIT + #c = 516 + c + SCREEN spaces,0,#c,1,8,1 + SCREEN portrait_pattern,0,#c+1,8,8,8 + NEXT c + + RESTORE message_2 + + GOSUB show_message + + GOSUB small_wait + + FOR c = 0 TO 144 + WAIT + SPRITE 0,$A0,c,$01,0 + SPRITE 1,$A0,c+8,$03,0 + NEXT c + + RESTORE message_3 + + GOSUB show_message + + GOSUB small_wait + + FOR c = 0 TO 31 + x(c) = RANDOM(176) + y(c) = RANDOM(240) + col(c) = c % 3 * 4 + col2(c) = (c / 3) % 4 + SPRITE c * 2,y(c),x(c),col(c) + 1,col2(c) + SPRITE c * 2 + 1,y(c),x(c) + 8,col(c) + 3,col2(c) + NEXT c + + FOR c = 0 TO 240 + WAIT + FOR d = 0 TO 15 + SPRITE d * 2,y(d),x(d),col(d) + 1,col2(d) + SPRITE d * 2 + 1,y(d),x(d) + 8,col(d) + 3,col2(d) + y(d) = y(d) + 1 + IF y(d) = $c0 THEN y(d) = $f1 + NEXT d + FOR d = 16 TO 31 + SPRITE d * 2,y(d),x(d),col(d) + 1,col2(d) + SPRITE d * 2 + 1,y(d),x(d) + 8,col(d) + 3,col2(d) + x(d) = x(d) + 1 + IF x(d) = $ff THEN x(d) = $00 + NEXT d + NEXT c + + FOR c = 0 TO 63 + SPRITE c,$f0,0,0,0 + NEXT c + + RESTORE message_4 + + GOSUB show_message + + GOSUB small_wait + + WEND + +demo_palette: + DATA BYTE $0F,$26,$27,$30 + DATA BYTE $0F,$26,$27,$30 + DATA BYTE $0F,$26,$27,$30 + DATA BYTE $0F,$26,$27,$30 + DATA BYTE $0F,$21,$22,$23 + DATA BYTE $0F,$24,$25,$26 + DATA BYTE $0F,$27,$28,$29 + DATA BYTE $0F,$2A,$2B,$2C + +spaces: + DATA BYTE $20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00 + +small_wait: PROCEDURE + FOR c = 0 TO 60 + WAIT + NEXT c + END + +show_message: PROCEDURE + + ' + ' Erase area. + ' + FOR #position = $210e TO $21ee STEP 32 + FOR #c = 0 TO $11 + VPOKE #position + #c, 32 + NEXT #c + NEXT #position + + ' + ' Draw message. + ' + #position = $2000 + 270 + DO + READ BYTE d + IF d = $0D THEN + #position = ((#position + 32) AND $FFe0) + $000e + ELSEIF d <> 0 THEN + VPOKE #position, d + #position = #position + 1 + END IF + WAIT + LOOP WHILE d + + END + +message_1: + DATA BYTE "Hi! This is a",$0d + DATA BYTE "CVBasic demo",$0d + DATA BYTE "program.",$00 + +message_2: + DATA BYTE "You can displace",$0d + DATA BYTE "graphics moving",$0d + DATA BYTE "tiles on the",$0d + DATA BYTE "screen instead of",$0d + DATA BYTE "graphic data.",$00 + +message_3: + DATA BYTE "Sprites can",$0d + DATA BYTE "overlay",$0d + DATA BYTE "background",$0d + DATA BYTE "graphics.",$00 + +message_4: + DATA BYTE "I hope you",$0d + DATA BYTE "enjoyed the",$0d + DATA BYTE "demo.",$00 + + CHRROM 0 PATTERN 256 + + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + BITMAP "1111111111111111" + + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + BITMAP "2222222222222222" + + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + BITMAP "3333333333333333" + + ' TMSColor 3.2 Aug/26/2025 + ' Command: ../tmscolor/tmscolor -nes -t128 -b portrait_nes.png portrait_nes.bas + ' Created: Tue Aug 26 10:55:48 2025 + + ' Start tile = 128. Total_tiles = 52 + CHRROM 0 PATTERN 128 + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000111" + BITMAP "00111111" + BITMAP "11111111" + BITMAP "11111110" + BITMAP "11001100" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "11100000" + BITMAP "11100000" + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11111000" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000002" + BITMAP "00000022" + BITMAP "00000222" + BITMAP "00002222" + BITMAP "00022222" + + BITMAP "00222222" + BITMAP "02222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "00000000" + BITMAP "20000000" + BITMAP "22200000" + BITMAP "22220000" + BITMAP "22222000" + BITMAP "22222200" + BITMAP "22222220" + BITMAP "22222220" + + BITMAP "11101110" + BITMAP "11101110" + BITMAP "00000000" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "00000000" + BITMAP "11101110" + BITMAP "11101110" + + BITMAP "10011111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11000000" + BITMAP "10011111" + BITMAP "11111111" + BITMAP "11111110" + BITMAP "11001000" + + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + + BITMAP "00222222" + BITMAP "00222222" + BITMAP "02222222" + BITMAP "02222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22322222" + + BITMAP "22222220" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "20000000" + BITMAP "20000000" + BITMAP "20000000" + BITMAP "20000000" + BITMAP "22000000" + + BITMAP "00000000" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "00000000" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "00000000" + BITMAP "11101110" + + BITMAP "11010111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "11110000" + BITMAP "11000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333332" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "32223222" + BITMAP "32233222" + BITMAP "32233322" + BITMAP "21000000" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "21010222" + BITMAP "10101222" + + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + + BITMAP "11101110" + BITMAP "00000000" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "00000000" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "00000000" + + BITMAP "00000000" + BITMAP "00011111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11110001" + BITMAP "10001111" + BITMAP "11111111" + + BITMAP "00000000" + BITMAP "11110000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + + BITMAP "32200000" + BITMAP "22211111" + BITMAP "22211111" + BITMAP "22211111" + BITMAP "22211111" + BITMAP "22211111" + BITMAP "22221111" + BITMAP "22221111" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "01111111" + BITMAP "01111111" + BITMAP "01111111" + BITMAP "01111111" + BITMAP "01111111" + BITMAP "00111111" + + BITMAP "11010222" + BITMAP "10101222" + BITMAP "11010222" + BITMAP "11101222" + BITMAP "11010222" + BITMAP "11101222" + BITMAP "11010222" + BITMAP "11101222" + + BITMAP "11111101" + BITMAP "10000001" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11000000" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11100000" + BITMAP "10000000" + + BITMAP "22222111" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222221" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "32222222" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "00000111" + BITMAP "00000111" + BITMAP "10001111" + BITMAP "11111100" + BITMAP "21111100" + BITMAP "22111100" + + BITMAP "11010222" + BITMAP "11101222" + BITMAP "11010222" + BITMAP "10100222" + BITMAP "11000222" + BITMAP "01001223" + BITMAP "00010223" + BITMAP "01101233" + + BITMAP "11111100" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + + BITMAP "22111111" + BITMAP "22200000" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22221211" + BITMAP "00000011" + BITMAP "02020211" + + BITMAP "01010233" + BITMAP "10101233" + BITMAP "01010233" + BITMAP "10101233" + BITMAP "11010232" + BITMAP "11101232" + BITMAP "11111232" + BITMAP "11111232" + + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22000000" + BITMAP "22200000" + BITMAP "22200000" + BITMAP "22200000" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000003" + BITMAP "00003333" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000030" + BITMAP "00003333" + BITMAP "00333333" + BITMAP "03333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222222" + BITMAP "32222220" + BITMAP "32222220" + BITMAP "32222223" + BITMAP "32222233" + BITMAP "32222233" + + BITMAP "00202011" + BITMAP "20020201" + BITMAP "20202000" + BITMAP "02020233" + BITMAP "20202033" + BITMAP "02020233" + BITMAP "20202033" + BITMAP "02020232" + + BITMAP "11111232" + BITMAP "11111222" + BITMAP "11111222" + BITMAP "11111222" + BITMAP "00000222" + BITMAP "02020222" + BITMAP "20200222" + BITMAP "02020222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22333333" + + BITMAP "22200000" + BITMAP "22333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "33300000" + BITMAP "33333000" + BITMAP "33333300" + BITMAP "33333330" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "30303030" + BITMAP "03030303" + BITMAP "30303030" + BITMAP "03030303" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "03333333" + BITMAP "30333333" + BITMAP "03333333" + BITMAP "33333333" + BITMAP "03333333" + + BITMAP "32222233" + BITMAP "33222233" + BITMAP "33333330" + BITMAP "33333332" + BITMAP "30303030" + BITMAP "03030302" + BITMAP "30303020" + BITMAP "03030202" + + BITMAP "20202320" + BITMAP "02020202" + BITMAP "20202020" + BITMAP "02020202" + BITMAP "20202020" + BITMAP "02020202" + BITMAP "20202023" + BITMAP "02020233" + + BITMAP "20202022" + BITMAP "02020022" + BITMAP "20203333" + BITMAP "02033333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333303" + BITMAP "33333030" + BITMAP "33030303" + BITMAP "30303030" + BITMAP "03030303" + + BITMAP "33333033" + BITMAP "33030303" + BITMAP "30303030" + BITMAP "03030303" + BITMAP "30303030" + BITMAP "03030303" + BITMAP "30303030" + BITMAP "03030303" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "03333333" + BITMAP "30333333" + BITMAP "03033333" + BITMAP "30303333" + BITMAP "03033333" + + + ' Width = 8, height = 8 +portrait_pattern: + DATA BYTE $80,$81,$82,$83,$84,$85,$86,$86 + DATA BYTE $87,$88,$89,$84,$84,$8a,$8b,$8c + DATA BYTE $8d,$8e,$8f,$90,$91,$84,$92,$93 + DATA BYTE $94,$95,$96,$97,$98,$84,$92,$86 + DATA BYTE $99,$9a,$9b,$9c,$9d,$84,$92,$8c + DATA BYTE $9e,$9f,$a0,$a1,$a2,$84,$a3,$93 + DATA BYTE $a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab + DATA BYTE $ac,$ad,$ae,$af,$b0,$b1,$b2,$b3 diff --git a/examples/hello.bas b/examples/hello.bas deleted file mode 100644 index 35287ec..0000000 --- a/examples/hello.bas +++ /dev/null @@ -1,15 +0,0 @@ - ' - ' Hello World! - ' - ' by Oscar Toledo G. - ' - ' Creation date: Jul/19/2025. - ' - - FOR #c = $0000 TO $0210 STEP $21 - - PRINT AT #c,"Hello world!" - - NEXT #c - - WHILE 1: WEND diff --git a/examples/oscar_nes.bas b/examples/oscar_nes.bas new file mode 100644 index 0000000..ecff48d --- /dev/null +++ b/examples/oscar_nes.bas @@ -0,0 +1,1099 @@ + ' TMSColor 3.2 Aug/26/2025 + ' Command: ./tmscolor -nes -p1 -t128 -b oscar.png oscar.bas + ' Created: Tue Aug 26 10:07:21 2025 + + ' Display image. + PALETTE 0,$0F + PALETTE 1,$16 + PALETTE 2,$27 + PALETTE 3,$38 + WAIT + SCREEN DISABLE + SCREEN image_pattern,0,$00ea,12,16,12 + WAIT + SCREEN ENABLE + WHILE 1: WEND + + ' Start tile = 128. Total_tiles = 118 + CHRROM 0 PATTERN 128 + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "12222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222233" + BITMAP "22223333" + BITMAP "22333333" + + BITMAP "22222223" + BITMAP "22222333" + BITMAP "23223333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22233333" + BITMAP "22333333" + + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + + BITMAP "22333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22223333" + BITMAP "22233333" + BITMAP "22233333" + BITMAP "22333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333322" + BITMAP "33332222" + BITMAP "33322211" + BITMAP "33222111" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33323333" + BITMAP "22222222" + BITMAP "11111111" + BITMAP "11100111" + BITMAP "11111111" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "22333333" + BITMAP "11112333" + BITMAP "11111223" + + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22223333" + BITMAP "22233333" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333332" + BITMAP "33333332" + BITMAP "33333322" + BITMAP "33333322" + + BITMAP "33221111" + BITMAP "32211111" + BITMAP "22211111" + BITMAP "22111111" + BITMAP "21111111" + BITMAP "21111112" + BITMAP "11112222" + BITMAP "11122222" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "22222221" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "11111112" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "22111111" + BITMAP "22221111" + + BITMAP "22333333" + BITMAP "11122333" + BITMAP "11000233" + BITMAP "11100023" + BITMAP "11100001" + BITMAP "11100000" + BITMAP "11100000" + BITMAP "11110000" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "13333333" + BITMAP "01333333" + BITMAP "00233333" + + BITMAP "22233333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "23333333" + BITMAP "23333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "33333321" + BITMAP "33333321" + BITMAP "33333321" + BITMAP "33333212" + BITMAP "33333212" + BITMAP "33333222" + BITMAP "33333222" + BITMAP "33333222" + + BITMAP "11222222" + BITMAP "12222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22221111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222211" + BITMAP "22222221" + BITMAP "22222221" + BITMAP "22222221" + BITMAP "22222221" + + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111100" + + BITMAP "00033333" + BITMAP "00023333" + BITMAP "00003333" + BITMAP "00002333" + BITMAP "00002333" + BITMAP "00001333" + BITMAP "00000333" + BITMAP "00000233" + + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222223" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222333" + + BITMAP "33332122" + BITMAP "33332122" + BITMAP "33332122" + BITMAP "33332222" + BITMAP "33333122" + BITMAP "33333122" + BITMAP "33332111" + BITMAP "33332111" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222232" + BITMAP "22232233" + BITMAP "22222222" + BITMAP "11122222" + BITMAP "11112222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22233333" + BITMAP "22233222" + BITMAP "22222111" + BITMAP "22221110" + BITMAP "22221112" + + BITMAP "22222221" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "32222111" + BITMAP "22221111" + BITMAP "01111111" + BITMAP "11222211" + BITMAP "33333222" + + BITMAP "11111100" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11110000" + BITMAP "11110001" + + BITMAP "00000233" + BITMAP "00000232" + BITMAP "00000132" + BITMAP "00000122" + BITMAP "01110122" + BITMAP "11000112" + BITMAP "00001111" + BITMAP "00001122" + + BITMAP "33333333" + BITMAP "22233333" + BITMAP "22222233" + BITMAP "22222223" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "23333333" + BITMAP "23333333" + + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22223333" + + BITMAP "33332111" + BITMAP "33222122" + BITMAP "32321222" + BITMAP "32101211" + BITMAP "10233110" + BITMAP "12333111" + BITMAP "33333112" + BITMAP "33233122" + + BITMAP "11111122" + BITMAP "22222112" + BITMAP "22212111" + BITMAP "11110111" + BITMAP "22000111" + BITMAP "22111101" + BITMAP "22222211" + BITMAP "22222212" + + BITMAP "22211222" + BITMAP "22211221" + BITMAP "22111211" + BITMAP "22111121" + BITMAP "22111122" + BITMAP "22111122" + BITMAP "22211122" + BITMAP "22211122" + + BITMAP "33332112" + BITMAP "12231001" + BITMAP "23110110" + BITMAP "22211221" + BITMAP "21222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "20011111" + BITMAP "11111111" + BITMAP "11222111" + BITMAP "11222111" + BITMAP "21222211" + BITMAP "21222211" + BITMAP "21222211" + BITMAP "12222111" + + BITMAP "10000222" + BITMAP "10001221" + BITMAP "10000221" + BITMAP "10001121" + BITMAP "11001121" + BITMAP "11111121" + BITMAP "11111121" + BITMAP "11101111" + + BITMAP "23333333" + BITMAP "23333333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "22333333" + BITMAP "22233333" + BITMAP "22233333" + BITMAP "22223333" + + BITMAP "22223333" + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22223333" + + BITMAP "33232122" + BITMAP "33322122" + BITMAP "33332122" + BITMAP "33333211" + BITMAP "33333222" + BITMAP "33333322" + BITMAP "33333322" + BITMAP "33333322" + + BITMAP "22222112" + BITMAP "22222122" + BITMAP "22221122" + BITMAP "12122222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22221112" + BITMAP "22211111" + BITMAP "22211112" + BITMAP "22211111" + BITMAP "22211111" + BITMAP "22221211" + BITMAP "32222221" + BITMAP "22111111" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222232" + BITMAP "22223332" + BITMAP "12222332" + BITMAP "12222222" + BITMAP "12222222" + BITMAP "22222222" + + BITMAP "12222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22222111" + BITMAP "22221111" + BITMAP "22221111" + + BITMAP "11101211" + BITMAP "11112222" + BITMAP "11111112" + BITMAP "11111222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222223" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "22333333" + + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222333" + + BITMAP "33333332" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + BITMAP "22222222" + BITMAP "22222212" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "32222222" + BITMAP "32222111" + BITMAP "33222211" + BITMAP "33222222" + + BITMAP "22112222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222211" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11222222" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22111222" + BITMAP "11112222" + BITMAP "11222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "22221211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222211" + BITMAP "22222111" + + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11112222" + BITMAP "11101222" + + BITMAP "22233333" + BITMAP "22223333" + BITMAP "22222233" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "22333333" + BITMAP "22223333" + BITMAP "22222333" + BITMAP "22222233" + + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222333" + BITMAP "22222233" + + BITMAP "33322222" + BITMAP "33322222" + BITMAP "33332222" + BITMAP "33332122" + BITMAP "33333222" + BITMAP "33333212" + BITMAP "33333322" + BITMAP "33333332" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222112" + BITMAP "22221112" + BITMAP "22211111" + BITMAP "22211111" + + BITMAP "22222111" + BITMAP "22221111" + BITMAP "22211111" + BITMAP "22111111" + BITMAP "21111111" + BITMAP "11111112" + BITMAP "11211132" + BITMAP "11112321" + + BITMAP "11001222" + BITMAP "11001222" + BITMAP "10101222" + BITMAP "11102212" + BITMAP "21112112" + BITMAP "11022022" + BITMAP "01132022" + BITMAP "10231132" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "12222222" + BITMAP "00122222" + + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222333" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222233" + BITMAP "22222233" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333321" + BITMAP "33333100" + BITMAP "33321010" + + BITMAP "33333332" + BITMAP "33333211" + BITMAP "33321002" + BITMAP "32100112" + BITMAP "20011122" + BITMAP "00111123" + BITMAP "10110232" + BITMAP "01111322" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22111111" + BITMAP "22111111" + BITMAP "22122222" + BITMAP "22112222" + BITMAP "21012222" + BITMAP "21012222" + + BITMAP "22111111" + BITMAP "21111111" + BITMAP "11111222" + BITMAP "12222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222223" + BITMAP "22222233" + + BITMAP "11223311" + BITMAP "22223201" + BITMAP "22232110" + BITMAP "22331102" + BITMAP "23321113" + BITMAP "33211023" + BITMAP "33110233" + BITMAP "32011332" + + BITMAP "02320231" + BITMAP "13311320" + BITMAP "23202310" + BITMAP "33013201" + BITMAP "31033101" + BITMAP "20232010" + BITMAP "11331010" + BITMAP "02320110" + + BITMAP "00012222" + BITMAP "00012222" + BITMAP "00000112" + BITMAP "00000001" + BITMAP "00000000" + BITMAP "11000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "12222222" + BITMAP "01222222" + BITMAP "00122222" + BITMAP "00012222" + BITMAP "00000112" + + BITMAP "22222223" + BITMAP "22222223" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333331" + BITMAP "33333210" + BITMAP "23333111" + BITMAP "22232111" + BITMAP "22331110" + + BITMAP "33200100" + BITMAP "32011001" + BITMAP "10110011" + BITMAP "01110011" + BITMAP "11100111" + BITMAP "11101110" + BITMAP "01011111" + BITMAP "11111101" + + BITMAP "11102322" + BITMAP "11112322" + BITMAP "01123322" + BITMAP "11123222" + BITMAP "11132222" + BITMAP "21022222" + BITMAP "21122222" + BITMAP "20022122" + + BITMAP "21012222" + BITMAP "21012222" + BITMAP "21011222" + BITMAP "21011222" + BITMAP "21011222" + BITMAP "11011222" + BITMAP "22011222" + BITMAP "22101232" + + BITMAP "22222333" + BITMAP "22223333" + BITMAP "22233332" + BITMAP "22333331" + BITMAP "23333311" + BITMAP "22223211" + BITMAP "22222110" + BITMAP "22221112" + + BITMAP "21102320" + BITMAP "11023310" + BITMAP "01133202" + BITMAP "10232013" + BITMAP "02331023" + BITMAP "13320233" + BITMAP "23301331" + BITMAP "33102320" + + BITMAP "13201001" + BITMAP "33101000" + BITMAP "32011000" + BITMAP "31010000" + BITMAP "20100010" + BITMAP "01100110" + BITMAP "01000000" + BITMAP "11001100" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "00000001" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "22222222" + BITMAP "01222222" + BITMAP "00122222" + BITMAP "00012222" + BITMAP "00001222" + BITMAP "00000122" + BITMAP "00000112" + BITMAP "00000000" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "11222222" + + BITMAP "22321110" + BITMAP "22321100" + BITMAP "22321100" + BITMAP "22311100" + BITMAP "23311101" + BITMAP "23310101" + BITMAP "23310111" + BITMAP "23320111" + + BITMAP "10111102" + BITMAP "01111112" + BITMAP "11111112" + BITMAP "11111112" + BITMAP "11111022" + BITMAP "11111121" + BITMAP "11111121" + BITMAP "11111111" + + BITMAP "20023112" + BITMAP "10013212" + BITMAP "10001222" + BITMAP "00001222" + BITMAP "00001222" + BITMAP "00001222" + BITMAP "00012223" + BITMAP "00012233" + + BITMAP "22201322" + BITMAP "22201322" + BITMAP "22222223" + BITMAP "22222333" + BITMAP "22222332" + BITMAP "32222322" + BITMAP "33212221" + BITMAP "33202101" + + BITMAP "22221113" + BITMAP "22211023" + BITMAP "22111233" + BITMAP "21111332" + BITMAP "11103331" + BITMAP "11023310" + BITMAP "10233201" + BITMAP "02332013" + + BITMAP "32013310" + BITMAP "31133201" + BITMAP "20233011" + BITMAP "01331011" + BITMAP "03320111" + BITMAP "23311110" + BITMAP "33211000" + BITMAP "32111111" + + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11110000" + BITMAP "11000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000001" + BITMAP "00000001" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "11000000" + BITMAP "11000000" + BITMAP "11100000" + BITMAP "11100000" + + BITMAP "00012222" + BITMAP "00000122" + BITMAP "00000002" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + + BITMAP "23310111" + BITMAP "23301111" + BITMAP "23201111" + BITMAP "23111111" + BITMAP "22111111" + BITMAP "22011111" + BITMAP "21111111" + BITMAP "21111111" + + BITMAP "11111111" + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11101110" + BITMAP "11101110" + BITMAP "11011100" + BITMAP "11011100" + BITMAP "10011100" + + BITMAP "00012333" + BITMAP "00123333" + BITMAP "00123333" + BITMAP "01223333" + BITMAP "01223333" + BITMAP "01233333" + BITMAP "12233333" + BITMAP "12333332" + + BITMAP "33201110" + BITMAP "33201102" + BITMAP "33111123" + BITMAP "32111122" + BITMAP "21111100" + BITMAP "21111011" + BITMAP "11123201" + BITMAP "11133311" + + BITMAP "23331122" + BITMAP "33201110" + BITMAP "32111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "10111111" + BITMAP "11111111" + BITMAP "11101111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "10000001" + BITMAP "11100001" + BITMAP "11111001" + BITMAP "11111001" + BITMAP "11111001" + BITMAP "11111011" + BITMAP "11110011" + BITMAP "11100011" + + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11110000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111000" + BITMAP "11111100" + BITMAP "11111100" + + BITMAP "00000000" + BITMAP "00000001" + BITMAP "00000012" + BITMAP "00000222" + BITMAP "00002322" + BITMAP "00013332" + BITMAP "00023333" + BITMAP "00133333" + + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222221" + BITMAP "22222221" + BITMAP "22222210" + BITMAP "22222211" + + BITMAP "21111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111110" + BITMAP "11111110" + + BITMAP "10111001" + BITMAP "11111001" + BITMAP "11111012" + BITMAP "11110012" + BITMAP "11110122" + BITMAP "11110122" + BITMAP "11101222" + BITMAP "11001123" + + BITMAP "23333222" + BITMAP "23332232" + BITMAP "23223331" + BITMAP "32233321" + BITMAP "22333321" + BITMAP "23333321" + BITMAP "33332211" + BITMAP "33332211" + + BITMAP "11133311" + BITMAP "11112101" + BITMAP "11110111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11110111" + BITMAP "11100111" + BITMAP "11101111" + BITMAP "11001111" + BITMAP "10011111" + + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "11100011" + BITMAP "11000111" + BITMAP "11000111" + BITMAP "11000111" + BITMAP "11000111" + BITMAP "11001111" + BITMAP "10001111" + BITMAP "10001111" + + BITMAP "11111110" + BITMAP "11111110" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "10000000" + BITMAP "10000000" + BITMAP "10000000" + BITMAP "11000000" + + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00000000" + BITMAP "00100000" + BITMAP "00100001" + BITMAP "00101102" + + BITMAP "00233333" + BITMAP "01333323" + BITMAP "02333323" + BITMAP "13333223" + BITMAP "23333223" + BITMAP "23333223" + BITMAP "33332233" + BITMAP "33332233" + + + ' Width = 12, height = 16 +image_pattern: + DATA BYTE $80,$81,$81,$81,$82,$83,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$81,$81,$85,$86,$84,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$81,$87,$88,$84,$84,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$81,$89,$8a,$8b,$8c,$84,$84,$84,$84,$84,$84 + DATA BYTE $81,$8d,$8e,$8f,$90,$91,$92,$93,$84,$84,$84,$84 + DATA BYTE $81,$94,$95,$96,$81,$97,$98,$99,$84,$84,$84,$84 + DATA BYTE $9a,$84,$9b,$9c,$9d,$9e,$9f,$a0,$a1,$a2,$84,$84 + DATA BYTE $a3,$84,$a4,$a5,$a6,$a7,$a8,$a9,$81,$aa,$84,$84 + DATA BYTE $ab,$84,$ac,$ad,$ae,$af,$b0,$b1,$81,$b2,$b3,$84 + DATA BYTE $b4,$84,$b5,$b6,$b7,$b8,$b9,$ba,$81,$81,$bb,$bc + DATA BYTE $bd,$84,$84,$be,$81,$bf,$c0,$c1,$c2,$81,$81,$81 + DATA BYTE $c3,$84,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$81,$81 + DATA BYTE $cc,$cd,$ce,$cf,$d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7 + DATA BYTE $81,$d8,$d9,$da,$db,$dc,$dd,$de,$df,$d4,$d4,$e0 + DATA BYTE $81,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$d4,$d4,$e9 + DATA BYTE $ea,$eb,$ec,$ed,$ee,$ef,$f0,$f1,$f2,$f3,$f4,$f5 diff --git a/manual.txt b/manual.txt index 7460436..257fb27 100644 --- a/manual.txt +++ b/manual.txt @@ -22,7 +22,7 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.0 Aug/25/2025 o Added support for NES/Famicom using --nes +v0.9.0 Aug/26/2025 o Added support for NES/Famicom using --nes o MSX: Added support for Konami mapper using -konami o Solved bug in DEF FN precedence inside expressions. o Solved bug in > operator with 16-bit variable. @@ -903,8 +903,26 @@ The following statements are available: 20-23 palette 1 for sprites 24-27 palette 2 for sprites 28-31 palette 3 for sprites - - For the palette colors see https://www.nesdev.org/wiki/PPU_palettes#2C02 + + The value for each entry is in the range of 0-63 (the lower 4 bits choose + the color, and bits 5-4 choose the luminance). The black color is any of + the values $0e, $0f, $1e, $1f, $2e, $2f, $3e, or $3f. Don't use the value + $0d as it generates a blacker than black signal that may cause unstable + picture. + + Color table: + + 0= White. 8= Lemon + 1= Dark blue. 9= Grass + 2= Blue. A= Green + 3= Magenta. B= Pear + 4= Purple. C= Turquoise + 5= Wine. D= Gray + 6= Red. E= Black + 7= Golden. F= Black + + For a reference of the palette colors see + https://www.nesdev.org/wiki/PPU_palettes#2C02 When you update the full palette the 32 bytes are written into the palette memory, and because how the NES/Famicom palette memory is implemented, @@ -1007,14 +1025,32 @@ The following statements are available: bit 3 - Uses sprite palette if set. bit 4 - The tile will be drawn on top of sprites. + NAMETABLE number + + For NES/Famicom it selects the type of nametable arrangement. This is an + informative field for emulators. + + 0 - Vertical scrolling (CIRAM A10 = PPU A11) + 1 - Horizontal scrolling (CIRAM A10 = PPU A10) + 2 - Single-screen board (only with bank-switching) + 3 - 4-screen board (only with bank-switching) + + CHRRAM number + + For NES/Famicom bank-switching mode it allows to select the CHRRAM bank (0-3) + + The bit 2 (value 4) allows to select the PPU screen mirroring (0 for vertical + scrolling, 1 for horizontal scrolling) See the UNROM 512 documentation. CHRROM number + CHRROM number PATTERN number CHRROM PATTERN number For NES/Famicom the graphic data are saved into CHRROM banks of 8K. You should specify the CHRROM bank before putting any BITMAP statement. - Currently only CHRROM 0 is supported. + Currently only CHRROM 0 is supported for 32K ROM, and 0-3 for bank-switching + ROM (UNROM 512) CVBasic will predefine an ASCII charset with color 3 in the patterns 32-127. @@ -1214,8 +1250,8 @@ The following statements are available: BANK ROM 1024 This statement allows you to use 128K-1024K cartridges for your program - (Opcode's Megacart for the Colecovision, ASCII 16K mapper for MSX, and - SMS Sega Mapper for SG1000). + (Opcode's Megacart for the Colecovision, ASCII 16K mapper for MSX, SMS + Sega Mapper for SG1000, and UNROM 512 for NES/Famicom). It should be the very first statement in your program. 128 allows for 8 banks, 256 allows for 16 banks, 512 allows for 32 banks, and 1024 allows @@ -1227,6 +1263,10 @@ The following statements are available: In bank 0 you should have global procedures and data that are shared by all your banks. + Note for NES/Famicom, you cannot refer to the top three banks (banks 13-15 + for 256K, and banks 29-31 for 512K) as these are used to save the CHRROM + data. + BANK 1-63 Select the bank for the following code/data of your program. Each bank can @@ -1286,7 +1326,7 @@ The expression parser will take advantage of 8-bit variables and numbers to opti an expression. A=VPEEK(expr) Reads a VRAM memory location VPEEK always reads 8-bit data that can be processed in - an expression. + an expression. Not supported for NES/Famicom. A=ABS(expr) Gets the absolute value of the expression (non-negative) A=SGN(expr) Gets sign of expression (-1, 0 or 1) A=array(expr) Accesses an array. The array can be defined with DIM or From 5d6bf964ec123f83bd5b26d60c146b4a80ce72bd Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 12:41:31 -0600 Subject: [PATCH 078/155] NES corrections for real hardware --- cvbasic.c | 20 ++++++++------------ cvbasic_nes_prologue.asm | 37 +++++++++++++++++++++---------------- examples/brinquitos_nes.bas | 4 ++-- examples/oscar_nes.bas | 5 +++-- manual.txt | 6 +++++- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 8a55ad8..c699c59 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -4933,24 +4933,20 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "HL", temp); generic_call("palette_load"); } else if (machine == NES) { - cpu6502_1op("LDX", "ppu_pointer"); - cpu6502_1op("LDA", "#$00"); - cpu6502_1op("STA", "PPUBUF,X"); - cpu6502_1op("LDA", "#$3f"); - cpu6502_1op("STA", "PPUBUF+1,X"); + cpu6502_1op("LDA", "#0"); + cpu6502_1op("STA", "pointer"); + cpu6502_1op("LDA", "#63"); + cpu6502_1op("STA", "pointer+1"); cpu6502_1op("LDA", "#32"); - cpu6502_1op("STA", "PPUBUF+2,X"); + cpu6502_1op("STA", "temp2"); strcpy(temp, "#" LABEL_PREFIX); strcat(temp, name); cpu6502_1op("LDA", temp); - cpu6502_1op("STA", "PPUBUF+3,X"); + cpu6502_1op("STA", "temp"); strcat(temp, ">>8"); cpu6502_1op("LDA", temp); - cpu6502_1op("STA", "PPUBUF+4,X"); - cpu6502_noop("TXA"); - cpu6502_noop("CLC"); - cpu6502_1op("ADC", "#5"); - cpu6502_1op("STA", "ppu_pointer"); + cpu6502_1op("STA", "temp+1"); + cpu6502_1op("JSR", "LDIRVM"); } get_lex(); } diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 61e7ca9..e04b0e4 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -179,11 +179,16 @@ LDIRVM: STA PPUBUF,X LDA pointer+1 STA PPUBUF+1,X - LDA temp2 + LDA #0 + SEC + SBC temp2 STA PPUBUF+2,X LDA temp + SEC + SBC PPUBUF+2,X STA PPUBUF+3,X LDA temp+1 + SBC #0 STA PPUBUF+4,X TXA CLC @@ -635,9 +640,6 @@ nmi_handler: LDA $BFFF PHA endif - LDA PPUSTATUS ; VDP interruption clear. - STA vdp_status - ; Load sprites LDA mode AND #4 ; Flicker enabled? @@ -662,30 +664,25 @@ nmi_handler: INX LDA PPUBUF,X INX - STA PPUADDR + STA PPUADDR ; High-byte of VRAM address. ROL A - STY PPUADDR - BCS .2 - BMI .7 - + STY PPUADDR ; Low-byte of VRAM address. + BCS .2 ; Fill routine. + BMI .7 ; Single byte routine. + ; Copy routine. LDA PPUBUF+1,X STA ppu_source LDA PPUBUF+2,X STA ppu_source+1 - LDA PPUBUF,X + LDY PPUBUF,X ; Negative counter. INX INX INX - STX ppu_temp - TAX - LDY #0 .4: LDA (ppu_source),Y STA PPUDATA INY - DEX BNE .4 - LDX ppu_temp CPX ppu_pointer BNE .0 JMP .11 @@ -740,6 +737,9 @@ nmi_handler: LDA ppu_mask STA PPUMASK + LDA PPUSTATUS ; VDP interruption clear. + STA vdp_status + ; Read controllers LDA #$01 STA CONT1 @@ -940,11 +940,16 @@ print_string: AND #$07 ORA #$20 STA PPUBUF+1,X - LDA temp2 + LDA #0 + SEC + SBC temp2 STA PPUBUF+2,X LDA temp + SEC + SBC PPUBUF+2,X STA PPUBUF+3,X LDA temp+1 + SBC #0 STA PPUBUF+4,X TXA CLC diff --git a/examples/brinquitos_nes.bas b/examples/brinquitos_nes.bas index 35fe684..6d009c3 100644 --- a/examples/brinquitos_nes.bas +++ b/examples/brinquitos_nes.bas @@ -73,11 +73,11 @@ main_loop: ' IF jump_state >= 33 THEN ' Jumping f = 4 - SOUND 12, $0800 + y + SOUND 12, $0800 + y, 64 SOUND 15, 15 ELSEIF jump_state THEN ' Falling f = 8 - SOUND 12, $0800 + y + SOUND 12, $0800 + y, 64 SOUND 15, 15 ELSE ' Standing f = 0 diff --git a/examples/oscar_nes.bas b/examples/oscar_nes.bas index ecff48d..2149b4c 100644 --- a/examples/oscar_nes.bas +++ b/examples/oscar_nes.bas @@ -7,10 +7,11 @@ PALETTE 1,$16 PALETTE 2,$27 PALETTE 3,$38 - WAIT SCREEN DISABLE + WAIT ' Make sure the screen is disabled + ' so a big update can happen. SCREEN image_pattern,0,$00ea,12,16,12 - WAIT + WAIT ' Make sure all the data is processed. SCREEN ENABLE WHILE 1: WEND diff --git a/manual.txt b/manual.txt index bb36b49..0ec7336 100644 --- a/manual.txt +++ b/manual.txt @@ -729,7 +729,8 @@ The following statements are available: until frequency value becomes zero. As SOUND 12 doesn't have a volume register, you should turn it on using - SOUND 15, 15, and turn it off using SOUND 15, 11. + SOUND 15, 15, and turn it off using SOUND 15, 11. Also the linear counter + should have a non-zero value. Don't update the frequency if it is the same, or otherwise the output phase will reset and generate glitches in the audio output. @@ -980,6 +981,9 @@ The following statements are available: screen (can be set up using the BORDER statement). The video can be enabled again with SCREEN ENABLE or using a MODE statement. + For NES/Famicom add a WAIT statement after this one because the operation + is executed on the next video frame. + SCREEN ENABLE Enables the video output (preserves the previous video mode set by MODE). From 2af853ad5c81a61f60c1658f85264f1b87546996 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 14:41:27 -0600 Subject: [PATCH 079/155] NES bank-switching now works in real hardware --- bank.lst | 4620 ++++++++++++++++++++++++++++++++++++++ cvbasic.c | 4 +- cvbasic_nes_epilogue.asm | 4 + cvbasic_nes_prologue.asm | 18 +- examples/bank_nes.bas | 17 +- 5 files changed, 4644 insertions(+), 19 deletions(-) create mode 100644 bank.lst diff --git a/bank.lst b/bank.lst new file mode 100644 index 0000000..3686b5b --- /dev/null +++ b/bank.lst @@ -0,0 +1,4620 @@ + 00001 ; CVBasic compiler v0.9.0 Aug/25/2025 + 00002 ; Command: ./cvbasic --nes examples/bank_nes.bas bank.asm + 00003 ; Created: Tue Aug 26 14:39:32 2025 + 00004 + 00005 COLECO: EQU 0 + 00006 SG1000: EQU 0 + 00007 MSX: EQU 0 + 00008 SGM: EQU 0 + 00009 SVI: EQU 0 + 00010 SORD: EQU 0 + 00011 MEMOTECH: EQU 0 + 00012 EINSTEIN: EQU 0 + 00013 CPM: EQU 0 + 00014 PENCIL: EQU 0 + 00015 PV2000: EQU 0 + 00016 TI99: EQU 0 + 00017 NABU: EQU 0 + 00018 SMS: EQU 0 + 00019 NES_PRG_BANKS: EQU 16 ; Each one 16K. + 00020 NES_CHR_BANKS: EQU 1 ; Each one 4K. + 00021 NES_NAMETABLE: EQU 0 + 00022 + 00023 CVBASIC_MUSIC_PLAYER: EQU 1 + 00024 CVBASIC_COMPRESSION: EQU 0 + 00025 CVBASIC_BANK_SWITCHING: EQU 1 + 00026 CVBASIC_BANK_ROM_SIZE: EQU 256 + 00027 + 00028 BASE_RAM: EQU $0050 ; Base of RAM + 00029 RAM_SIZE: EQU $0800 ; Base of RAM + 00030 STACK: EQU $01FF ; Base stack pointer + 00031 VDP: EQU $00 ; VDP port (write) + 00032 VDPR: EQU $00 ; VDP port (read) + 00033 PSG: EQU $00 ; PSG port (write) + 00034 + 00035 FORG $00000 + 00036 ; + 00037 ; CVBasic prologue (BASIC compiler, 6502 target) + 00038 ; + 00039 ; by Oscar Toledo G. + 00040 ; https://nanochess.org/ + 00041 ; + 00042 ; Creation date: May/13/2025. + 00043 ; Revision date: Jul/20/2025. Added code to load sprites and read controllers. + 00044 ; Revision date: Aug/23/2025. Support for writing VRAM and PRINT. + 00045 ; Revision date: Aug/24/2025. Support for scrolling, SCREEN, and DISABLE/ENABLE. + 00046 ; Added music player. + 00047 ; Revision date: Aug/25/2025. Added support for 256K and 512K ROM. + 00048 ; Revision date: Aug/26/2025. Added support for CHRRAM selection. + 00049 ; + 00050 + 00051 CPU 6502 + 00052 + 00053 ; + 00054 ; Platforms supported: + 00055 ; o NES/Famicom + 00056 ; + 00057 + 00058 ; + 00059 ; CVBasic variables in zero page. + 00060 ; + 00061 + 00062 PPU_SOURCE: EQU $00 ; Used in NMI for source address for PPU copy + 00063 ; This is a block of 8 bytes that should stay together. + 00064 TEMP: EQU $02 + 00065 TEMP2: EQU $04 + 00066 RESULT: EQU $06 + 00067 POINTER: EQU $08 + 00068 + 00069 READ_POINTER: EQU $0A + 00070 CURSOR: EQU $0C + 00071 MODE: EQU $0E + 00072 NTSC: EQU $0F + 00073 + 00074 VDP_STATUS: EQU $10 + 00075 FLICKER: EQU $11 + 00076 FRAME: EQU $12 + 00077 PPU_POINTER: EQU $14 + 00078 PPU_TEMP: EQU $15 ; Used in NMI to save X + 00079 PPU_CTRL: EQU $16 + 00080 PPU_MASK: EQU $17 + 00081 SCROLL_X: EQU $18 + 00082 SCROLL_Y: EQU $1A + 00083 CHRRAM_BANK: EQU $1C + 00084 CONT_BITS: EQU $1D + 00085 LFSR: EQU $1E + 00086 + 00087 JOY1_DATA: EQU $20 + 00088 JOY2_DATA: EQU $21 + 00089 KEY1_DATA: EQU $22 + 00090 KEY2_DATA: EQU $23 + 00091 SPRITE_DATA: EQU $24 + 00092 + 00093 IF CVBASIC_MUSIC_PLAYER + 00094 MUSIC_PLAYING: EQU $4F + 00095 MUSIC_BANK: EQU $30 + 00096 MUSIC_TIMING: EQU $31 + 00097 MUSIC_START: EQU $32 + 00098 MUSIC_POINTER: EQU $34 + 00099 MUSIC_NOTE_COUNTER: EQU $36 + 00100 MUSIC_INSTRUMENT_1: EQU $37 + 00101 MUSIC_NOTE_1: EQU $38 + 00102 MUSIC_COUNTER_1: EQU $39 + 00103 MUSIC_INSTRUMENT_2: EQU $3A + 00104 MUSIC_NOTE_2: EQU $3B + 00105 MUSIC_COUNTER_2: EQU $3C + 00106 MUSIC_INSTRUMENT_3: EQU $3D + 00107 MUSIC_NOTE_3: EQU $3E + 00108 MUSIC_COUNTER_3: EQU $3F + 00109 MUSIC_DRUM: EQU $40 + 00110 MUSIC_COUNTER_4: EQU $41 + 00111 AUDIO_FREQ1: EQU $42 + 00112 AUDIO_FREQ2: EQU $44 + 00113 AUDIO_FREQ3: EQU $46 + 00114 AUDIO_VOL1: EQU $48 + 00115 AUDIO_VOL2: EQU $49 + 00116 AUDIO_VOL3: EQU $4A + 00117 AUDIO_VOL4HW: EQU $4B + 00118 AUDIO_NOISE: EQU $4C + 00119 MUSIC_TICK: EQU $4D + 00120 MUSIC_MODE: EQU $4E + 00121 ENDIF + 00122 + 00123 SPRITE_PAGE: EQU $02 + 00124 PPUBUF: EQU $0100 + 00125 BANKSEL: EQU $C000 + 00126 + 00127 FORG $0000 + 00128 ; The ORG address doesn't matter here + 00129 ; iNES cartridge header +0000 4E45531A 00130 DB "NES",$1A +0004 10 00131 DB NES_PRG_BANKS +0005 00132 IF CVBASIC_BANK_SWITCHING +0005 00 00133 DB 0 ; It has CHRRAM +0006 E2 00134 DB $E2|NES_NAMETABLE ; Cartridge type LSB +0007 10 00135 DB $10 ; Cartridge type MSB +0008 00 00136 DB $00 ; Number of 8K RAM pages. +0009 00137 ELSE +0009 00138 DB NES_CHR_BANKS +0009 00139 DB $00|NES_NAMETABLE ; Cartridge type LSB +0009 00140 DB $00 ; Cartridge type MSB +0009 00141 DB $00 ; Number of 8K RAM pages. +0009 00142 ENDIF +0009 00000000000000 00143 DB $00,$00,$00,$00,$00,$00,$00 ; Reserved +0010 00144 +0010 00145 IF CVBASIC_BANK_SWITCHING +0010 00146 IF CVBASIC_BANK_ROM_SIZE-512 + 00147 FORG $3C010 +C000 00148 ORG $C000 +C000 00149 ELSE +C000 00150 FORG $7C010 +C000 00151 ORG $C000 +C000 00152 ENDIF +C000 00153 ELSE +C000 00154 FORG $0010 +C000 00155 ORG $8000 +C000 00156 ENDIF +C000 00157 +C000 00158 PPUCTRL: EQU $2000 +C000 00159 PPUMASK: EQU $2001 +C000 00160 PPUSTATUS: EQU $2002 +C000 00161 OAMADDR: EQU $2003 +C000 00162 PPUSCROLL: EQU $2005 +C000 00163 PPUADDR: EQU $2006 +C000 00164 PPUDATA: EQU $2007 +C000 00165 SPRRAM: EQU $4014 +C000 00166 CONT1: EQU $4016 +C000 00167 CONT2: EQU $4017 +C000 00168 +C000 00169 ; +C000 00170 ; NES architecture prevents direct access to VRAM except +C000 00171 ; during the VBLANK. +C000 00172 ; +C000 00173 WRTVRM: +C000 48 00174 PHA +C001 8A 00175 TXA +C002 A614 00176 LDX PPU_POINTER +C004 9D0201 00177 STA PPUBUF+2,X +C007 68 00178 PLA +C008 9D0001 00179 STA PPUBUF,X +C00B 98 00180 TYA +C00C 0940 00181 ORA #$40 +C00E 9D0101 00182 STA PPUBUF+1,X +C011 E8 00183 INX +C012 E8 00184 INX +C013 E8 00185 INX +C014 8614 00186 STX PPU_POINTER +C016 E040 00187 CPX #$40 +C018 B001 00188 BCS .1 +C01A 60 00189 RTS +C01B 00190 .1: +C01B 4C63C4 00191 JMP WAIT +C01E 00192 +C01E 00193 LDIRVM4: +C01E 202BC0 00194 JSR LDIRVM2 +C021 202BC0 00195 JSR LDIRVM2 +C024 202BC0 00196 JSR LDIRVM2 +C027 202BC0 00197 JSR LDIRVM2 +C02A 60 00198 RTS +C02B 00199 +C02B 00200 LDIRVM2: +C02B 203AC0 00201 JSR LDIRVM +C02E A508 00202 LDA POINTER +C030 18 00203 CLC +C031 6504 00204 ADC TEMP2 +C033 8508 00205 STA POINTER +C035 9002 00206 BCC .1 +C037 E609 00207 INC POINTER+1 +C039 00208 .1: +C039 60 00209 RTS +C03A 00210 +C03A 00211 LDIRVM: +C03A A614 00212 LDX PPU_POINTER +C03C A508 00213 LDA POINTER +C03E 9D0001 00214 STA PPUBUF,X +C041 A509 00215 LDA POINTER+1 +C043 9D0101 00216 STA PPUBUF+1,X +C046 A900 00217 LDA #0 +C048 38 00218 SEC +C049 E504 00219 SBC TEMP2 +C04B 9D0201 00220 STA PPUBUF+2,X +C04E A502 00221 LDA TEMP +C050 38 00222 SEC +C051 FD0201 00223 SBC PPUBUF+2,X +C054 9D0301 00224 STA PPUBUF+3,X +C057 A503 00225 LDA TEMP+1 +C059 E900 00226 SBC #0 +C05B 9D0401 00227 STA PPUBUF+4,X +C05E 8A 00228 TXA +C05F 18 00229 CLC +C060 6905 00230 ADC #5 +C062 8514 00231 STA PPU_POINTER +C064 C940 00232 CMP #$40 +C066 B001 00233 BCS .1 +C068 60 00234 RTS +C069 00235 .1: +C069 4C63C4 00236 JMP WAIT +C06C 00237 +C06C 00238 ENASCR: +C06C A517 00239 LDA PPU_MASK +C06E 0918 00240 ORA #$18 +C070 8517 00241 STA PPU_MASK +C072 60 00242 RTS +C073 00243 +C073 00244 DISSCR: +C073 A517 00245 LDA PPU_MASK +C075 29E7 00246 AND #$E7 +C077 8517 00247 STA PPU_MASK +C079 60 00248 RTS +C07A 00249 +C07A 00250 CPYBLK: +C07A 00251 .1: +C07A A504 00252 LDA TEMP2 +C07C 48 00253 PHA +C07D A505 00254 LDA TEMP2+1 +C07F 48 00255 PHA +C080 8A 00256 TXA +C081 48 00257 PHA +C082 98 00258 TYA +C083 48 00259 PHA +C084 A502 00260 LDA TEMP +C086 48 00261 PHA +C087 A503 00262 LDA TEMP+1 +C089 48 00263 PHA +C08A A900 00264 LDA #0 +C08C 8505 00265 STA TEMP2+1 +C08E 203AC0 00266 JSR LDIRVM +C091 68 00267 PLA +C092 8503 00268 STA TEMP+1 +C094 68 00269 PLA +C095 8502 00270 STA TEMP +C097 68 00271 PLA +C098 8505 00272 STA TEMP2+1 +C09A 68 00273 PLA +C09B 8504 00274 STA TEMP2 +C09D A502 00275 LDA TEMP +C09F 18 00276 CLC +C0A0 6504 00277 ADC TEMP2 +C0A2 8502 00278 STA TEMP +C0A4 A503 00279 LDA TEMP+1 +C0A6 6505 00280 ADC TEMP2+1 +C0A8 8503 00281 STA TEMP+1 +C0AA A604 00282 LDX TEMP2 +C0AC A405 00283 LDY TEMP2+1 +C0AE 68 00284 PLA +C0AF 8505 00285 STA TEMP2+1 +C0B1 68 00286 PLA +C0B2 8504 00287 STA TEMP2 +C0B4 A508 00288 LDA POINTER +C0B6 18 00289 CLC +C0B7 6920 00290 ADC #$20 ; !!! Variation for scrolling +C0B9 8508 00291 STA POINTER +C0BB A509 00292 LDA POINTER+1 +C0BD 6900 00293 ADC #$00 +C0BF 8509 00294 STA POINTER+1 +C0C1 C605 00295 DEC TEMP2+1 +C0C3 D0B5 00296 BNE .1 +C0C5 60 00297 RTS +C0C6 00298 +C0C6 00299 CLS: +C0C6 A980 00300 LDA #$80 +C0C8 00301 .1: +C0C8 48 00302 PHA +C0C9 A614 00303 LDX PPU_POINTER +C0CB C98F 00304 CMP #$8F +C0CD D004 00305 BNE .2 +C0CF A900 00306 LDA #$00 +C0D1 F002 00307 BEQ .3 +C0D3 00308 +C0D3 A920 00309 .2: LDA #$20 +C0D5 9D0301 00310 .3: STA PPUBUF+3,X +C0D8 A940 00311 LDA #$40 +C0DA 9D0201 00312 STA PPUBUF+2,X +C0DD A900 00313 LDA #$00 +C0DF 9D0001 00314 STA PPUBUF,X +C0E2 68 00315 PLA +C0E3 9D0101 00316 STA PPUBUF+1,X +C0E6 48 00317 PHA +C0E7 18 00318 CLC +C0E8 7E0101 00319 ROR PPUBUF+1,X +C0EB 7E0001 00320 ROR PPUBUF,X +C0EE 38 00321 SEC +C0EF 7E0101 00322 ROR PPUBUF+1,X +C0F2 7E0001 00323 ROR PPUBUF,X +C0F5 E8 00324 INX +C0F6 E8 00325 INX +C0F7 E8 00326 INX +C0F8 E8 00327 INX +C0F9 8614 00328 STX PPU_POINTER +C0FB 2063C4 00329 JSR WAIT +C0FE 68 00330 PLA +C0FF 18 00331 CLC +C100 6901 00332 ADC #1 +C102 C990 00333 CMP #$90 +C104 D0C2 00334 BNE .1 +C106 60 00335 RTS +C107 00336 +C107 00337 UPDATE_SPRITE: +C107 0A 00338 ASL A +C108 0A 00339 ASL A +C109 8508 00340 STA POINTER +C10B A902 00341 LDA #SPRITE_PAGE +C10D 8509 00342 STA POINTER+1 +C10F A000 00343 LDY #0 +C111 A524 00344 LDA SPRITE_DATA+0 +C113 9108 00345 STA (POINTER),Y +C115 C8 00346 INY +C116 A525 00347 LDA SPRITE_DATA+1 +C118 9108 00348 STA (POINTER),Y +C11A C8 00349 INY +C11B A526 00350 LDA SPRITE_DATA+2 +C11D 9108 00351 STA (POINTER),Y +C11F C8 00352 INY +C120 A527 00353 LDA SPRITE_DATA+3 +C122 9108 00354 STA (POINTER),Y +C124 60 00355 RTS +C125 00356 +C125 00357 _ABS16: +C125 48 00358 PHA +C126 98 00359 TYA +C127 100D 00360 BPL _NEG16.1 +C129 68 00361 PLA +C12A 00362 _NEG16: +C12A 49FF 00363 EOR #$FF +C12C 18 00364 CLC +C12D 6901 00365 ADC #1 +C12F 48 00366 PHA +C130 98 00367 TYA +C131 49FF 00368 EOR #$FF +C133 6900 00369 ADC #0 +C135 A8 00370 TAY +C136 00371 .1: +C136 68 00372 PLA +C137 60 00373 RTS +C138 00374 +C138 00375 _SGN16: +C138 8402 00376 STY TEMP +C13A 0502 00377 ORA TEMP +C13C F00B 00378 BEQ .1 +C13E 98 00379 TYA +C13F 3006 00380 BMI .2 +C141 A900 00381 LDA #0 +C143 A8 00382 TAY +C144 A901 00383 LDA #1 +C146 60 00384 RTS +C147 00385 +C147 A9FF 00386 .2: LDA #$FF +C149 A8 00387 .1: TAY +C14A 60 00388 RTS +C14B 00389 +C14B 00390 _READ16: +C14B 2055C1 00391 JSR _READ8 +C14E 48 00392 PHA +C14F 2055C1 00393 JSR _READ8 +C152 A8 00394 TAY +C153 68 00395 PLA +C154 60 00396 RTS +C155 00397 +C155 00398 _READ8: +C155 A000 00399 LDY #0 +C157 B10A 00400 LDA (READ_POINTER),Y +C159 E60A 00401 INC READ_POINTER +C15B D002 00402 BNE .1 +C15D E60B 00403 INC READ_POINTER+1 +C15F 00404 .1: +C15F 60 00405 RTS +C160 00406 +C160 00407 _PEEK8: +C160 8508 00408 STA POINTER +C162 8409 00409 STY POINTER+1 +C164 A000 00410 LDY #0 +C166 B108 00411 LDA (POINTER),Y +C168 60 00412 RTS +C169 00413 +C169 00414 _PEEK16: +C169 8508 00415 STA POINTER +C16B 8409 00416 STY POINTER+1 +C16D A000 00417 LDY #0 +C16F B108 00418 LDA (POINTER),Y +C171 48 00419 PHA +C172 C8 00420 INY +C173 B108 00421 LDA (POINTER),Y +C175 A8 00422 TAY +C176 68 00423 PLA +C177 60 00424 RTS +C178 00425 +C178 00426 ; temp2 contains left side (dividend) +C178 00427 ; temp contains right side (divisor) +C178 00428 +C178 00429 ; 16-bit multiplication. +C178 00430 _MUL16: +C178 68 00431 PLA +C179 8506 00432 STA RESULT +C17B 68 00433 PLA +C17C 8507 00434 STA RESULT+1 +C17E 68 00435 PLA +C17F 8505 00436 STA TEMP2+1 +C181 68 00437 PLA +C182 8504 00438 STA TEMP2 +C184 A507 00439 LDA RESULT+1 +C186 48 00440 PHA +C187 A506 00441 LDA RESULT +C189 48 00442 PHA +C18A A900 00443 LDA #0 +C18C 8506 00444 STA RESULT +C18E 8507 00445 STA RESULT+1 +C190 A20F 00446 LDX #15 +C192 00447 .1: +C192 4605 00448 LSR TEMP2+1 +C194 6604 00449 ROR TEMP2 +C196 900D 00450 BCC .2 +C198 A506 00451 LDA RESULT +C19A 18 00452 CLC +C19B 6502 00453 ADC TEMP +C19D 8506 00454 STA RESULT +C19F A507 00455 LDA RESULT+1 +C1A1 6503 00456 ADC TEMP+1 +C1A3 8507 00457 STA RESULT+1 +C1A5 0602 00458 .2: ASL TEMP +C1A7 2603 00459 ROL TEMP+1 +C1A9 CA 00460 DEX +C1AA 10E6 00461 BPL .1 +C1AC A506 00462 LDA RESULT +C1AE A407 00463 LDY RESULT+1 +C1B0 60 00464 RTS +C1B1 00465 +C1B1 00466 ; 16-bit signed modulo. +C1B1 00467 _MOD16S: +C1B1 68 00468 PLA +C1B2 8506 00469 STA RESULT +C1B4 68 00470 PLA +C1B5 8507 00471 STA RESULT+1 +C1B7 68 00472 PLA +C1B8 8505 00473 STA TEMP2+1 +C1BA 68 00474 PLA +C1BB 8504 00475 STA TEMP2 +C1BD A507 00476 LDA RESULT+1 +C1BF 48 00477 PHA +C1C0 A506 00478 LDA RESULT +C1C2 48 00479 PHA +C1C3 A405 00480 LDY TEMP2+1 +C1C5 08 00481 PHP +C1C6 1009 00482 BPL .1 +C1C8 A504 00483 LDA TEMP2 +C1CA 202AC1 00484 JSR _NEG16 +C1CD 8504 00485 STA TEMP2 +C1CF 8405 00486 STY TEMP2+1 +C1D1 00487 .1: +C1D1 A403 00488 LDY TEMP+1 +C1D3 1009 00489 BPL .2 +C1D5 A502 00490 LDA TEMP +C1D7 202AC1 00491 JSR _NEG16 +C1DA 8502 00492 STA TEMP +C1DC 8403 00493 STY TEMP+1 +C1DE 00494 .2: +C1DE 207FC2 00495 JSR _MOD16.1 +C1E1 28 00496 PLP +C1E2 1003 00497 BPL .3 +C1E4 4C2AC1 00498 JMP _NEG16 +C1E7 00499 .3: +C1E7 60 00500 RTS +C1E8 00501 +C1E8 00502 ; 16-bit signed division. +C1E8 00503 _DIV16S: +C1E8 68 00504 PLA +C1E9 8506 00505 STA RESULT +C1EB 68 00506 PLA +C1EC 8507 00507 STA RESULT+1 +C1EE 68 00508 PLA +C1EF 8505 00509 STA TEMP2+1 +C1F1 68 00510 PLA +C1F2 8504 00511 STA TEMP2 +C1F4 A507 00512 LDA RESULT+1 +C1F6 48 00513 PHA +C1F7 A506 00514 LDA RESULT +C1F9 48 00515 PHA +C1FA A503 00516 LDA TEMP+1 +C1FC 4505 00517 EOR TEMP2+1 +C1FE 08 00518 PHP +C1FF A405 00519 LDY TEMP2+1 +C201 1009 00520 BPL .1 +C203 A504 00521 LDA TEMP2 +C205 202AC1 00522 JSR _NEG16 +C208 8504 00523 STA TEMP2 +C20A 8405 00524 STY TEMP2+1 +C20C 00525 .1: +C20C A403 00526 LDY TEMP+1 +C20E 1009 00527 BPL .2 +C210 A502 00528 LDA TEMP +C212 202AC1 00529 JSR _NEG16 +C215 8502 00530 STA TEMP +C217 8403 00531 STY TEMP+1 +C219 00532 .2: +C219 2035C2 00533 JSR _DIV16.1 +C21C 28 00534 PLP +C21D 1003 00535 BPL .3 +C21F 4C2AC1 00536 JMP _NEG16 +C222 00537 .3: +C222 60 00538 RTS +C223 00539 +C223 00540 _DIV16: +C223 68 00541 PLA +C224 8506 00542 STA RESULT +C226 68 00543 PLA +C227 8507 00544 STA RESULT+1 +C229 68 00545 PLA +C22A 8505 00546 STA TEMP2+1 +C22C 68 00547 PLA +C22D 8504 00548 STA TEMP2 +C22F A507 00549 LDA RESULT+1 +C231 48 00550 PHA +C232 A506 00551 LDA RESULT +C234 48 00552 PHA +C235 00553 .1: +C235 A900 00554 LDA #0 +C237 8506 00555 STA RESULT +C239 8507 00556 STA RESULT+1 +C23B A20F 00557 LDX #15 +C23D 00558 .2: +C23D 2604 00559 ROL TEMP2 +C23F 2605 00560 ROL TEMP2+1 +C241 2606 00561 ROL RESULT +C243 2607 00562 ROL RESULT+1 +C245 A506 00563 LDA RESULT +C247 38 00564 SEC +C248 E502 00565 SBC TEMP +C24A 8506 00566 STA RESULT +C24C A507 00567 LDA RESULT+1 +C24E E503 00568 SBC TEMP+1 +C250 8507 00569 STA RESULT+1 +C252 B00D 00570 BCS .3 +C254 A506 00571 LDA RESULT +C256 6502 00572 ADC TEMP +C258 8506 00573 STA RESULT +C25A A507 00574 LDA RESULT+1 +C25C 6503 00575 ADC TEMP+1 +C25E 8507 00576 STA RESULT+1 +C260 18 00577 CLC +C261 00578 .3: +C261 CA 00579 DEX +C262 10D9 00580 BPL .2 +C264 2604 00581 ROL TEMP2 +C266 2605 00582 ROL TEMP2+1 +C268 A504 00583 LDA TEMP2 +C26A A405 00584 LDY TEMP2+1 +C26C 60 00585 RTS +C26D 00586 +C26D 00587 _MOD16: +C26D 68 00588 PLA +C26E 8506 00589 STA RESULT +C270 68 00590 PLA +C271 8507 00591 STA RESULT+1 +C273 68 00592 PLA +C274 8505 00593 STA TEMP2+1 +C276 68 00594 PLA +C277 8504 00595 STA TEMP2 +C279 A507 00596 LDA RESULT+1 +C27B 48 00597 PHA +C27C A506 00598 LDA RESULT +C27E 48 00599 PHA +C27F 00600 .1: +C27F A900 00601 LDA #0 +C281 8506 00602 STA RESULT +C283 8507 00603 STA RESULT+1 +C285 A20F 00604 LDX #15 +C287 00605 .2: +C287 2604 00606 ROL TEMP2 +C289 2605 00607 ROL TEMP2+1 +C28B 2606 00608 ROL RESULT +C28D 2607 00609 ROL RESULT+1 +C28F A506 00610 LDA RESULT +C291 38 00611 SEC +C292 E502 00612 SBC TEMP +C294 8506 00613 STA RESULT +C296 A507 00614 LDA RESULT+1 +C298 E503 00615 SBC TEMP+1 +C29A 8507 00616 STA RESULT+1 +C29C B00D 00617 BCS .3 +C29E A506 00618 LDA RESULT +C2A0 6502 00619 ADC TEMP +C2A2 8506 00620 STA RESULT +C2A4 A507 00621 LDA RESULT+1 +C2A6 6503 00622 ADC TEMP+1 +C2A8 8507 00623 STA RESULT+1 +C2AA 18 00624 CLC +C2AB 00625 .3: +C2AB CA 00626 DEX +C2AC 10D9 00627 BPL .2 +C2AE A506 00628 LDA RESULT +C2B0 A407 00629 LDY RESULT+1 +C2B2 60 00630 RTS +C2B3 00631 +C2B3 00632 ; Random number generator. +C2B3 00633 ; From my game Mecha Eight. +C2B3 00634 RANDOM: +C2B3 A51E 00635 LDA LFSR +C2B5 051F 00636 ORA LFSR+1 +C2B7 D008 00637 BNE .0 +C2B9 A911 00638 LDA #$11 +C2BB 851E 00639 STA LFSR +C2BD A978 00640 LDA #$78 +C2BF 851F 00641 STA LFSR+1 +C2C1 A51F 00642 .0: LDA LFSR+1 +C2C3 6A 00643 ROR A +C2C4 6A 00644 ROR A +C2C5 6A 00645 ROR A +C2C6 451F 00646 EOR LFSR+1 +C2C8 8502 00647 STA TEMP +C2CA A51F 00648 LDA LFSR+1 +C2CC 6A 00649 ROR A +C2CD 6A 00650 ROR A +C2CE 4502 00651 EOR TEMP +C2D0 8502 00652 STA TEMP +C2D2 A51E 00653 LDA LFSR +C2D4 0A 00654 ASL A +C2D5 0A 00655 ASL A +C2D6 4502 00656 EOR TEMP +C2D8 2A 00657 ROL A +C2D9 661F 00658 ROR LFSR+1 +C2DB 661E 00659 ROR LFSR +C2DD A51E 00660 LDA LFSR +C2DF A41F 00661 LDY LFSR+1 +C2E1 60 00662 RTS +C2E2 00663 +C2E2 00664 IRQ_HANDLER: +C2E2 40 00665 RTI +C2E3 00666 +C2E3 00667 NMI_HANDLER: +C2E3 48 00668 PHA +C2E4 8A 00669 TXA +C2E5 48 00670 PHA +C2E6 98 00671 TYA +C2E7 48 00672 PHA +C2E8 00673 +C2E8 00674 IF CVBASIC_BANK_SWITCHING +C2E8 ADFFBF 00675 LDA $BFFF +C2EB 48 00676 PHA +C2EC 00677 ENDIF +C2EC 00678 ; Load sprites +C2EC A50E 00679 LDA MODE +C2EE 2904 00680 AND #4 ; Flicker enabled? +C2F0 D00A 00681 BNE .5 ; No, jump. +C2F2 A511 00682 LDA FLICKER +C2F4 18 00683 CLC +C2F5 6920 00684 ADC #32 +C2F7 8511 00685 STA FLICKER +C2F9 4CFEC2 00686 JMP .6 +C2FC 00687 .5: +C2FC A900 00688 LDA #$00 +C2FE 00689 .6: +C2FE 8D0320 00690 STA OAMADDR +C301 A902 00691 LDA #SPRITE_PAGE +C303 8D1440 00692 STA SPRRAM ; Use DMA for sprite loading +C306 00693 +C306 00694 ; Screen changes +C306 A514 00695 LDA PPU_POINTER ; Any change? +C308 F058 00696 BEQ .1 ; No, jump. +C30A A200 00697 LDX #$00 +C30C BC0001 00698 .0: LDY PPUBUF,X +C30F E8 00699 INX +C310 BD0001 00700 LDA PPUBUF,X +C313 E8 00701 INX +C314 8D0620 00702 STA PPUADDR ; High-byte of VRAM address. +C317 2A 00703 ROL A +C318 8C0620 00704 STY PPUADDR ; Low-byte of VRAM address. +C31B B02F 00705 BCS .2 ; Fill routine. +C31D 301F 00706 BMI .7 ; Single byte routine. +C31F 00707 ; Copy routine. +C31F BD0101 00708 LDA PPUBUF+1,X +C322 8500 00709 STA PPU_SOURCE +C324 BD0201 00710 LDA PPUBUF+2,X +C327 8501 00711 STA PPU_SOURCE+1 +C329 BC0001 00712 LDY PPUBUF,X ; Negative counter. +C32C E8 00713 INX +C32D E8 00714 INX +C32E E8 00715 INX +C32F 00716 .4: +C32F B100 00717 LDA (PPU_SOURCE),Y +C331 8D0720 00718 STA PPUDATA +C334 C8 00719 INY +C335 D0F8 00720 BNE .4 +C337 E414 00721 CPX PPU_POINTER +C339 D0D1 00722 BNE .0 +C33B 4C5EC3 00723 JMP .11 +C33E 00724 +C33E 00725 ; Single byte +C33E 00726 .7: +C33E BD0001 00727 LDA PPUBUF,X +C341 E8 00728 INX +C342 8D0720 00729 STA PPUDATA +C345 E414 00730 CPX PPU_POINTER +C347 D0C3 00731 BNE .0 +C349 4C5EC3 00732 JMP .11 +C34C 00733 +C34C 00734 ; Filling data +C34C 00735 .2: +C34C BC0001 00736 LDY PPUBUF,X +C34F E8 00737 INX +C350 BD0001 00738 LDA PPUBUF,X +C353 E8 00739 INX +C354 00740 .3: +C354 8D0720 00741 STA PPUDATA +C357 88 00742 DEY +C358 D0FA 00743 BNE .3 +C35A E414 00744 CPX PPU_POINTER +C35C D0AE 00745 BNE .0 +C35E 00746 +C35E 00747 .11: +C35E A900 00748 LDA #0 +C360 8514 00749 STA PPU_POINTER +C362 00750 .1: +C362 00751 +C362 00752 ; Final settings for PPU +C362 A900 00753 LDA #0 +C364 8D0620 00754 STA PPUADDR +C367 8D0620 00755 STA PPUADDR +C36A A518 00756 LDA SCROLL_X +C36C 8D0520 00757 STA PPUSCROLL +C36F A51A 00758 LDA SCROLL_Y +C371 8D0520 00759 STA PPUSCROLL +C374 A516 00760 LDA PPU_CTRL +C376 4A 00761 LSR A +C377 4A 00762 LSR A +C378 8515 00763 STA PPU_TEMP +C37A A51B 00764 LDA SCROLL_Y+1 +C37C 6A 00765 ROR A +C37D 2615 00766 ROL PPU_TEMP +C37F A519 00767 LDA SCROLL_X+1 +C381 6A 00768 ROR A +C382 2615 00769 ROL PPU_TEMP +C384 A515 00770 LDA PPU_TEMP +C386 8D0020 00771 STA PPUCTRL +C389 A517 00772 LDA PPU_MASK +C38B 8D0120 00773 STA PPUMASK +C38E 00774 +C38E AD0220 00775 LDA PPUSTATUS ; VDP interruption clear. +C391 8510 00776 STA VDP_STATUS +C393 00777 +C393 00778 ; Read controllers +C393 A901 00779 LDA #$01 +C395 8D1640 00780 STA CONT1 +C398 851D 00781 STA CONT_BITS +C39A 4A 00782 LSR A +C39B 8D1640 00783 STA CONT1 +C39E 00784 +C39E AD1640 00785 LDA CONT1 +C3A1 4A 00786 LSR A +C3A2 261D 00787 ROL CONT_BITS +C3A4 90F8 00788 BCC $-6 +C3A6 00789 +C3A6 202EC4 00790 JSR CONVERT_JOYSTICK +C3A9 8520 00791 STA JOY1_DATA +C3AB 8622 00792 STX KEY1_DATA +C3AD 00793 +C3AD A901 00794 LDA #$01 +C3AF 8D1640 00795 STA CONT1 +C3B2 851D 00796 STA CONT_BITS +C3B4 4A 00797 LSR A +C3B5 8D1640 00798 STA CONT1 +C3B8 00799 +C3B8 AD1740 00800 LDA CONT2 +C3BB 4A 00801 LSR A +C3BC 261D 00802 ROL CONT_BITS +C3BE 90F8 00803 BCC $-6 +C3C0 00804 +C3C0 202EC4 00805 JSR CONVERT_JOYSTICK +C3C3 8521 00806 STA JOY2_DATA +C3C5 8623 00807 STX KEY2_DATA +C3C7 00808 +C3C7 00809 IF CVBASIC_MUSIC_PLAYER +C3C7 A54E 00810 LDA MUSIC_MODE +C3C9 F003 00811 BEQ .10 +C3CB 205DC8 00812 JSR MUSIC_HARDWARE +C3CE 00813 .10: +C3CE 00814 ENDIF +C3CE E612 00815 INC FRAME +C3D0 D002 00816 BNE .8 +C3D2 E613 00817 INC FRAME+1 +C3D4 00818 .8: +C3D4 E61E 00819 INC LFSR ; Make LFSR more random +C3D6 E61E 00820 INC LFSR +C3D8 E61E 00821 INC LFSR +C3DA 00822 IF CVBASIC_MUSIC_PLAYER +C3DA A50F 00823 LDA NTSC +C3DC F00D 00824 BEQ .12 +C3DE A64D 00825 LDX MUSIC_TICK +C3E0 E8 00826 INX +C3E1 E006 00827 CPX #6 +C3E3 D002 00828 BNE .14 +C3E5 A200 00829 LDX #0 +C3E7 864D 00830 .14: STX MUSIC_TICK +C3E9 F007 00831 BEQ .9 +C3EB 00832 .12: +C3EB A54E 00833 LDA MUSIC_MODE +C3ED F003 00834 BEQ .9 +C3EF 20CBC5 00835 JSR MUSIC_GENERATE +C3F2 00836 .9: +C3F2 00837 ENDIF +C3F2 00838 ; This is like saving extra registers, because these +C3F2 00839 ; are used by the compiled code, and we don't want +C3F2 00840 ; any reentrancy. +C3F2 A502 00841 LDA TEMP+0 +C3F4 48 00842 PHA +C3F5 A503 00843 LDA TEMP+1 +C3F7 48 00844 PHA +C3F8 A504 00845 LDA TEMP+2 +C3FA 48 00846 PHA +C3FB A505 00847 LDA TEMP+3 +C3FD 48 00848 PHA +C3FE A506 00849 LDA TEMP+4 +C400 48 00850 PHA +C401 A507 00851 LDA TEMP+5 +C403 48 00852 PHA +C404 A508 00853 LDA TEMP+6 +C406 48 00854 PHA +C407 A509 00855 LDA TEMP+7 +C409 48 00856 PHA +C40A 00857 +C40A 68 00858 PLA +C40B 8509 00859 STA TEMP+7 +C40D 68 00860 PLA +C40E 8508 00861 STA TEMP+6 +C410 68 00862 PLA +C411 8507 00863 STA TEMP+5 +C413 68 00864 PLA +C414 8506 00865 STA TEMP+4 +C416 68 00866 PLA +C417 8505 00867 STA TEMP+3 +C419 68 00868 PLA +C41A 8504 00869 STA TEMP+2 +C41C 68 00870 PLA +C41D 8503 00871 STA TEMP+1 +C41F 68 00872 PLA +C420 8502 00873 STA TEMP+0 +C422 00874 +C422 00875 IF CVBASIC_BANK_SWITCHING +C422 68 00876 PLA +C423 051C 00877 ORA CHRRAM_BANK +C425 8D00C0 00878 STA BANKSEL +C428 00879 ENDIF +C428 68 00880 PLA +C429 A8 00881 TAY +C42A 68 00882 PLA +C42B AA 00883 TAX +C42C 68 00884 PLA +C42D 40 00885 RTI +C42E 00886 +C42E 00887 CONVERT_JOYSTICK: +C42E A900 00888 LDA #0 +C430 A20F 00889 LDX #15 +C432 661D 00890 ROR CONT_BITS +C434 9002 00891 BCC $+4 +C436 0902 00892 ORA #2 +C438 661D 00893 ROR CONT_BITS +C43A 9002 00894 BCC $+4 +C43C 0908 00895 ORA #8 +C43E 661D 00896 ROR CONT_BITS +C440 9002 00897 BCC $+4 +C442 0904 00898 ORA #4 +C444 661D 00899 ROR CONT_BITS +C446 9002 00900 BCC $+4 +C448 0901 00901 ORA #1 +C44A 661D 00902 ROR CONT_BITS +C44C 9002 00903 BCC $+4 +C44E A20B 00904 LDX #11 +C450 661D 00905 ROR CONT_BITS +C452 9002 00906 BCC $+4 +C454 A20A 00907 LDX #10 +C456 661D 00908 ROR CONT_BITS +C458 9002 00909 BCC $+4 +C45A 0940 00910 ORA #$40 +C45C 661D 00911 ROR CONT_BITS +C45E 9002 00912 BCC $+4 +C460 0980 00913 ORA #$80 +C462 60 00914 RTS +C463 00915 +C463 00916 WAIT: +C463 A512 00917 LDA FRAME +C465 C512 00918 .1: CMP FRAME +C467 F0FC 00919 BEQ .1 +C469 60 00920 RTS +C46A 00921 +C46A 00922 PRINT_STRING_CURSOR_CONSTANT: +C46A 68 00923 PLA +C46B 8502 00924 STA TEMP +C46D 68 00925 PLA +C46E 8503 00926 STA TEMP+1 +C470 A001 00927 LDY #1 +C472 B102 00928 LDA (TEMP),Y +C474 850C 00929 STA CURSOR +C476 C8 00930 INY +C477 B102 00931 LDA (TEMP),Y +C479 850D 00932 STA CURSOR+1 +C47B C8 00933 INY +C47C B102 00934 LDA (TEMP),Y +C47E 8504 00935 STA TEMP2 +C480 98 00936 TYA +C481 18 00937 CLC +C482 6502 00938 ADC TEMP +C484 8502 00939 STA TEMP +C486 9002 00940 BCC $+4 +C488 E603 00941 INC TEMP+1 +C48A A504 00942 LDA TEMP2 +C48C D016 00943 BNE PRINT_STRING.2 +C48E 00944 +C48E 00945 PRINT_STRING_CURSOR: +C48E 850C 00946 STA CURSOR +C490 840D 00947 STY CURSOR+1 +C492 00948 PRINT_STRING: +C492 68 00949 PLA +C493 8502 00950 STA TEMP +C495 68 00951 PLA +C496 8503 00952 STA TEMP+1 +C498 A001 00953 LDY #1 +C49A B102 00954 LDA (TEMP),Y +C49C 8504 00955 STA TEMP2 +C49E E602 00956 INC TEMP +C4A0 D002 00957 BNE $+4 +C4A2 E603 00958 INC TEMP+1 +C4A4 18 00959 .2: CLC +C4A5 6502 00960 ADC TEMP +C4A7 A8 00961 TAY +C4A8 A900 00962 LDA #0 +C4AA 6503 00963 ADC TEMP+1 +C4AC 48 00964 PHA +C4AD 98 00965 TYA +C4AE 48 00966 PHA +C4AF E602 00967 INC TEMP +C4B1 D002 00968 BNE $+4 +C4B3 E603 00969 INC TEMP+1 +C4B5 A614 00970 LDX PPU_POINTER +C4B7 A50C 00971 LDA CURSOR +C4B9 9D0001 00972 STA PPUBUF,X +C4BC A50D 00973 LDA CURSOR+1 +C4BE 2907 00974 AND #$07 +C4C0 0920 00975 ORA #$20 +C4C2 9D0101 00976 STA PPUBUF+1,X +C4C5 A900 00977 LDA #0 +C4C7 38 00978 SEC +C4C8 E504 00979 SBC TEMP2 +C4CA 9D0201 00980 STA PPUBUF+2,X +C4CD A502 00981 LDA TEMP +C4CF 38 00982 SEC +C4D0 FD0201 00983 SBC PPUBUF+2,X +C4D3 9D0301 00984 STA PPUBUF+3,X +C4D6 A503 00985 LDA TEMP+1 +C4D8 E900 00986 SBC #0 +C4DA 9D0401 00987 STA PPUBUF+4,X +C4DD 8A 00988 TXA +C4DE 18 00989 CLC +C4DF 6905 00990 ADC #5 +C4E1 8514 00991 STA PPU_POINTER +C4E3 A504 00992 LDA TEMP2 +C4E5 18 00993 CLC +C4E6 650C 00994 ADC CURSOR +C4E8 850C 00995 STA CURSOR +C4EA 9002 00996 BCC .1 +C4EC E60D 00997 INC CURSOR+1 +C4EE 00998 .1: +C4EE 60 00999 RTS +C4EF 01000 +C4EF 01001 PRINT_NUMBER: +C4EF A200 01002 LDX #0 +C4F1 8602 01003 STX TEMP +C4F3 78 01004 SEI +C4F4 01005 PRINT_NUMBER5: +C4F4 A210 01006 LDX #10000 +C4F6 8604 01007 STX TEMP2 +C4F8 A227 01008 LDX #10000/256 +C4FA 8605 01009 STX TEMP2+1 +C4FC 202FC5 01010 JSR PRINT_DIGIT +C4FF 01011 PRINT_NUMBER4: +C4FF A2E8 01012 LDX #1000 +C501 8604 01013 STX TEMP2 +C503 A203 01014 LDX #1000/256 +C505 8605 01015 STX TEMP2+1 +C507 202FC5 01016 JSR PRINT_DIGIT +C50A 01017 PRINT_NUMBER3: +C50A A264 01018 LDX #100 +C50C 8604 01019 STX TEMP2 +C50E A200 01020 LDX #0 +C510 8605 01021 STX TEMP2+1 +C512 202FC5 01022 JSR PRINT_DIGIT +C515 01023 PRINT_NUMBER2: +C515 A20A 01024 LDX #10 +C517 8604 01025 STX TEMP2 +C519 A200 01026 LDX #0 +C51B 8605 01027 STX TEMP2+1 +C51D 202FC5 01028 JSR PRINT_DIGIT +C520 01029 PRINT_NUMBER1: +C520 A201 01030 LDX #1 +C522 8604 01031 STX TEMP2 +C524 8602 01032 STX TEMP +C526 A200 01033 LDX #0 +C528 8605 01034 STX TEMP2+1 +C52A 202FC5 01035 JSR PRINT_DIGIT +C52D 58 01036 CLI +C52E 60 01037 RTS +C52F 01038 +C52F 01039 PRINT_DIGIT: +C52F A22F 01040 LDX #$2F +C531 01041 .2: +C531 E8 01042 INX +C532 38 01043 SEC +C533 E504 01044 SBC TEMP2 +C535 48 01045 PHA +C536 98 01046 TYA +C537 E505 01047 SBC TEMP2+1 +C539 A8 01048 TAY +C53A 68 01049 PLA +C53B B0F4 01050 BCS .2 +C53D 18 01051 CLC +C53E 6504 01052 ADC TEMP2 +C540 48 01053 PHA +C541 98 01054 TYA +C542 6505 01055 ADC TEMP2+1 +C544 A8 01056 TAY +C545 68 01057 PLA +C546 E030 01058 CPX #$30 +C548 D00E 01059 BNE .3 +C54A A602 01060 LDX TEMP +C54C D001 01061 BNE .4 +C54E 60 01062 RTS +C54F 01063 +C54F CA 01064 .4: DEX +C550 F004 01065 BEQ .6 +C552 A603 01066 LDX TEMP+1 +C554 D008 01067 BNE PRINT_CHAR +C556 01068 .6: +C556 A230 01069 LDX #$30 +C558 48 01070 .3: PHA +C559 A901 01071 LDA #1 +C55B 8502 01072 STA TEMP +C55D 68 01073 PLA +C55E 01074 +C55E 01075 PRINT_CHAR: +C55E 48 01076 PHA +C55F 98 01077 TYA +C560 48 01078 PHA +C561 A50D 01079 LDA CURSOR+1 +C563 2907 01080 AND #$07 +C565 0920 01081 ORA #$20 +C567 A8 01082 TAY +C568 A50C 01083 LDA CURSOR +C56A 2000C0 01084 JSR WRTVRM +C56D E60C 01085 INC CURSOR +C56F D002 01086 BNE .1 +C571 E60D 01087 INC CURSOR+1 +C573 01088 .1: +C573 68 01089 PLA +C574 A8 01090 TAY +C575 68 01091 PLA +C576 60 01092 RTS +C577 01093 +C577 01094 MODE_0: +C577 20C6C0 01095 JSR CLS +C57A 01096 CLEAR_SPRITES: +C57A A9F0 01097 LDA #$F0 +C57C A200 01098 LDX #0 +C57E 01099 .1: +C57E 9D0002 01100 STA $0200,X +C581 E8 01101 INX +C582 E8 01102 INX +C583 E8 01103 INX +C584 E8 01104 INX +C585 D0F7 01105 BNE .1 +C587 60 01106 RTS +C588 01107 +C588 01108 MUSIC_INIT: +C588 A940 01109 LDA #$40 +C58A 8D1740 01110 STA $4017 +C58D A910 01111 LDA #$10 +C58F 8D0040 01112 STA $4000 ; Channel 1 silent +C592 8D0440 01113 STA $4004 ; Channel 2 silent +C595 8D0C40 01114 STA $400C ; Channel 4 silent +C598 A90B 01115 LDA #$0B +C59A 8D1540 01116 STA $4015 ; Enable channel 1, 2 and 4. +C59D A900 01117 LDA #$00 +C59F 8D1040 01118 STA $4010 +C5A2 01119 IF CVBASIC_MUSIC_PLAYER +C5A2 01120 ELSE +C5A2 01121 RTS +C5A2 01122 ENDIF +C5A2 01123 +C5A2 01124 IF CVBASIC_MUSIC_PLAYER +C5A2 A903 01125 LDA #MUSIC_SILENCE +C5A4 A0C9 01126 LDY #MUSIC_SILENCE>>8 +C5A6 01127 ; +C5A6 01128 ; Play music. +C5A6 01129 ; YA = Pointer to music. +C5A6 01130 ; +C5A6 01131 MUSIC_PLAY: +C5A6 78 01132 SEI +C5A7 8534 01133 STA MUSIC_POINTER +C5A9 8435 01134 STY MUSIC_POINTER+1 +C5AB A000 01135 LDY #0 +C5AD 8436 01136 STY MUSIC_NOTE_COUNTER +C5AF B134 01137 LDA (MUSIC_POINTER),Y +C5B1 8531 01138 STA MUSIC_TIMING +C5B3 C8 01139 INY +C5B4 844F 01140 STY MUSIC_PLAYING +C5B6 E634 01141 INC MUSIC_POINTER +C5B8 D002 01142 BNE $+4 +C5BA E635 01143 INC MUSIC_POINTER+1 +C5BC A534 01144 LDA MUSIC_POINTER +C5BE A435 01145 LDY MUSIC_POINTER+1 +C5C0 8532 01146 STA MUSIC_START +C5C2 8433 01147 STY MUSIC_START+1 +C5C4 01148 IF CVBASIC_BANK_SWITCHING +C5C4 ADFFBF 01149 LDA $BFFF +C5C7 8530 01150 STA MUSIC_BANK +C5C9 01151 ENDIF +C5C9 58 01152 CLI +C5CA 60 01153 RTS +C5CB 01154 +C5CB 01155 ; +C5CB 01156 ; Generates music +C5CB 01157 ; +C5CB 01158 MUSIC_GENERATE: +C5CB A910 01159 LDA #$10 +C5CD 8548 01160 STA AUDIO_VOL1 +C5CF 8549 01161 STA AUDIO_VOL2 +C5D1 854A 01162 STA AUDIO_VOL3 +C5D3 854B 01163 STA AUDIO_VOL4HW +C5D5 A536 01164 LDA MUSIC_NOTE_COUNTER +C5D7 F003 01165 BEQ .1 +C5D9 4C5CC6 01166 JMP .2 +C5DC 01167 .1: +C5DC 01168 IF CVBASIC_BANK_SWITCHING +C5DC A530 01169 LDA MUSIC_BANK +C5DE 051C 01170 ORA CHRRAM_BANK +C5E0 8D00C0 01171 STA BANKSEL +C5E3 01172 ENDIF +C5E3 A000 01173 LDY #0 +C5E5 B134 01174 LDA (MUSIC_POINTER),Y +C5E7 C9FE 01175 CMP #$FE ; End of music? +C5E9 D005 01176 BNE .3 ; No, jump. +C5EB A900 01177 LDA #0 ; Keep at same place. +C5ED 854F 01178 STA MUSIC_PLAYING +C5EF 60 01179 RTS +C5F0 01180 +C5F0 C9FD 01181 .3: CMP #$FD ; Repeat music? +C5F2 D00B 01182 BNE .4 +C5F4 A532 01183 LDA MUSIC_START +C5F6 A433 01184 LDY MUSIC_START+1 +C5F8 8534 01185 STA MUSIC_POINTER +C5FA 8435 01186 STY MUSIC_POINTER+1 +C5FC 4CDCC5 01187 JMP .1 +C5FF 01188 +C5FF A531 01189 .4: LDA MUSIC_TIMING +C601 293F 01190 AND #$3F ; Restart note time. +C603 8536 01191 STA MUSIC_NOTE_COUNTER +C605 01192 +C605 B134 01193 LDA (MUSIC_POINTER),Y +C607 C93F 01194 CMP #$3F ; Sustain? +C609 F00F 01195 BEQ .5 +C60B 29C0 01196 AND #$C0 +C60D 8537 01197 STA MUSIC_INSTRUMENT_1 +C60F B134 01198 LDA (MUSIC_POINTER),Y +C611 293F 01199 AND #$3F +C613 0A 01200 ASL A +C614 8538 01201 STA MUSIC_NOTE_1 +C616 A900 01202 LDA #0 +C618 8539 01203 STA MUSIC_COUNTER_1 +C61A 01204 .5: +C61A C8 01205 INY +C61B B134 01206 LDA (MUSIC_POINTER),Y +C61D C93F 01207 CMP #$3F ; Sustain? +C61F F00F 01208 BEQ .6 +C621 29C0 01209 AND #$C0 +C623 853A 01210 STA MUSIC_INSTRUMENT_2 +C625 B134 01211 LDA (MUSIC_POINTER),Y +C627 293F 01212 AND #$3F +C629 0A 01213 ASL A +C62A 853B 01214 STA MUSIC_NOTE_2 +C62C A900 01215 LDA #0 +C62E 853C 01216 STA MUSIC_COUNTER_2 +C630 01217 .6: +C630 C8 01218 INY +C631 B134 01219 LDA (MUSIC_POINTER),Y +C633 C93F 01220 CMP #$3F ; Sustain? +C635 F00F 01221 BEQ .7 +C637 29C0 01222 AND #$C0 +C639 853D 01223 STA MUSIC_INSTRUMENT_3 +C63B B134 01224 LDA (MUSIC_POINTER),Y +C63D 293F 01225 AND #$3F +C63F 0A 01226 ASL A +C640 853E 01227 STA MUSIC_NOTE_3 +C642 A900 01228 LDA #0 +C644 853F 01229 STA MUSIC_COUNTER_3 +C646 01230 .7: +C646 C8 01231 INY +C647 B134 01232 LDA (MUSIC_POINTER),Y +C649 8540 01233 STA MUSIC_DRUM +C64B A900 01234 LDA #0 +C64D 8541 01235 STA MUSIC_COUNTER_4 +C64F A534 01236 LDA MUSIC_POINTER +C651 18 01237 CLC +C652 6904 01238 ADC #4 +C654 8534 01239 STA MUSIC_POINTER +C656 A535 01240 LDA MUSIC_POINTER+1 +C658 6900 01241 ADC #0 +C65A 8535 01242 STA MUSIC_POINTER+1 +C65C 01243 .2: +C65C A438 01244 LDY MUSIC_NOTE_1 +C65E F00D 01245 BEQ .8 +C660 A537 01246 LDA MUSIC_INSTRUMENT_1 +C662 A639 01247 LDX MUSIC_COUNTER_1 +C664 2037C7 01248 JSR MUSIC_NOTE2FREQ +C667 8542 01249 STA AUDIO_FREQ1 +C669 8443 01250 STY AUDIO_FREQ1+1 +C66B 8648 01251 STX AUDIO_VOL1 +C66D 01252 .8: +C66D A43B 01253 LDY MUSIC_NOTE_2 +C66F F00D 01254 BEQ .9 +C671 A53A 01255 LDA MUSIC_INSTRUMENT_2 +C673 A63C 01256 LDX MUSIC_COUNTER_2 +C675 2037C7 01257 JSR MUSIC_NOTE2FREQ +C678 8544 01258 STA AUDIO_FREQ2 +C67A 8445 01259 STY AUDIO_FREQ2+1 +C67C 8649 01260 STX AUDIO_VOL2 +C67E 01261 .9: +C67E A43E 01262 LDY MUSIC_NOTE_3 +C680 F00D 01263 BEQ .10 +C682 A53D 01264 LDA MUSIC_INSTRUMENT_3 +C684 A63F 01265 LDX MUSIC_COUNTER_3 +C686 2037C7 01266 JSR MUSIC_NOTE2FREQ +C689 8546 01267 STA AUDIO_FREQ3 +C68B 8447 01268 STY AUDIO_FREQ3+1 +C68D 864A 01269 STX AUDIO_VOL3 +C68F 01270 .10: +C68F A540 01271 LDA MUSIC_DRUM +C691 F03A 01272 BEQ .11 +C693 C901 01273 CMP #1 ; 1 - Long drum. +C695 D011 01274 BNE .12 +C697 A541 01275 LDA MUSIC_COUNTER_4 +C699 C903 01276 CMP #3 +C69B B030 01277 BCS .11 +C69D 01278 .15: +C69D A906 01279 LDA #$06 +C69F 854C 01280 STA AUDIO_NOISE +C6A1 A99C 01281 LDA #$9C +C6A3 854B 01282 STA AUDIO_VOL4HW +C6A5 4CCDC6 01283 JMP .11 +C6A8 01284 +C6A8 C902 01285 .12: CMP #2 ; 2 - Short drum. +C6AA D011 01286 BNE .14 +C6AC A541 01287 LDA MUSIC_COUNTER_4 +C6AE C900 01288 CMP #0 +C6B0 D01B 01289 BNE .11 +C6B2 A902 01290 LDA #$02 +C6B4 854C 01291 STA AUDIO_NOISE +C6B6 A99C 01292 LDA #$9C +C6B8 854B 01293 STA AUDIO_VOL4HW +C6BA 4CCDC6 01294 JMP .11 +C6BD 01295 +C6BD 01296 .14: ;CMP #3 ; 3 - Roll. +C6BD 01297 ;BNE +C6BD A541 01298 LDA MUSIC_COUNTER_4 +C6BF C902 01299 CMP #2 +C6C1 90DA 01300 BCC .15 +C6C3 0A 01301 ASL A +C6C4 38 01302 SEC +C6C5 E531 01303 SBC MUSIC_TIMING +C6C7 9004 01304 BCC .11 +C6C9 C904 01305 CMP #4 +C6CB 90D0 01306 BCC .15 +C6CD 01307 .11: +C6CD A639 01308 LDX MUSIC_COUNTER_1 +C6CF E8 01309 INX +C6D0 E018 01310 CPX #$18 +C6D2 D002 01311 BNE $+4 +C6D4 A210 01312 LDX #$10 +C6D6 8639 01313 STX MUSIC_COUNTER_1 +C6D8 01314 +C6D8 A63C 01315 LDX MUSIC_COUNTER_2 +C6DA E8 01316 INX +C6DB E018 01317 CPX #$18 +C6DD D002 01318 BNE $+4 +C6DF A210 01319 LDX #$10 +C6E1 863C 01320 STX MUSIC_COUNTER_2 +C6E3 01321 +C6E3 A63F 01322 LDX MUSIC_COUNTER_3 +C6E5 E8 01323 INX +C6E6 E018 01324 CPX #$18 +C6E8 D002 01325 BNE $+4 +C6EA A210 01326 LDX #$10 +C6EC 863F 01327 STX MUSIC_COUNTER_3 +C6EE 01328 +C6EE E641 01329 INC MUSIC_COUNTER_4 +C6F0 C636 01330 DEC MUSIC_NOTE_COUNTER +C6F2 60 01331 RTS +C6F3 01332 +C6F3 01333 MUSIC_FLUTE: +C6F3 B9DDC7 01334 LDA MUSIC_NOTES_TABLE,Y +C6F6 18 01335 CLC +C6F7 7D1FC7 01336 ADC .2,X +C6FA 48 01337 PHA +C6FB B9DEC7 01338 LDA MUSIC_NOTES_TABLE+1,Y +C6FE 6900 01339 ADC #0 +C700 A8 01340 TAY +C701 BD07C7 01341 LDA .1,X +C704 AA 01342 TAX +C705 68 01343 PLA +C706 60 01344 RTS +C707 01345 +C707 01346 .1: +C707 9A9C9D9D9C9C9C9C 01347 DB $9A,$9C,$9D,$9D,$9C,$9C,$9C,$9C +C70F 9B9B9B9B9A9A9A9A 01348 DB $9B,$9B,$9B,$9B,$9A,$9A,$9A,$9A +C717 9B9B9B9B9A9A9A9A 01349 DB $9B,$9B,$9B,$9B,$9A,$9A,$9A,$9A +C71F 01350 +C71F 01351 .2: +C71F 0000000000010101 01352 DB 0,0,0,0,0,1,1,1 +C727 0001010100010101 01353 DB 0,1,1,1,0,1,1,1 +C72F 0001010100010101 01354 DB 0,1,1,1,0,1,1,1 +C737 01355 +C737 01356 ; +C737 01357 ; Converts note to frequency. +C737 01358 ; Input: +C737 01359 ; A = Instrument. +C737 01360 ; Y = Note (1-62) +C737 01361 ; X = Instrument counter. +C737 01362 ; Output: +C737 01363 ; YA = Frequency. +C737 01364 ; X = Volume. +C737 01365 ; +C737 01366 MUSIC_NOTE2FREQ: +C737 C940 01367 CMP #$40 +C739 902E 01368 BCC MUSIC_PIANO +C73B F052 01369 BEQ MUSIC_CLARINET +C73D C980 01370 CMP #$80 +C73F F0B2 01371 BEQ MUSIC_FLUTE +C741 01372 ; +C741 01373 ; Bass instrument +C741 01374 ; +C741 01375 MUSIC_BASS: +C741 B9DDC7 01376 LDA MUSIC_NOTES_TABLE,Y +C744 0A 01377 ASL A +C745 48 01378 PHA +C746 B9DEC7 01379 LDA MUSIC_NOTES_TABLE+1,Y +C749 2A 01380 ROL A +C74A A8 01381 TAY +C74B BD51C7 01382 LDA .1,X +C74E AA 01383 TAX +C74F 68 01384 PLA +C750 60 01385 RTS +C751 01386 +C751 01387 .1: +C751 9D9D9C9C9B9B9A9A 01388 DB $9D,$9D,$9C,$9C,$9B,$9B,$9A,$9A +C759 9999989897979696 01389 DB $99,$99,$98,$98,$97,$97,$96,$96 +C761 9595949493939292 01390 DB $95,$95,$94,$94,$93,$93,$92,$92 +C769 01391 +C769 01392 MUSIC_PIANO: +C769 B9DDC7 01393 LDA MUSIC_NOTES_TABLE,Y +C76C 48 01394 PHA +C76D B9DEC7 01395 LDA MUSIC_NOTES_TABLE+1,Y +C770 A8 01396 TAY +C771 BD77C7 01397 LDA .1,X +C774 AA 01398 TAX +C775 68 01399 PLA +C776 60 01400 RTS +C777 01401 +C777 01402 .1: +C777 DCDBDBDADAD9D9D8 01403 DB $DC,$DB,$DB,$DA,$DA,$D9,$D9,$D8 +C77F D8D7D7D6D6D5D5D4 01404 DB $D8,$D7,$D7,$D6,$D6,$D5,$D5,$D4 +C787 D4D4D5D5D4D4D3D3 01405 DB $D4,$D4,$D5,$D5,$D4,$D4,$D3,$D3 +C78F 01406 +C78F 01407 MUSIC_CLARINET: +C78F B9DDC7 01408 LDA MUSIC_NOTES_TABLE,Y +C792 18 01409 CLC +C793 7DC5C7 01410 ADC .2,X +C796 48 01411 PHA +C797 BDC5C7 01412 LDA .2,X +C79A 3003 01413 BMI .3 +C79C A900 01414 LDA #$00 +C79E 2C 01415 DB $2C +C79F A9FF 01416 .3: LDA #$FF +C7A1 79DEC7 01417 ADC MUSIC_NOTES_TABLE+1,Y +C7A4 4A 01418 LSR A +C7A5 A8 01419 TAY +C7A6 BDADC7 01420 LDA .1,X +C7A9 AA 01421 TAX +C7AA 68 01422 PLA +C7AB 6A 01423 ROR A +C7AC 60 01424 RTS +C7AD 01425 +C7AD 01426 .1: +C7AD 1D1E1E1D1D1C1C1C 01427 DB $1D,$1E,$1E,$1D,$1D,$1C,$1C,$1C +C7B5 1B1B1B1B1C1C1C1C 01428 DB $1B,$1B,$1B,$1B,$1C,$1C,$1C,$1C +C7BD 1B1B1B1B1C1C1C1C 01429 DB $1B,$1B,$1B,$1B,$1C,$1C,$1C,$1C +C7C5 01430 +C7C5 01431 .2: +C7C5 00000000FFFFFF00 01432 DB 0,0,0,0,-1,-1,-1,0 +C7CD 01010100FFFFFF00 01433 DB 1,1,1,0,-1,-1,-1,0 +C7D5 01010100FFFFFF00 01434 DB 1,1,1,0,-1,-1,-1,0 +C7DD 01435 +C7DD 01436 ; +C7DD 01437 ; Musical notes table. +C7DD 01438 ; +C7DD 01439 MUSIC_NOTES_TABLE: +C7DD 01440 ; Silence - 0 +C7DD 0000 01441 DW 0 +C7DF 01442 ; Values for 1.79 mhz. / 16, offset 0 +C7DF 01443 ; 2nd octave - Index 1 +C7DF AE064E06F4059E05 01444 DW 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 +C7F7 01445 ; 3rd octave - Index 13 +C7F7 57032703FA02CF02 01446 DW 855,807,762,719,679,641,605,571,539,508,480,453 +C80F 01447 ; 4th octave - Index 25 +C80F AC0194017D016801 01448 DW 428,404,381,360,339,320,302,285,269,254,240,226 +C827 01449 ; 5th octave - Index 37 +C827 D600CA00BE00B400 01450 DW 214,202,190,180,170,160,151,143,135,127,120,113 +C83F 01451 ; 6th octave - Index 49 +C83F 6B0065005F005A00 01452 DW 107,101,95,90,85,80,76,71,67,64,60,57 +C857 01453 ; 7th octave - Index 61 +C857 350032003000 01454 DW 53,50,48 +C85D 01455 +C85D 01456 ; +C85D 01457 ; When the frequency upper byte is rewritten, the +C85D 01458 ; output phase is reset, and it creates glitches. +C85D 01459 ; So it doesn't rewrite frequency unless the note +C85D 01460 ; changes. +C85D 01461 ; +C85D 01462 MUSIC_HARDWARE: +C85D A54E 01463 LDA MUSIC_MODE +C85F C904 01464 CMP #4 ; PLAY SIMPLE? +C861 901C 01465 BCC .9 ; Yes, jump. +C863 A549 01466 LDA AUDIO_VOL2 +C865 290F 01467 AND #$0F +C867 D016 01468 BNE .9 +C869 A54A 01469 LDA AUDIO_VOL3 +C86B 290F 01470 AND #$0F +C86D F010 01471 BEQ .9 +C86F A54A 01472 LDA AUDIO_VOL3 +C871 8549 01473 STA AUDIO_VOL2 +C873 A910 01474 LDA #$10 +C875 854A 01475 STA AUDIO_VOL3 +C877 A546 01476 LDA AUDIO_FREQ3 +C879 A447 01477 LDY AUDIO_FREQ3+1 +C87B 8544 01478 STA AUDIO_FREQ2 +C87D 8445 01479 STY AUDIO_FREQ2+1 +C87F 01480 .9: +C87F A542 01481 LDA AUDIO_FREQ1 +C881 8D0240 01482 STA $4002 +C884 A539 01483 LDA MUSIC_COUNTER_1 +C886 C901 01484 CMP #1 +C888 D007 01485 BNE .3 +C88A A543 01486 LDA AUDIO_FREQ1+1 +C88C 0908 01487 ORA #$08 ; Keeps tone enabled +C88E 8D0340 01488 STA $4003 +C891 A548 01489 .3: LDA AUDIO_VOL1 +C893 8D0040 01490 STA $4000 +C896 A900 01491 LDA #0 +C898 8D0140 01492 STA $4001 +C89B 01493 +C89B A544 01494 LDA AUDIO_FREQ2 +C89D 8D0640 01495 STA $4006 +C8A0 A53C 01496 LDA MUSIC_COUNTER_2 +C8A2 C901 01497 CMP #1 +C8A4 D007 01498 BNE .4 +C8A6 A545 01499 LDA AUDIO_FREQ2+1 +C8A8 0908 01500 ORA #$08 ; Keeps tone enabled +C8AA 8D0740 01501 STA $4007 +C8AD A549 01502 .4: LDA AUDIO_VOL2 +C8AF 8D0440 01503 STA $4004 +C8B2 A900 01504 LDA #0 +C8B4 8D0540 01505 STA $4005 +C8B7 01506 +C8B7 A54E 01507 LDA MUSIC_MODE +C8B9 C904 01508 CMP #4 ; PLAY SIMPLE? +C8BB 902B 01509 BCC .6 ; Yes, jump. +C8BD 01510 +C8BD 4647 01511 LSR AUDIO_FREQ3+1 +C8BF 6646 01512 ROR AUDIO_FREQ3 +C8C1 A546 01513 LDA AUDIO_FREQ3 +C8C3 8D0A40 01514 STA $400A +C8C6 A53F 01515 LDA MUSIC_COUNTER_3 +C8C8 C901 01516 CMP #1 +C8CA D007 01517 BNE .5 +C8CC A547 01518 LDA AUDIO_FREQ3+1 +C8CE 0908 01519 ORA #$08 ; Keeps tone enabled +C8D0 8D0B40 01520 STA $400B +C8D3 01521 .5: +C8D3 A920 01522 LDA #$20 +C8D5 8D0840 01523 STA $4008 +C8D8 A54A 01524 LDA AUDIO_VOL3 +C8DA 290F 01525 AND #$0F +C8DC D005 01526 BNE .1 +C8DE A90B 01527 LDA #$0B +C8E0 4CE5C8 01528 JMP .2 +C8E3 01529 +C8E3 A90F 01530 .1: LDA #$0F +C8E5 8D1540 01531 .2: STA $4015 +C8E8 01532 +C8E8 A54E 01533 .6: LDA MUSIC_MODE +C8EA 4A 01534 LSR A ; NO DRUMS? +C8EB 9015 01535 BCC .8 +C8ED A541 01536 LDA MUSIC_COUNTER_4 +C8EF C901 01537 CMP #1 +C8F1 D00A 01538 BNE .7 +C8F3 A54C 01539 LDA AUDIO_NOISE +C8F5 8D0E40 01540 STA $400E +C8F8 0908 01541 ORA #$08 ; Keeps tone enabled +C8FA 8D0F40 01542 STA $400F +C8FD A54B 01543 .7: LDA AUDIO_VOL4HW +C8FF 8D0C40 01544 STA $400C +C902 01545 .8: +C902 60 01546 RTS +C903 01547 +C903 01548 MUSIC_SILENCE: +C903 08 01549 DB 8 +C904 00000000 01550 DB 0,0,0,0 +C908 FE 01551 DB -2 +C909 01552 ENDIF +C909 01553 +C909 01554 +C909 01555 IF CVBASIC_BANK_SWITCHING +C909 01556 COPY_CHRRAM: +C909 A900 01557 LDA #$00 +C90B 8D0620 01558 STA PPUADDR +C90E 8D0620 01559 STA PPUADDR +C911 8502 01560 STA TEMP +C913 8603 01561 STX TEMP+1 +C915 A220 01562 LDX #32 +C917 01563 .1: +C917 201EC9 01564 JSR COPY_PAGE +C91A CA 01565 DEX +C91B D0FA 01566 BNE .1 +C91D 60 01567 RTS +C91E 01568 +C91E 01569 COPY_PAGE: +C91E A000 01570 LDY #0 +C920 01571 .1: +C920 B102 01572 LDA (TEMP),Y +C922 8D0720 01573 STA PPUDATA +C925 C8 01574 INY +C926 D0F8 01575 BNE .1 +C928 E603 01576 INC TEMP+1 +C92A 60 01577 RTS +C92B 01578 ENDIF +C92B 01579 +C92B 01580 START: +C92B 78 01581 SEI +C92C D8 01582 CLD +C92D 01583 +C92D 2C0220 01584 BIT PPUSTATUS +C930 01585 +C930 A940 01586 LDA #$40 +C932 8D1740 01587 STA $4017 +C935 A910 01588 LDA #$10 +C937 8D0040 01589 STA $4000 ; Channel 1 silent +C93A 8D0440 01590 STA $4004 ; Channel 2 silent +C93D 8D0C40 01591 STA $400C ; Channel 4 silent +C940 A90B 01592 LDA #$0B +C942 8D1540 01593 STA $4015 ; Enable channel 1, 2 and 4. +C945 A900 01594 LDA #$00 +C947 8D1040 01595 STA $4010 +C94A 01596 +C94A A900 01597 LDA #0 +C94C 8D0020 01598 STA PPUCTRL +C94F 8D0120 01599 STA PPUMASK +C952 01600 +C952 AA 01601 TAX +C953 9500 01602 .1: STA $00,X +C955 9D0001 01603 STA $0100,X +C958 9D0003 01604 STA $0300,X +C95B 9D0004 01605 STA $0400,X +C95E 9D0005 01606 STA $0500,X +C961 9D0006 01607 STA $0600,X +C964 9D0007 01608 STA $0700,X +C967 E8 01609 INX +C968 D0E9 01610 BNE .1 +C96A 01611 +C96A A2FF 01612 LDX #STACK +C96C 9A 01613 TXS +C96D 01614 +C96D 207AC5 01615 JSR CLEAR_SPRITES +C970 01616 +C970 01617 ; +C970 01618 ; The NES starts with the PPU registers write-protected. +C970 01619 ; Around 29000 cycles must happen before these can be written. +C970 01620 ; +C970 01621 +C970 01622 ; lidnariq code for detecting NTSC/PAL/Dendy system +C970 01623 ; From: https://forums.nesdev.org/viewtopic.php?p=163258#p163258 +C970 A200 01624 LDX #0 +C972 A000 01625 LDY #0 +C974 2C0220 01626 BIT PPUSTATUS +C977 10FB 01627 BPL $-3 +C979 01628 .5: +C979 E8 01629 INX +C97A D001 01630 BNE .6 +C97C C8 01631 INY +C97D 01632 .6: +C97D 01633 ; About 27384 cycles passed at this time. +C97D 2C0220 01634 BIT PPUSTATUS +C980 10F7 01635 BPL .5 +C982 A900 01636 LDA #0 +C984 8D0020 01637 STA PPUCTRL +C987 8D0120 01638 STA PPUMASK +C98A 01639 +C98A 98 01640 TYA +C98B C910 01641 CMP #16 +C98D 9001 01642 BCC .7 +C98F 4A 01643 LSR A +C990 18 01644 .7: CLC +C991 69F7 01645 ADC #$F7 +C993 C903 01646 CMP #3 +C995 9002 01647 BCC .8 +C997 A903 01648 LDA #3 ; Bad +C999 01649 ; 0=NTSC, 1=Pal, 2=Dendy, 3=Bad +C999 01650 .8: +C999 C900 01651 CMP #0 ; Pass NTSC unchanged +C99B F002 01652 BEQ .9 +C99D A901 01653 LDA #1 ; All other PAL +C99F 4901 01654 .9: EOR #1 +C9A1 850F 01655 STA NTSC +C9A3 01656 ; About 57165 cycles passed at this time. +C9A3 01657 +C9A3 01658 IF CVBASIC_BANK_SWITCHING +C9A3 01659 ; Copy CHRROM to CHRRAM +C9A3 A90D 01660 LDA #$00+CVBASIC_BANK_ROM_SIZE/16-3 +C9A5 8D00C0 01661 STA BANKSEL +C9A8 A280 01662 LDX #$80 +C9AA 2009C9 01663 JSR COPY_CHRRAM +C9AD 01664 +C9AD A92D 01665 LDA #$20+CVBASIC_BANK_ROM_SIZE/16-3 +C9AF 8D00C0 01666 STA BANKSEL +C9B2 A2A0 01667 LDX #$A0 +C9B4 2009C9 01668 JSR COPY_CHRRAM +C9B7 01669 +C9B7 A94E 01670 LDA #$40+CVBASIC_BANK_ROM_SIZE/16-2 +C9B9 8D00C0 01671 STA BANKSEL +C9BC A280 01672 LDX #$80 +C9BE 2009C9 01673 JSR COPY_CHRRAM +C9C1 01674 +C9C1 A96E 01675 LDA #$60+CVBASIC_BANK_ROM_SIZE/16-2 +C9C3 8D00C0 01676 STA BANKSEL +C9C6 A2A0 01677 LDX #$A0 +C9C8 2009C9 01678 JSR COPY_CHRRAM +C9CB 01679 +C9CB A900 01680 LDA #$00 ; BANK SELECT 1 +C9CD 8D00C0 01681 STA BANKSEL +C9D0 01682 ENDIF +C9D0 01683 +C9D0 01684 ; Clear 2K of pattern memory +C9D0 A920 01685 LDA #$20 +C9D2 8D0620 01686 STA PPUADDR +C9D5 A900 01687 LDA #$00 +C9D7 8D0620 01688 STA PPUADDR +C9DA A278 01689 LDX #$78 +C9DC A920 01690 LDA #$20 +C9DE 01691 .2: +C9DE 8D0720 01692 STA PPUDATA +C9E1 8D0720 01693 STA PPUDATA +C9E4 8D0720 01694 STA PPUDATA +C9E7 8D0720 01695 STA PPUDATA +C9EA 8D0720 01696 STA PPUDATA +C9ED 8D0720 01697 STA PPUDATA +C9F0 8D0720 01698 STA PPUDATA +C9F3 8D0720 01699 STA PPUDATA +C9F6 CA 01700 DEX +C9F7 D0E5 01701 BNE .2 +C9F9 01702 +C9F9 A240 01703 LDX #$40 +C9FB A900 01704 LDA #$00 +C9FD 8D0720 01705 .3: STA PPUDATA +CA00 CA 01706 DEX +CA01 D0FA 01707 BNE .3 +CA03 01708 +CA03 01709 ; Setup base palette +CA03 A93F 01710 LDA #$3F +CA05 8D0620 01711 STA PPUADDR +CA08 A900 01712 LDA #$00 +CA0A 8D0620 01713 STA PPUADDR +CA0D A208 01714 LDX #8 +CA0F 01715 .4: +CA0F A90F 01716 LDA #$0F ; Black +CA11 8D0720 01717 STA PPUDATA +CA14 A935 01718 LDA #$35 ; Red +CA16 8D0720 01719 STA PPUDATA +CA19 A93A 01720 LDA #$3A ; Green +CA1B 8D0720 01721 STA PPUDATA +CA1E A930 01722 LDA #$30 ; White +CA20 8D0720 01723 STA PPUDATA +CA23 CA 01724 DEX +CA24 D0E9 01725 BNE .4 +CA26 01726 +CA26 2C0220 01727 BIT PPUSTATUS +CA29 10FB 01728 BPL $-3 +CA2B A91E 01729 LDA #$1E ; Color normal, Sprites visible, Background visible, No clipping, Color. +CA2D 8D0120 01730 STA PPUMASK +CA30 8517 01731 STA PPU_MASK +CA32 A9A8 01732 LDA #$A8 ; Enable NMI, 8x16 sprites, BG=$0000, SPR=$1000, NAME=$2000 +CA34 8516 01733 STA PPU_CTRL +CA36 8D0020 01734 STA PPUCTRL +CA39 01735 +CA39 2088C5 01736 JSR MUSIC_INIT +CA3C 01737 +CA3C 2077C5 01738 JSR MODE_0 +CA3F 01739 +CA3F A900 01740 LDA #$00 +CA41 8520 01741 STA JOY1_DATA +CA43 8521 01742 STA JOY2_DATA +CA45 A90F 01743 LDA #$0F +CA47 8522 01744 STA KEY1_DATA +CA49 8523 01745 STA KEY2_DATA +CA4B 01746 +CA4B 01747 RAM_END: +CA4B 01748 ; rem +CA4B 01749 ; rem Bank-switching example for NES/Famicom +CA4B 01750 ; rem by Oscar Toledo G. http://nanochess.org +CA4B 01751 ; rem Aug/26/2025 +CA4B 01752 ; rem +CA4B 01753 ; +CA4B 01754 ; BANK ROM 256 ' Select a 256KB target ROM size. +CA4B 01755 ; ' Now it is in bank 0. +CA4B 01756 ; +CA4B 01757 ; PLAY FULL +CA4B A905 01758 LDA #5 +CA4D 854E 01759 STA MUSIC_MODE +CA4F 01760 ; BANK SELECT 1 ' Select bank 1 to access. +CA4F A900 01761 LDA #0 +CA51 051C 01762 ORA CHRRAM_BANK +CA53 8D00C0 01763 STA BANKSEL +CA56 01764 ; PLAY tune_1 +CA56 A900 01765 LDA #CVB_TUNE_1 +CA58 A080 01766 LDY #CVB_TUNE_1>>8 +CA5A 20A6C5 01767 JSR MUSIC_PLAY +CA5D 01768 ; +CA5D 01769 ; ' Display image. +CA5D 01770 ; PALETTE 0,$0F +CA5D A900 01771 LDA #0 +CA5F A614 01772 LDX PPU_POINTER +CA61 9D0001 01773 STA PPUBUF,X +CA64 A97F 01774 LDA #$7F +CA66 9D0101 01775 STA PPUBUF+1,X +CA69 A90F 01776 LDA #15 +CA6B A614 01777 LDX PPU_POINTER +CA6D 9D0201 01778 STA PPUBUF+2,X +CA70 E8 01779 INX +CA71 E8 01780 INX +CA72 E8 01781 INX +CA73 8614 01782 STX PPU_POINTER +CA75 01783 ; PALETTE 1,$16 +CA75 A901 01784 LDA #1 +CA77 A614 01785 LDX PPU_POINTER +CA79 9D0001 01786 STA PPUBUF,X +CA7C A97F 01787 LDA #$7F +CA7E 9D0101 01788 STA PPUBUF+1,X +CA81 A916 01789 LDA #22 +CA83 A614 01790 LDX PPU_POINTER +CA85 9D0201 01791 STA PPUBUF+2,X +CA88 E8 01792 INX +CA89 E8 01793 INX +CA8A E8 01794 INX +CA8B 8614 01795 STX PPU_POINTER +CA8D 01796 ; PALETTE 2,$27 +CA8D A902 01797 LDA #2 +CA8F A614 01798 LDX PPU_POINTER +CA91 9D0001 01799 STA PPUBUF,X +CA94 A97F 01800 LDA #$7F +CA96 9D0101 01801 STA PPUBUF+1,X +CA99 A927 01802 LDA #39 +CA9B A614 01803 LDX PPU_POINTER +CA9D 9D0201 01804 STA PPUBUF+2,X +CAA0 E8 01805 INX +CAA1 E8 01806 INX +CAA2 E8 01807 INX +CAA3 8614 01808 STX PPU_POINTER +CAA5 01809 ; PALETTE 3,$38 +CAA5 A903 01810 LDA #3 +CAA7 A614 01811 LDX PPU_POINTER +CAA9 9D0001 01812 STA PPUBUF,X +CAAC A97F 01813 LDA #$7F +CAAE 9D0101 01814 STA PPUBUF+1,X +CAB1 A938 01815 LDA #56 +CAB3 A614 01816 LDX PPU_POINTER +CAB5 9D0201 01817 STA PPUBUF+2,X +CAB8 E8 01818 INX +CAB9 E8 01819 INX +CABA E8 01820 INX +CABB 8614 01821 STX PPU_POINTER +CABD 01822 ; SCREEN DISABLE +CABD 2073C0 01823 JSR DISSCR +CAC0 01824 ; WAIT +CAC0 2063C4 01825 JSR WAIT +CAC3 01826 ; +CAC3 01827 ; BANK SELECT 2 ' Select bank 2 to access. +CAC3 A901 01828 LDA #1 +CAC5 051C 01829 ORA CHRRAM_BANK +CAC7 8D00C0 01830 STA BANKSEL +CACA 01831 ; +CACA 01832 ; SCREEN image_pattern,0,132,12,16,12 +CACA A93A 01833 LDA #CVB_IMAGE_PATTERN +CACC A080 01834 LDY #CVB_IMAGE_PATTERN>>8 +CACE 48 01835 PHA +CACF 98 01836 TYA +CAD0 48 01837 PHA +CAD1 A984 01838 LDA #132 +CAD3 A020 01839 LDY #32 +CAD5 8508 01840 STA POINTER +CAD7 8409 01841 STY POINTER+1 +CAD9 A90C 01842 LDA #12 +CADB 48 01843 PHA +CADC A910 01844 LDA #16 +CADE 48 01845 PHA +CADF A90C 01846 LDA #12 +CAE1 A000 01847 LDY #0 +CAE3 AA 01848 TAX +CAE4 68 01849 PLA +CAE5 8505 01850 STA TEMP2+1 +CAE7 68 01851 PLA +CAE8 8504 01852 STA TEMP2 +CAEA 68 01853 PLA +CAEB 8503 01854 STA TEMP+1 +CAED 68 01855 PLA +CAEE 8502 01856 STA TEMP +CAF0 207AC0 01857 JSR CPYBLK +CAF3 01858 ; WAIT +CAF3 2063C4 01859 JSR WAIT +CAF6 01860 ; SCREEN ENABLE +CAF6 206CC0 01861 JSR ENASCR +CAF9 01862 ; +CAF9 01863 ; GOSUB display_some_text +CAF9 200080 01864 JSR CVB_DISPLAY_SOME_TEXT +CAFC 01865 ; +CAFC 01866 ; WHILE 1: WEND +CAFC 01867 CV1: +CAFC 4CFCCA 01868 JMP CV1 +CAFF 01869 CV2: +CAFF 01870 ; +CAFF 01871 ; BANK 1 ' Start of bank 1 data +CAFF 01872 BANK_0_FREE: EQU $FFFA-$ +CAFF FFFFFFFFFFFFFFFF 01873 TIMES $FFFA-$ DB $FF +FFFA 1F 01874 DB $1F + 01875 FORG $00010 +8000 01876 ORG $8000 +8000 01877 ; +8000 01878 ; ' Bach Invention 8 (BWV779) +8000 01879 ; ' Fragment +8000 01880 ; tune_1: DATA BYTE 7 +8000 01881 CVB_TUNE_1: +8000 07 01882 DB $07 +8001 01883 ; MUSIC F4,- +8001 1E000000 01884 DB $1E,$00,$00,$00 +8005 01885 ; MUSIC S,- +8005 3F000000 01886 DB $3F,$00,$00,$00 +8009 01887 ; MUSIC A4,- +8009 22000000 01888 DB $22,$00,$00,$00 +800D 01889 ; MUSIC S,- +800D 3F000000 01890 DB $3F,$00,$00,$00 +8011 01891 ; MUSIC F4,- +8011 1E000000 01892 DB $1E,$00,$00,$00 +8015 01893 ; MUSIC S,- +8015 3F000000 01894 DB $3F,$00,$00,$00 +8019 01895 ; MUSIC C5,- +8019 25000000 01896 DB $25,$00,$00,$00 +801D 01897 ; MUSIC S,- +801D 3F000000 01898 DB $3F,$00,$00,$00 +8021 01899 ; MUSIC F4,- +8021 1E000000 01900 DB $1E,$00,$00,$00 +8025 01901 ; MUSIC S,- +8025 3F000000 01902 DB $3F,$00,$00,$00 +8029 01903 ; +8029 01904 ; MUSIC F5,- +8029 2A000000 01905 DB $2A,$00,$00,$00 +802D 01906 ; MUSIC S,- +802D 3F000000 01907 DB $3F,$00,$00,$00 +8031 01908 ; MUSIC E5,F3 +8031 29120000 01909 DB $29,$12,$00,$00 +8035 01910 ; MUSIC D5,S +8035 273F0000 01911 DB $27,$3F,$00,$00 +8039 01912 ; MUSIC C5,A3 +8039 25160000 01913 DB $25,$16,$00,$00 +803D 01914 ; MUSIC D5,S +803D 273F0000 01915 DB $27,$3F,$00,$00 +8041 01916 ; MUSIC C5,F3 +8041 25120000 01917 DB $25,$12,$00,$00 +8045 01918 ; MUSIC A4#,S +8045 233F0000 01919 DB $23,$3F,$00,$00 +8049 01920 ; MUSIC A4,C4 +8049 22190000 01921 DB $22,$19,$00,$00 +804D 01922 ; MUSIC A4#,S +804D 233F0000 01923 DB $23,$3F,$00,$00 +8051 01924 ; MUSIC A4,F3 +8051 22120000 01925 DB $22,$12,$00,$00 +8055 01926 ; MUSIC G4,S +8055 203F0000 01927 DB $20,$3F,$00,$00 +8059 01928 ; +8059 01929 ; MUSIC F4,F4 +8059 1E1E0000 01930 DB $1E,$1E,$00,$00 +805D 01931 ; MUSIC S,S +805D 3F3F0000 01932 DB $3F,$3F,$00,$00 +8061 01933 ; MUSIC A4,E4 +8061 221D0000 01934 DB $22,$1D,$00,$00 +8065 01935 ; MUSIC S,D4 +8065 3F1B0000 01936 DB $3F,$1B,$00,$00 +8069 01937 ; MUSIC C5,C4 +8069 25190000 01938 DB $25,$19,$00,$00 +806D 01939 ; MUSIC S,D4 +806D 3F1B0000 01940 DB $3F,$1B,$00,$00 +8071 01941 ; MUSIC A4,C4 +8071 22190000 01942 DB $22,$19,$00,$00 +8075 01943 ; MUSIC S,A3# +8075 3F170000 01944 DB $3F,$17,$00,$00 +8079 01945 ; MUSIC F5,A3 +8079 2A160000 01946 DB $2A,$16,$00,$00 +807D 01947 ; MUSIC S,A3# +807D 3F170000 01948 DB $3F,$17,$00,$00 +8081 01949 ; MUSIC C5,A3 +8081 25160000 01950 DB $25,$16,$00,$00 +8085 01951 ; MUSIC S,G3 +8085 3F140000 01952 DB $3F,$14,$00,$00 +8089 01953 ; +8089 01954 ; MUSIC A5,F3 +8089 2E120000 01955 DB $2E,$12,$00,$00 +808D 01956 ; MUSIC C6,S +808D 313F0000 01957 DB $31,$3F,$00,$00 +8091 01958 ; MUSIC A5#,A3 +8091 2F160000 01959 DB $2F,$16,$00,$00 +8095 01960 ; MUSIC C6,S +8095 313F0000 01961 DB $31,$3F,$00,$00 +8099 01962 ; MUSIC A5,C4 +8099 2E190000 01963 DB $2E,$19,$00,$00 +809D 01964 ; MUSIC C6,S +809D 313F0000 01965 DB $31,$3F,$00,$00 +80A1 01966 ; MUSIC A5#,A3 +80A1 2F160000 01967 DB $2F,$16,$00,$00 +80A5 01968 ; MUSIC C6,S +80A5 313F0000 01969 DB $31,$3F,$00,$00 +80A9 01970 ; MUSIC A5,F4 +80A9 2E1E0000 01971 DB $2E,$1E,$00,$00 +80AD 01972 ; MUSIC C6,S +80AD 313F0000 01973 DB $31,$3F,$00,$00 +80B1 01974 ; MUSIC A5#,C4 +80B1 2F190000 01975 DB $2F,$19,$00,$00 +80B5 01976 ; MUSIC C6,S +80B5 313F0000 01977 DB $31,$3F,$00,$00 +80B9 01978 ; +80B9 01979 ; MUSIC F5,A3 +80B9 2A160000 01980 DB $2A,$16,$00,$00 +80BD 01981 ; MUSIC A5,C4 +80BD 2E190000 01982 DB $2E,$19,$00,$00 +80C1 01983 ; MUSIC G5,A3# +80C1 2C170000 01984 DB $2C,$17,$00,$00 +80C5 01985 ; MUSIC A5,C4 +80C5 2E190000 01986 DB $2E,$19,$00,$00 +80C9 01987 ; MUSIC F5,A3 +80C9 2A160000 01988 DB $2A,$16,$00,$00 +80CD 01989 ; MUSIC A5,C4 +80CD 2E190000 01990 DB $2E,$19,$00,$00 +80D1 01991 ; MUSIC G5,A3# +80D1 2C170000 01992 DB $2C,$17,$00,$00 +80D5 01993 ; MUSIC A5,C4 +80D5 2E190000 01994 DB $2E,$19,$00,$00 +80D9 01995 ; MUSIC F5,A3 +80D9 2A160000 01996 DB $2A,$16,$00,$00 +80DD 01997 ; MUSIC A5,C4 +80DD 2E190000 01998 DB $2E,$19,$00,$00 +80E1 01999 ; MUSIC G5,A3# +80E1 2C170000 02000 DB $2C,$17,$00,$00 +80E5 02001 ; MUSIC A5,C4 +80E5 2E190000 02002 DB $2E,$19,$00,$00 +80E9 02003 ; +80E9 02004 ; MUSIC D5,F3 +80E9 27120000 02005 DB $27,$12,$00,$00 +80ED 02006 ; MUSIC F5,A3 +80ED 2A160000 02007 DB $2A,$16,$00,$00 +80F1 02008 ; MUSIC E5,G3 +80F1 29140000 02009 DB $29,$14,$00,$00 +80F5 02010 ; MUSIC F5,A3 +80F5 2A160000 02011 DB $2A,$16,$00,$00 +80F9 02012 ; MUSIC D5,F3 +80F9 27120000 02013 DB $27,$12,$00,$00 +80FD 02014 ; MUSIC F5,A3 +80FD 2A160000 02015 DB $2A,$16,$00,$00 +8101 02016 ; MUSIC E5,G3 +8101 29140000 02017 DB $29,$14,$00,$00 +8105 02018 ; MUSIC F5,A3 +8105 2A160000 02019 DB $2A,$16,$00,$00 +8109 02020 ; MUSIC D5,F3 +8109 27120000 02021 DB $27,$12,$00,$00 +810D 02022 ; MUSIC F5,A3 +810D 2A160000 02023 DB $2A,$16,$00,$00 +8111 02024 ; MUSIC E5,G3 +8111 29140000 02025 DB $29,$14,$00,$00 +8115 02026 ; MUSIC F5,A3 +8115 2A160000 02027 DB $2A,$16,$00,$00 +8119 02028 ; +8119 02029 ; MUSIC B4,D3 +8119 240F0000 02030 DB $24,$0F,$00,$00 +811D 02031 ; MUSIC S,F3 +811D 3F120000 02032 DB $3F,$12,$00,$00 +8121 02033 ; MUSIC G4,E3 +8121 20110000 02034 DB $20,$11,$00,$00 +8125 02035 ; MUSIC S,F3 +8125 3F120000 02036 DB $3F,$12,$00,$00 +8129 02037 ; MUSIC D5,D3 +8129 270F0000 02038 DB $27,$0F,$00,$00 +812D 02039 ; MUSIC S,F3 +812D 3F120000 02040 DB $3F,$12,$00,$00 +8131 02041 ; MUSIC B4,E3 +8131 24110000 02042 DB $24,$11,$00,$00 +8135 02043 ; MUSIC S,F3 +8135 3F120000 02044 DB $3F,$12,$00,$00 +8139 02045 ; MUSIC F5,D3 +8139 2A0F0000 02046 DB $2A,$0F,$00,$00 +813D 02047 ; MUSIC S,F3 +813D 3F120000 02048 DB $3F,$12,$00,$00 +8141 02049 ; MUSIC D5,E3 +8141 27110000 02050 DB $27,$11,$00,$00 +8145 02051 ; MUSIC S,F3 +8145 3F120000 02052 DB $3F,$12,$00,$00 +8149 02053 ; +8149 02054 ; MUSIC G5,B3 +8149 2C180000 02055 DB $2C,$18,$00,$00 +814D 02056 ; MUSIC A5,S +814D 2E3F0000 02057 DB $2E,$3F,$00,$00 +8151 02058 ; MUSIC G5,G3 +8151 2C140000 02059 DB $2C,$14,$00,$00 +8155 02060 ; MUSIC F5,S +8155 2A3F0000 02061 DB $2A,$3F,$00,$00 +8159 02062 ; MUSIC E5,C4 +8159 29190000 02063 DB $29,$19,$00,$00 +815D 02064 ; MUSIC F5,S +815D 2A3F0000 02065 DB $2A,$3F,$00,$00 +8161 02066 ; MUSIC E5,G3 +8161 29140000 02067 DB $29,$14,$00,$00 +8165 02068 ; MUSIC D5,S +8165 273F0000 02069 DB $27,$3F,$00,$00 +8169 02070 ; MUSIC C5,E4 +8169 251D0000 02071 DB $25,$1D,$00,$00 +816D 02072 ; MUSIC D5,S +816D 273F0000 02073 DB $27,$3F,$00,$00 +8171 02074 ; MUSIC C5,C4 +8171 25190000 02075 DB $25,$19,$00,$00 +8175 02076 ; MUSIC A4#,S +8175 233F0000 02077 DB $23,$3F,$00,$00 +8179 02078 ; +8179 02079 ; MUSIC A4,F4 +8179 221E0000 02080 DB $22,$1E,$00,$00 +817D 02081 ; MUSIC S,G4 +817D 3F200000 02082 DB $3F,$20,$00,$00 +8181 02083 ; MUSIC D5,F4 +8181 271E0000 02084 DB $27,$1E,$00,$00 +8185 02085 ; MUSIC C5,E4 +8185 251D0000 02086 DB $25,$1D,$00,$00 +8189 02087 ; MUSIC B4,D4 +8189 241B0000 02088 DB $24,$1B,$00,$00 +818D 02089 ; MUSIC C5,E4 +818D 251D0000 02090 DB $25,$1D,$00,$00 +8191 02091 ; MUSIC B4,D4 +8191 241B0000 02092 DB $24,$1B,$00,$00 +8195 02093 ; MUSIC A4,C4 +8195 22190000 02094 DB $22,$19,$00,$00 +8199 02095 ; MUSIC G4,B3 +8199 20180000 02096 DB $20,$18,$00,$00 +819D 02097 ; MUSIC A4,C4 +819D 22190000 02098 DB $22,$19,$00,$00 +81A1 02099 ; MUSIC G4,B3 +81A1 20180000 02100 DB $20,$18,$00,$00 +81A5 02101 ; MUSIC F4,A3 +81A5 1E160000 02102 DB $1E,$16,$00,$00 +81A9 02103 ; +81A9 02104 ; MUSIC E4,G3 +81A9 1D140000 02105 DB $1D,$14,$00,$00 +81AD 02106 ; MUSIC F4,S +81AD 1E3F0000 02107 DB $1E,$3F,$00,$00 +81B1 02108 ; MUSIC E4,C4 +81B1 1D190000 02109 DB $1D,$19,$00,$00 +81B5 02110 ; MUSIC D4,B3 +81B5 1B180000 02111 DB $1B,$18,$00,$00 +81B9 02112 ; MUSIC C4,A3 +81B9 19160000 02113 DB $19,$16,$00,$00 +81BD 02114 ; MUSIC S,B3 +81BD 3F180000 02115 DB $3F,$18,$00,$00 +81C1 02116 ; MUSIC C5,A3 +81C1 25160000 02117 DB $25,$16,$00,$00 +81C5 02118 ; MUSIC B4,G3 +81C5 24140000 02119 DB $24,$14,$00,$00 +81C9 02120 ; MUSIC C5,F3 +81C9 25120000 02121 DB $25,$12,$00,$00 +81CD 02122 ; MUSIC S,G3 +81CD 3F140000 02123 DB $3F,$14,$00,$00 +81D1 02124 ; MUSIC E4,F3 +81D1 1D120000 02125 DB $1D,$12,$00,$00 +81D5 02126 ; MUSIC S,E3 +81D5 3F110000 02127 DB $3F,$11,$00,$00 +81D9 02128 ; +81D9 02129 ; MUSIC F4,D3 +81D9 1E0F0000 02130 DB $1E,$0F,$00,$00 +81DD 02131 ; MUSIC S,E3 +81DD 3F110000 02132 DB $3F,$11,$00,$00 +81E1 02133 ; MUSIC C5,D3 +81E1 250F0000 02134 DB $25,$0F,$00,$00 +81E5 02135 ; MUSIC S,C3 +81E5 3F0D0000 02136 DB $3F,$0D,$00,$00 +81E9 02137 ; MUSIC E4,G3 +81E9 1D140000 02138 DB $1D,$14,$00,$00 +81ED 02139 ; MUSIC S,F3 +81ED 3F120000 02140 DB $3F,$12,$00,$00 +81F1 02141 ; MUSIC C5,E3 +81F1 25110000 02142 DB $25,$11,$00,$00 +81F5 02143 ; MUSIC S,F3 +81F5 3F120000 02144 DB $3F,$12,$00,$00 +81F9 02145 ; MUSIC D4,G3 +81F9 1B140000 02146 DB $1B,$14,$00,$00 +81FD 02147 ; MUSIC S,S +81FD 3F3F0000 02148 DB $3F,$3F,$00,$00 +8201 02149 ; MUSIC B4,G2 +8201 24080000 02150 DB $24,$08,$00,$00 +8205 02151 ; MUSIC S,S +8205 3F3F0000 02152 DB $3F,$3F,$00,$00 +8209 02153 ; +8209 02154 ; MUSIC C5,C4 +8209 25190000 02155 DB $25,$19,$00,$00 +820D 02156 ; MUSIC S,S +820D 3F3F0000 02157 DB $3F,$3F,$00,$00 +8211 02158 ; MUSIC S,S +8211 3F3F0000 02159 DB $3F,$3F,$00,$00 +8215 02160 ; MUSIC S,S +8215 3F3F0000 02161 DB $3F,$3F,$00,$00 +8219 02162 ; MUSIC STOP +8219 FE000000 02163 DB $FE,$00,$00,$00 +821D 02164 ; +821D 02165 ; BANK 2 +821D 02166 BANK_1_FREE: EQU $BFFF-$ +821D FFFFFFFFFFFFFFFF 02167 TIMES $BFFF-$ DB $FF +BFFF 00 02168 DB $00 + 02169 FORG $04010 +8000 02170 ORG $8000 +8000 02171 ; +8000 02172 ; display_some_text: PROCEDURE +8000 02173 CVB_DISPLAY_SOME_TEXT: +8000 02174 ; +8000 02175 ; PRINT AT $01d1,"Hi!" +8000 206AC4 02176 JSR PRINT_STRING_CURSOR_CONSTANT +8003 D10103 02177 DB $D1,$01,$03 +8006 486921 02178 DB $48,$69,$21 +8009 02179 ; +8009 02180 ; PRINT AT $0211,"This is bank-" +8009 206AC4 02181 JSR PRINT_STRING_CURSOR_CONSTANT +800C 11020D 02182 DB $11,$02,$0D +800F 5468697320697320 02183 DB $54,$68,$69,$73,$20,$69,$73,$20 +8017 62616E6B2D 02184 DB $62,$61,$6E,$6B,$2D +801C 02185 ; +801C 02186 ; PRINT AT $0231,"switching demo." +801C 206AC4 02187 JSR PRINT_STRING_CURSOR_CONSTANT +801F 31020F 02188 DB $31,$02,$0F +8022 737769746368696E 02189 DB $73,$77,$69,$74,$63,$68,$69,$6E +802A 672064656D6F2E 02190 DB $67,$20,$64,$65,$6D,$6F,$2E +8031 02191 ; +8031 02192 ; PRINT AT $0271,":)" +8031 206AC4 02193 JSR PRINT_STRING_CURSOR_CONSTANT +8034 710202 02194 DB $71,$02,$02 +8037 3A29 02195 DB $3A,$29 +8039 02196 ; +8039 02197 ; END +8039 60 02198 RTS +803A 02199 ; +803A 02200 ; ' CHRROM is technically outside of the ROM, but for +803A 02201 ; ' the purposes of UNROM 512 bank-switching it is saved +803A 02202 ; ' in reserved banks and copied to CHRRAM on boot. +803A 02203 ; +803A 02204 ; ' TMSColor 3.2 Aug/26/2025 +803A 02205 ; ' Command: ./tmscolor -nes -p1 -t128 -b yo.png yo.bas +803A 02206 ; ' Created: Tue Aug 26 10:07:21 2025 +803A 02207 ; +803A 02208 ; ' Start tile = 128. Total_tiles = 118 +803A 02209 ; CHRROM 0 PATTERN 128 +803A 02210 ; BITMAP "11112222" +803A 02211 ; BITMAP "11112222" +803A 02212 ; BITMAP "11112222" +803A 02213 ; BITMAP "12222222" +803A 02214 ; BITMAP "22222222" +803A 02215 ; BITMAP "22222222" +803A 02216 ; BITMAP "22222222" +803A 02217 ; BITMAP "22222222" +803A 02218 ; +803A 02219 ; BITMAP "22222222" +803A 02220 ; BITMAP "22222222" +803A 02221 ; BITMAP "22222222" +803A 02222 ; BITMAP "22222222" +803A 02223 ; BITMAP "22222222" +803A 02224 ; BITMAP "22222222" +803A 02225 ; BITMAP "22222222" +803A 02226 ; BITMAP "22222222" +803A 02227 ; +803A 02228 ; BITMAP "22222222" +803A 02229 ; BITMAP "22222222" +803A 02230 ; BITMAP "22222222" +803A 02231 ; BITMAP "22222222" +803A 02232 ; BITMAP "22222222" +803A 02233 ; BITMAP "22222233" +803A 02234 ; BITMAP "22223333" +803A 02235 ; BITMAP "22333333" +803A 02236 ; +803A 02237 ; BITMAP "22222223" +803A 02238 ; BITMAP "22222333" +803A 02239 ; BITMAP "23223333" +803A 02240 ; BITMAP "23333333" +803A 02241 ; BITMAP "33333333" +803A 02242 ; BITMAP "33333333" +803A 02243 ; BITMAP "33333333" +803A 02244 ; BITMAP "33333333" +803A 02245 ; +803A 02246 ; BITMAP "33333333" +803A 02247 ; BITMAP "33333333" +803A 02248 ; BITMAP "33333333" +803A 02249 ; BITMAP "33333333" +803A 02250 ; BITMAP "33333333" +803A 02251 ; BITMAP "33333333" +803A 02252 ; BITMAP "33333333" +803A 02253 ; BITMAP "33333333" +803A 02254 ; +803A 02255 ; BITMAP "22222222" +803A 02256 ; BITMAP "22222222" +803A 02257 ; BITMAP "22222223" +803A 02258 ; BITMAP "22222233" +803A 02259 ; BITMAP "22222333" +803A 02260 ; BITMAP "22223333" +803A 02261 ; BITMAP "22233333" +803A 02262 ; BITMAP "22333333" +803A 02263 ; +803A 02264 ; BITMAP "23333333" +803A 02265 ; BITMAP "33333333" +803A 02266 ; BITMAP "33333333" +803A 02267 ; BITMAP "33333333" +803A 02268 ; BITMAP "33333333" +803A 02269 ; BITMAP "33333333" +803A 02270 ; BITMAP "33333333" +803A 02271 ; BITMAP "33333333" +803A 02272 ; +803A 02273 ; BITMAP "22222222" +803A 02274 ; BITMAP "22222222" +803A 02275 ; BITMAP "22222222" +803A 02276 ; BITMAP "22222222" +803A 02277 ; BITMAP "22222233" +803A 02278 ; BITMAP "22222233" +803A 02279 ; BITMAP "22222333" +803A 02280 ; BITMAP "22223333" +803A 02281 ; +803A 02282 ; BITMAP "22333333" +803A 02283 ; BITMAP "23333333" +803A 02284 ; BITMAP "33333333" +803A 02285 ; BITMAP "33333333" +803A 02286 ; BITMAP "33333333" +803A 02287 ; BITMAP "33333333" +803A 02288 ; BITMAP "33333333" +803A 02289 ; BITMAP "33333333" +803A 02290 ; +803A 02291 ; BITMAP "22223333" +803A 02292 ; BITMAP "22233333" +803A 02293 ; BITMAP "22233333" +803A 02294 ; BITMAP "22333333" +803A 02295 ; BITMAP "23333333" +803A 02296 ; BITMAP "33333333" +803A 02297 ; BITMAP "33333333" +803A 02298 ; BITMAP "33333333" +803A 02299 ; +803A 02300 ; BITMAP "33333333" +803A 02301 ; BITMAP "33333333" +803A 02302 ; BITMAP "33333333" +803A 02303 ; BITMAP "33333333" +803A 02304 ; BITMAP "33333322" +803A 02305 ; BITMAP "33332222" +803A 02306 ; BITMAP "33322211" +803A 02307 ; BITMAP "33222111" +803A 02308 ; +803A 02309 ; BITMAP "33333333" +803A 02310 ; BITMAP "33333333" +803A 02311 ; BITMAP "33333333" +803A 02312 ; BITMAP "33323333" +803A 02313 ; BITMAP "22222222" +803A 02314 ; BITMAP "11111111" +803A 02315 ; BITMAP "11100111" +803A 02316 ; BITMAP "11111111" +803A 02317 ; +803A 02318 ; BITMAP "33333333" +803A 02319 ; BITMAP "33333333" +803A 02320 ; BITMAP "33333333" +803A 02321 ; BITMAP "33333333" +803A 02322 ; BITMAP "33333333" +803A 02323 ; BITMAP "22333333" +803A 02324 ; BITMAP "11112333" +803A 02325 ; BITMAP "11111223" +803A 02326 ; +803A 02327 ; BITMAP "22222222" +803A 02328 ; BITMAP "22222223" +803A 02329 ; BITMAP "22222233" +803A 02330 ; BITMAP "22222233" +803A 02331 ; BITMAP "22222333" +803A 02332 ; BITMAP "22223333" +803A 02333 ; BITMAP "22223333" +803A 02334 ; BITMAP "22233333" +803A 02335 ; +803A 02336 ; BITMAP "33333333" +803A 02337 ; BITMAP "33333333" +803A 02338 ; BITMAP "33333333" +803A 02339 ; BITMAP "33333333" +803A 02340 ; BITMAP "33333332" +803A 02341 ; BITMAP "33333332" +803A 02342 ; BITMAP "33333322" +803A 02343 ; BITMAP "33333322" +803A 02344 ; +803A 02345 ; BITMAP "33221111" +803A 02346 ; BITMAP "32211111" +803A 02347 ; BITMAP "22211111" +803A 02348 ; BITMAP "22111111" +803A 02349 ; BITMAP "21111111" +803A 02350 ; BITMAP "21111112" +803A 02351 ; BITMAP "11112222" +803A 02352 ; BITMAP "11122222" +803A 02353 ; +803A 02354 ; BITMAP "11111111" +803A 02355 ; BITMAP "11111111" +803A 02356 ; BITMAP "11111111" +803A 02357 ; BITMAP "11111111" +803A 02358 ; BITMAP "11111111" +803A 02359 ; BITMAP "22222221" +803A 02360 ; BITMAP "22222222" +803A 02361 ; BITMAP "22222222" +803A 02362 ; +803A 02363 ; BITMAP "11111112" +803A 02364 ; BITMAP "11111111" +803A 02365 ; BITMAP "11111111" +803A 02366 ; BITMAP "11111111" +803A 02367 ; BITMAP "11111111" +803A 02368 ; BITMAP "11111111" +803A 02369 ; BITMAP "22111111" +803A 02370 ; BITMAP "22221111" +803A 02371 ; +803A 02372 ; BITMAP "22333333" +803A 02373 ; BITMAP "11122333" +803A 02374 ; BITMAP "11000233" +803A 02375 ; BITMAP "11100023" +803A 02376 ; BITMAP "11100001" +803A 02377 ; BITMAP "11100000" +803A 02378 ; BITMAP "11100000" +803A 02379 ; BITMAP "11110000" +803A 02380 ; +803A 02381 ; BITMAP "33333333" +803A 02382 ; BITMAP "33333333" +803A 02383 ; BITMAP "33333333" +803A 02384 ; BITMAP "33333333" +803A 02385 ; BITMAP "33333333" +803A 02386 ; BITMAP "13333333" +803A 02387 ; BITMAP "01333333" +803A 02388 ; BITMAP "00233333" +803A 02389 ; +803A 02390 ; BITMAP "22233333" +803A 02391 ; BITMAP "22333333" +803A 02392 ; BITMAP "22333333" +803A 02393 ; BITMAP "22333333" +803A 02394 ; BITMAP "23333333" +803A 02395 ; BITMAP "23333333" +803A 02396 ; BITMAP "33333333" +803A 02397 ; BITMAP "33333333" +803A 02398 ; +803A 02399 ; BITMAP "33333321" +803A 02400 ; BITMAP "33333321" +803A 02401 ; BITMAP "33333321" +803A 02402 ; BITMAP "33333212" +803A 02403 ; BITMAP "33333212" +803A 02404 ; BITMAP "33333222" +803A 02405 ; BITMAP "33333222" +803A 02406 ; BITMAP "33333222" +803A 02407 ; +803A 02408 ; BITMAP "11222222" +803A 02409 ; BITMAP "12222222" +803A 02410 ; BITMAP "22222222" +803A 02411 ; BITMAP "22222222" +803A 02412 ; BITMAP "22222222" +803A 02413 ; BITMAP "22222222" +803A 02414 ; BITMAP "22222222" +803A 02415 ; BITMAP "22222222" +803A 02416 ; +803A 02417 ; BITMAP "22221111" +803A 02418 ; BITMAP "22222111" +803A 02419 ; BITMAP "22222111" +803A 02420 ; BITMAP "22222211" +803A 02421 ; BITMAP "22222221" +803A 02422 ; BITMAP "22222221" +803A 02423 ; BITMAP "22222221" +803A 02424 ; BITMAP "22222221" +803A 02425 ; +803A 02426 ; BITMAP "11110000" +803A 02427 ; BITMAP "11110000" +803A 02428 ; BITMAP "11111000" +803A 02429 ; BITMAP "11111000" +803A 02430 ; BITMAP "11111000" +803A 02431 ; BITMAP "11111000" +803A 02432 ; BITMAP "11111000" +803A 02433 ; BITMAP "11111100" +803A 02434 ; +803A 02435 ; BITMAP "00033333" +803A 02436 ; BITMAP "00023333" +803A 02437 ; BITMAP "00003333" +803A 02438 ; BITMAP "00002333" +803A 02439 ; BITMAP "00002333" +803A 02440 ; BITMAP "00001333" +803A 02441 ; BITMAP "00000333" +803A 02442 ; BITMAP "00000233" +803A 02443 ; +803A 02444 ; BITMAP "22222222" +803A 02445 ; BITMAP "22222223" +803A 02446 ; BITMAP "22222223" +803A 02447 ; BITMAP "22222233" +803A 02448 ; BITMAP "22222233" +803A 02449 ; BITMAP "22222233" +803A 02450 ; BITMAP "22222333" +803A 02451 ; BITMAP "22222333" +803A 02452 ; +803A 02453 ; BITMAP "33332122" +803A 02454 ; BITMAP "33332122" +803A 02455 ; BITMAP "33332122" +803A 02456 ; BITMAP "33332222" +803A 02457 ; BITMAP "33333122" +803A 02458 ; BITMAP "33333122" +803A 02459 ; BITMAP "33332111" +803A 02460 ; BITMAP "33332111" +803A 02461 ; +803A 02462 ; BITMAP "22222222" +803A 02463 ; BITMAP "22222222" +803A 02464 ; BITMAP "22222222" +803A 02465 ; BITMAP "22222232" +803A 02466 ; BITMAP "22232233" +803A 02467 ; BITMAP "22222222" +803A 02468 ; BITMAP "11122222" +803A 02469 ; BITMAP "11112222" +803A 02470 ; +803A 02471 ; BITMAP "22222222" +803A 02472 ; BITMAP "22222222" +803A 02473 ; BITMAP "22222222" +803A 02474 ; BITMAP "22233333" +803A 02475 ; BITMAP "22233222" +803A 02476 ; BITMAP "22222111" +803A 02477 ; BITMAP "22221110" +803A 02478 ; BITMAP "22221112" +803A 02479 ; +803A 02480 ; BITMAP "22222221" +803A 02481 ; BITMAP "22222211" +803A 02482 ; BITMAP "22222211" +803A 02483 ; BITMAP "32222111" +803A 02484 ; BITMAP "22221111" +803A 02485 ; BITMAP "01111111" +803A 02486 ; BITMAP "11222211" +803A 02487 ; BITMAP "33333222" +803A 02488 ; +803A 02489 ; BITMAP "11111100" +803A 02490 ; BITMAP "11111110" +803A 02491 ; BITMAP "11111110" +803A 02492 ; BITMAP "11111110" +803A 02493 ; BITMAP "11111110" +803A 02494 ; BITMAP "11111110" +803A 02495 ; BITMAP "11110000" +803A 02496 ; BITMAP "11110001" +803A 02497 ; +803A 02498 ; BITMAP "00000233" +803A 02499 ; BITMAP "00000232" +803A 02500 ; BITMAP "00000132" +803A 02501 ; BITMAP "00000122" +803A 02502 ; BITMAP "01110122" +803A 02503 ; BITMAP "11000112" +803A 02504 ; BITMAP "00001111" +803A 02505 ; BITMAP "00001122" +803A 02506 ; +803A 02507 ; BITMAP "33333333" +803A 02508 ; BITMAP "22233333" +803A 02509 ; BITMAP "22222233" +803A 02510 ; BITMAP "22222223" +803A 02511 ; BITMAP "22222222" +803A 02512 ; BITMAP "22222222" +803A 02513 ; BITMAP "22222222" +803A 02514 ; BITMAP "22222222" +803A 02515 ; +803A 02516 ; BITMAP "33333333" +803A 02517 ; BITMAP "33333333" +803A 02518 ; BITMAP "33333333" +803A 02519 ; BITMAP "33333333" +803A 02520 ; BITMAP "33333333" +803A 02521 ; BITMAP "33333333" +803A 02522 ; BITMAP "23333333" +803A 02523 ; BITMAP "23333333" +803A 02524 ; +803A 02525 ; BITMAP "22222333" +803A 02526 ; BITMAP "22222333" +803A 02527 ; BITMAP "22222333" +803A 02528 ; BITMAP "22222333" +803A 02529 ; BITMAP "22222333" +803A 02530 ; BITMAP "22222333" +803A 02531 ; BITMAP "22222333" +803A 02532 ; BITMAP "22223333" +803A 02533 ; +803A 02534 ; BITMAP "33332111" +803A 02535 ; BITMAP "33222122" +803A 02536 ; BITMAP "32321222" +803A 02537 ; BITMAP "32101211" +803A 02538 ; BITMAP "10233110" +803A 02539 ; BITMAP "12333111" +803A 02540 ; BITMAP "33333112" +803A 02541 ; BITMAP "33233122" +803A 02542 ; +803A 02543 ; BITMAP "11111122" +803A 02544 ; BITMAP "22222112" +803A 02545 ; BITMAP "22212111" +803A 02546 ; BITMAP "11110111" +803A 02547 ; BITMAP "22000111" +803A 02548 ; BITMAP "22111101" +803A 02549 ; BITMAP "22222211" +803A 02550 ; BITMAP "22222212" +803A 02551 ; +803A 02552 ; BITMAP "22211222" +803A 02553 ; BITMAP "22211221" +803A 02554 ; BITMAP "22111211" +803A 02555 ; BITMAP "22111121" +803A 02556 ; BITMAP "22111122" +803A 02557 ; BITMAP "22111122" +803A 02558 ; BITMAP "22211122" +803A 02559 ; BITMAP "22211122" +803A 02560 ; +803A 02561 ; BITMAP "33332112" +803A 02562 ; BITMAP "12231001" +803A 02563 ; BITMAP "23110110" +803A 02564 ; BITMAP "22211221" +803A 02565 ; BITMAP "21222222" +803A 02566 ; BITMAP "22222222" +803A 02567 ; BITMAP "22222222" +803A 02568 ; BITMAP "22222222" +803A 02569 ; +803A 02570 ; BITMAP "20011111" +803A 02571 ; BITMAP "11111111" +803A 02572 ; BITMAP "11222111" +803A 02573 ; BITMAP "11222111" +803A 02574 ; BITMAP "21222211" +803A 02575 ; BITMAP "21222211" +803A 02576 ; BITMAP "21222211" +803A 02577 ; BITMAP "12222111" +803A 02578 ; +803A 02579 ; BITMAP "10000222" +803A 02580 ; BITMAP "10001221" +803A 02581 ; BITMAP "10000221" +803A 02582 ; BITMAP "10001121" +803A 02583 ; BITMAP "11001121" +803A 02584 ; BITMAP "11111121" +803A 02585 ; BITMAP "11111121" +803A 02586 ; BITMAP "11101111" +803A 02587 ; +803A 02588 ; BITMAP "23333333" +803A 02589 ; BITMAP "23333333" +803A 02590 ; BITMAP "22333333" +803A 02591 ; BITMAP "22333333" +803A 02592 ; BITMAP "22333333" +803A 02593 ; BITMAP "22233333" +803A 02594 ; BITMAP "22233333" +803A 02595 ; BITMAP "22223333" +803A 02596 ; +803A 02597 ; BITMAP "22223333" +803A 02598 ; BITMAP "22223333" +803A 02599 ; BITMAP "22222333" +803A 02600 ; BITMAP "22223333" +803A 02601 ; BITMAP "22223333" +803A 02602 ; BITMAP "22222333" +803A 02603 ; BITMAP "22222333" +803A 02604 ; BITMAP "22223333" +803A 02605 ; +803A 02606 ; BITMAP "33232122" +803A 02607 ; BITMAP "33322122" +803A 02608 ; BITMAP "33332122" +803A 02609 ; BITMAP "33333211" +803A 02610 ; BITMAP "33333222" +803A 02611 ; BITMAP "33333322" +803A 02612 ; BITMAP "33333322" +803A 02613 ; BITMAP "33333322" +803A 02614 ; +803A 02615 ; BITMAP "22222112" +803A 02616 ; BITMAP "22222122" +803A 02617 ; BITMAP "22221122" +803A 02618 ; BITMAP "12122222" +803A 02619 ; BITMAP "22222222" +803A 02620 ; BITMAP "22222222" +803A 02621 ; BITMAP "22222222" +803A 02622 ; BITMAP "22222222" +803A 02623 ; +803A 02624 ; BITMAP "22221112" +803A 02625 ; BITMAP "22211111" +803A 02626 ; BITMAP "22211112" +803A 02627 ; BITMAP "22211111" +803A 02628 ; BITMAP "22211111" +803A 02629 ; BITMAP "22221211" +803A 02630 ; BITMAP "32222221" +803A 02631 ; BITMAP "22111111" +803A 02632 ; +803A 02633 ; BITMAP "22222222" +803A 02634 ; BITMAP "22222222" +803A 02635 ; BITMAP "22222232" +803A 02636 ; BITMAP "22223332" +803A 02637 ; BITMAP "12222332" +803A 02638 ; BITMAP "12222222" +803A 02639 ; BITMAP "12222222" +803A 02640 ; BITMAP "22222222" +803A 02641 ; +803A 02642 ; BITMAP "12222111" +803A 02643 ; BITMAP "22222111" +803A 02644 ; BITMAP "22222111" +803A 02645 ; BITMAP "22222111" +803A 02646 ; BITMAP "22222111" +803A 02647 ; BITMAP "22222111" +803A 02648 ; BITMAP "22221111" +803A 02649 ; BITMAP "22221111" +803A 02650 ; +803A 02651 ; BITMAP "11101211" +803A 02652 ; BITMAP "11112222" +803A 02653 ; BITMAP "11111112" +803A 02654 ; BITMAP "11111222" +803A 02655 ; BITMAP "11112222" +803A 02656 ; BITMAP "11112222" +803A 02657 ; BITMAP "11112222" +803A 02658 ; BITMAP "11112222" +803A 02659 ; +803A 02660 ; BITMAP "22223333" +803A 02661 ; BITMAP "22222333" +803A 02662 ; BITMAP "22222333" +803A 02663 ; BITMAP "22222233" +803A 02664 ; BITMAP "22222233" +803A 02665 ; BITMAP "22222223" +803A 02666 ; BITMAP "22222222" +803A 02667 ; BITMAP "22222222" +803A 02668 ; +803A 02669 ; BITMAP "33333333" +803A 02670 ; BITMAP "33333333" +803A 02671 ; BITMAP "33333333" +803A 02672 ; BITMAP "33333333" +803A 02673 ; BITMAP "33333333" +803A 02674 ; BITMAP "33333333" +803A 02675 ; BITMAP "33333333" +803A 02676 ; BITMAP "22333333" +803A 02677 ; +803A 02678 ; BITMAP "22223333" +803A 02679 ; BITMAP "22222333" +803A 02680 ; BITMAP "22222333" +803A 02681 ; BITMAP "22222333" +803A 02682 ; BITMAP "22222333" +803A 02683 ; BITMAP "22222233" +803A 02684 ; BITMAP "22222333" +803A 02685 ; BITMAP "22222333" +803A 02686 ; +803A 02687 ; BITMAP "33333332" +803A 02688 ; BITMAP "33333333" +803A 02689 ; BITMAP "33333333" +803A 02690 ; BITMAP "33333333" +803A 02691 ; BITMAP "33333333" +803A 02692 ; BITMAP "33333333" +803A 02693 ; BITMAP "33333333" +803A 02694 ; BITMAP "33333333" +803A 02695 ; +803A 02696 ; BITMAP "22222222" +803A 02697 ; BITMAP "22222212" +803A 02698 ; BITMAP "22222222" +803A 02699 ; BITMAP "22222222" +803A 02700 ; BITMAP "32222222" +803A 02701 ; BITMAP "32222111" +803A 02702 ; BITMAP "33222211" +803A 02703 ; BITMAP "33222222" +803A 02704 ; +803A 02705 ; BITMAP "22112222" +803A 02706 ; BITMAP "22222222" +803A 02707 ; BITMAP "22222222" +803A 02708 ; BITMAP "22222222" +803A 02709 ; BITMAP "22222211" +803A 02710 ; BITMAP "11111111" +803A 02711 ; BITMAP "11111111" +803A 02712 ; BITMAP "11222222" +803A 02713 ; +803A 02714 ; BITMAP "22222222" +803A 02715 ; BITMAP "22222222" +803A 02716 ; BITMAP "22222222" +803A 02717 ; BITMAP "22111222" +803A 02718 ; BITMAP "11112222" +803A 02719 ; BITMAP "11222222" +803A 02720 ; BITMAP "22222222" +803A 02721 ; BITMAP "22222222" +803A 02722 ; +803A 02723 ; BITMAP "22221211" +803A 02724 ; BITMAP "22222211" +803A 02725 ; BITMAP "22222211" +803A 02726 ; BITMAP "22222211" +803A 02727 ; BITMAP "22222211" +803A 02728 ; BITMAP "22222211" +803A 02729 ; BITMAP "22222211" +803A 02730 ; BITMAP "22222111" +803A 02731 ; +803A 02732 ; BITMAP "11112222" +803A 02733 ; BITMAP "11112222" +803A 02734 ; BITMAP "11112222" +803A 02735 ; BITMAP "11112222" +803A 02736 ; BITMAP "11112222" +803A 02737 ; BITMAP "11112222" +803A 02738 ; BITMAP "11112222" +803A 02739 ; BITMAP "11101222" +803A 02740 ; +803A 02741 ; BITMAP "22233333" +803A 02742 ; BITMAP "22223333" +803A 02743 ; BITMAP "22222233" +803A 02744 ; BITMAP "22222222" +803A 02745 ; BITMAP "22222222" +803A 02746 ; BITMAP "22222222" +803A 02747 ; BITMAP "22222222" +803A 02748 ; BITMAP "22222222" +803A 02749 ; +803A 02750 ; BITMAP "33333333" +803A 02751 ; BITMAP "33333333" +803A 02752 ; BITMAP "33333333" +803A 02753 ; BITMAP "33333333" +803A 02754 ; BITMAP "22333333" +803A 02755 ; BITMAP "22223333" +803A 02756 ; BITMAP "22222333" +803A 02757 ; BITMAP "22222233" +803A 02758 ; +803A 02759 ; BITMAP "22222333" +803A 02760 ; BITMAP "22222333" +803A 02761 ; BITMAP "22222233" +803A 02762 ; BITMAP "22222333" +803A 02763 ; BITMAP "22222333" +803A 02764 ; BITMAP "22222333" +803A 02765 ; BITMAP "22222333" +803A 02766 ; BITMAP "22222233" +803A 02767 ; +803A 02768 ; BITMAP "33322222" +803A 02769 ; BITMAP "33322222" +803A 02770 ; BITMAP "33332222" +803A 02771 ; BITMAP "33332122" +803A 02772 ; BITMAP "33333222" +803A 02773 ; BITMAP "33333212" +803A 02774 ; BITMAP "33333322" +803A 02775 ; BITMAP "33333332" +803A 02776 ; +803A 02777 ; BITMAP "22222222" +803A 02778 ; BITMAP "22222222" +803A 02779 ; BITMAP "22222222" +803A 02780 ; BITMAP "22222222" +803A 02781 ; BITMAP "22222112" +803A 02782 ; BITMAP "22221112" +803A 02783 ; BITMAP "22211111" +803A 02784 ; BITMAP "22211111" +803A 02785 ; +803A 02786 ; BITMAP "22222111" +803A 02787 ; BITMAP "22221111" +803A 02788 ; BITMAP "22211111" +803A 02789 ; BITMAP "22111111" +803A 02790 ; BITMAP "21111111" +803A 02791 ; BITMAP "11111112" +803A 02792 ; BITMAP "11211132" +803A 02793 ; BITMAP "11112321" +803A 02794 ; +803A 02795 ; BITMAP "11001222" +803A 02796 ; BITMAP "11001222" +803A 02797 ; BITMAP "10101222" +803A 02798 ; BITMAP "11102212" +803A 02799 ; BITMAP "21112112" +803A 02800 ; BITMAP "11022022" +803A 02801 ; BITMAP "01132022" +803A 02802 ; BITMAP "10231132" +803A 02803 ; +803A 02804 ; BITMAP "22222222" +803A 02805 ; BITMAP "22222222" +803A 02806 ; BITMAP "22222222" +803A 02807 ; BITMAP "22222222" +803A 02808 ; BITMAP "22222222" +803A 02809 ; BITMAP "22222222" +803A 02810 ; BITMAP "12222222" +803A 02811 ; BITMAP "00122222" +803A 02812 ; +803A 02813 ; BITMAP "22222333" +803A 02814 ; BITMAP "22222233" +803A 02815 ; BITMAP "22222233" +803A 02816 ; BITMAP "22222333" +803A 02817 ; BITMAP "22222233" +803A 02818 ; BITMAP "22222233" +803A 02819 ; BITMAP "22222233" +803A 02820 ; BITMAP "22222233" +803A 02821 ; +803A 02822 ; BITMAP "33333333" +803A 02823 ; BITMAP "33333333" +803A 02824 ; BITMAP "33333333" +803A 02825 ; BITMAP "33333333" +803A 02826 ; BITMAP "33333333" +803A 02827 ; BITMAP "33333321" +803A 02828 ; BITMAP "33333100" +803A 02829 ; BITMAP "33321010" +803A 02830 ; +803A 02831 ; BITMAP "33333332" +803A 02832 ; BITMAP "33333211" +803A 02833 ; BITMAP "33321002" +803A 02834 ; BITMAP "32100112" +803A 02835 ; BITMAP "20011122" +803A 02836 ; BITMAP "00111123" +803A 02837 ; BITMAP "10110232" +803A 02838 ; BITMAP "01111322" +803A 02839 ; +803A 02840 ; BITMAP "22222222" +803A 02841 ; BITMAP "22222222" +803A 02842 ; BITMAP "22111111" +803A 02843 ; BITMAP "22111111" +803A 02844 ; BITMAP "22122222" +803A 02845 ; BITMAP "22112222" +803A 02846 ; BITMAP "21012222" +803A 02847 ; BITMAP "21012222" +803A 02848 ; +803A 02849 ; BITMAP "22111111" +803A 02850 ; BITMAP "21111111" +803A 02851 ; BITMAP "11111222" +803A 02852 ; BITMAP "12222222" +803A 02853 ; BITMAP "22222222" +803A 02854 ; BITMAP "22222222" +803A 02855 ; BITMAP "22222223" +803A 02856 ; BITMAP "22222233" +803A 02857 ; +803A 02858 ; BITMAP "11223311" +803A 02859 ; BITMAP "22223201" +803A 02860 ; BITMAP "22232110" +803A 02861 ; BITMAP "22331102" +803A 02862 ; BITMAP "23321113" +803A 02863 ; BITMAP "33211023" +803A 02864 ; BITMAP "33110233" +803A 02865 ; BITMAP "32011332" +803A 02866 ; +803A 02867 ; BITMAP "02320231" +803A 02868 ; BITMAP "13311320" +803A 02869 ; BITMAP "23202310" +803A 02870 ; BITMAP "33013201" +803A 02871 ; BITMAP "31033101" +803A 02872 ; BITMAP "20232010" +803A 02873 ; BITMAP "11331010" +803A 02874 ; BITMAP "02320110" +803A 02875 ; +803A 02876 ; BITMAP "00012222" +803A 02877 ; BITMAP "00012222" +803A 02878 ; BITMAP "00000112" +803A 02879 ; BITMAP "00000001" +803A 02880 ; BITMAP "00000000" +803A 02881 ; BITMAP "11000000" +803A 02882 ; BITMAP "00000000" +803A 02883 ; BITMAP "00000000" +803A 02884 ; +803A 02885 ; BITMAP "22222222" +803A 02886 ; BITMAP "22222222" +803A 02887 ; BITMAP "22222222" +803A 02888 ; BITMAP "12222222" +803A 02889 ; BITMAP "01222222" +803A 02890 ; BITMAP "00122222" +803A 02891 ; BITMAP "00012222" +803A 02892 ; BITMAP "00000112" +803A 02893 ; +803A 02894 ; BITMAP "22222223" +803A 02895 ; BITMAP "22222223" +803A 02896 ; BITMAP "22222222" +803A 02897 ; BITMAP "22222222" +803A 02898 ; BITMAP "22222222" +803A 02899 ; BITMAP "22222222" +803A 02900 ; BITMAP "22222222" +803A 02901 ; BITMAP "22222222" +803A 02902 ; +803A 02903 ; BITMAP "33333333" +803A 02904 ; BITMAP "33333333" +803A 02905 ; BITMAP "33333333" +803A 02906 ; BITMAP "33333331" +803A 02907 ; BITMAP "33333210" +803A 02908 ; BITMAP "23333111" +803A 02909 ; BITMAP "22232111" +803A 02910 ; BITMAP "22331110" +803A 02911 ; +803A 02912 ; BITMAP "33200100" +803A 02913 ; BITMAP "32011001" +803A 02914 ; BITMAP "10110011" +803A 02915 ; BITMAP "01110011" +803A 02916 ; BITMAP "11100111" +803A 02917 ; BITMAP "11101110" +803A 02918 ; BITMAP "01011111" +803A 02919 ; BITMAP "11111101" +803A 02920 ; +803A 02921 ; BITMAP "11102322" +803A 02922 ; BITMAP "11112322" +803A 02923 ; BITMAP "01123322" +803A 02924 ; BITMAP "11123222" +803A 02925 ; BITMAP "11132222" +803A 02926 ; BITMAP "21022222" +803A 02927 ; BITMAP "21122222" +803A 02928 ; BITMAP "20022122" +803A 02929 ; +803A 02930 ; BITMAP "21012222" +803A 02931 ; BITMAP "21012222" +803A 02932 ; BITMAP "21011222" +803A 02933 ; BITMAP "21011222" +803A 02934 ; BITMAP "21011222" +803A 02935 ; BITMAP "11011222" +803A 02936 ; BITMAP "22011222" +803A 02937 ; BITMAP "22101232" +803A 02938 ; +803A 02939 ; BITMAP "22222333" +803A 02940 ; BITMAP "22223333" +803A 02941 ; BITMAP "22233332" +803A 02942 ; BITMAP "22333331" +803A 02943 ; BITMAP "23333311" +803A 02944 ; BITMAP "22223211" +803A 02945 ; BITMAP "22222110" +803A 02946 ; BITMAP "22221112" +803A 02947 ; +803A 02948 ; BITMAP "21102320" +803A 02949 ; BITMAP "11023310" +803A 02950 ; BITMAP "01133202" +803A 02951 ; BITMAP "10232013" +803A 02952 ; BITMAP "02331023" +803A 02953 ; BITMAP "13320233" +803A 02954 ; BITMAP "23301331" +803A 02955 ; BITMAP "33102320" +803A 02956 ; +803A 02957 ; BITMAP "13201001" +803A 02958 ; BITMAP "33101000" +803A 02959 ; BITMAP "32011000" +803A 02960 ; BITMAP "31010000" +803A 02961 ; BITMAP "20100010" +803A 02962 ; BITMAP "01100110" +803A 02963 ; BITMAP "01000000" +803A 02964 ; BITMAP "11001100" +803A 02965 ; +803A 02966 ; BITMAP "00000000" +803A 02967 ; BITMAP "00000000" +803A 02968 ; BITMAP "00000000" +803A 02969 ; BITMAP "00000000" +803A 02970 ; BITMAP "00000000" +803A 02971 ; BITMAP "00000000" +803A 02972 ; BITMAP "00000000" +803A 02973 ; BITMAP "00000000" +803A 02974 ; +803A 02975 ; BITMAP "00000001" +803A 02976 ; BITMAP "00000000" +803A 02977 ; BITMAP "00000000" +803A 02978 ; BITMAP "00000000" +803A 02979 ; BITMAP "00000000" +803A 02980 ; BITMAP "00000000" +803A 02981 ; BITMAP "00000000" +803A 02982 ; BITMAP "00000000" +803A 02983 ; +803A 02984 ; BITMAP "22222222" +803A 02985 ; BITMAP "01222222" +803A 02986 ; BITMAP "00122222" +803A 02987 ; BITMAP "00012222" +803A 02988 ; BITMAP "00001222" +803A 02989 ; BITMAP "00000122" +803A 02990 ; BITMAP "00000112" +803A 02991 ; BITMAP "00000000" +803A 02992 ; +803A 02993 ; BITMAP "22222222" +803A 02994 ; BITMAP "22222222" +803A 02995 ; BITMAP "22222222" +803A 02996 ; BITMAP "22222222" +803A 02997 ; BITMAP "22222222" +803A 02998 ; BITMAP "22222222" +803A 02999 ; BITMAP "22222222" +803A 03000 ; BITMAP "11222222" +803A 03001 ; +803A 03002 ; BITMAP "22321110" +803A 03003 ; BITMAP "22321100" +803A 03004 ; BITMAP "22321100" +803A 03005 ; BITMAP "22311100" +803A 03006 ; BITMAP "23311101" +803A 03007 ; BITMAP "23310101" +803A 03008 ; BITMAP "23310111" +803A 03009 ; BITMAP "23320111" +803A 03010 ; +803A 03011 ; BITMAP "10111102" +803A 03012 ; BITMAP "01111112" +803A 03013 ; BITMAP "11111112" +803A 03014 ; BITMAP "11111112" +803A 03015 ; BITMAP "11111022" +803A 03016 ; BITMAP "11111121" +803A 03017 ; BITMAP "11111121" +803A 03018 ; BITMAP "11111111" +803A 03019 ; +803A 03020 ; BITMAP "20023112" +803A 03021 ; BITMAP "10013212" +803A 03022 ; BITMAP "10001222" +803A 03023 ; BITMAP "00001222" +803A 03024 ; BITMAP "00001222" +803A 03025 ; BITMAP "00001222" +803A 03026 ; BITMAP "00012223" +803A 03027 ; BITMAP "00012233" +803A 03028 ; +803A 03029 ; BITMAP "22201322" +803A 03030 ; BITMAP "22201322" +803A 03031 ; BITMAP "22222223" +803A 03032 ; BITMAP "22222333" +803A 03033 ; BITMAP "22222332" +803A 03034 ; BITMAP "32222322" +803A 03035 ; BITMAP "33212221" +803A 03036 ; BITMAP "33202101" +803A 03037 ; +803A 03038 ; BITMAP "22221113" +803A 03039 ; BITMAP "22211023" +803A 03040 ; BITMAP "22111233" +803A 03041 ; BITMAP "21111332" +803A 03042 ; BITMAP "11103331" +803A 03043 ; BITMAP "11023310" +803A 03044 ; BITMAP "10233201" +803A 03045 ; BITMAP "02332013" +803A 03046 ; +803A 03047 ; BITMAP "32013310" +803A 03048 ; BITMAP "31133201" +803A 03049 ; BITMAP "20233011" +803A 03050 ; BITMAP "01331011" +803A 03051 ; BITMAP "03320111" +803A 03052 ; BITMAP "23311110" +803A 03053 ; BITMAP "33211000" +803A 03054 ; BITMAP "32111111" +803A 03055 ; +803A 03056 ; BITMAP "11111000" +803A 03057 ; BITMAP "11111000" +803A 03058 ; BITMAP "11110000" +803A 03059 ; BITMAP "11000000" +803A 03060 ; BITMAP "00000000" +803A 03061 ; BITMAP "00000000" +803A 03062 ; BITMAP "00000001" +803A 03063 ; BITMAP "00000001" +803A 03064 ; +803A 03065 ; BITMAP "00000000" +803A 03066 ; BITMAP "00000000" +803A 03067 ; BITMAP "00000000" +803A 03068 ; BITMAP "00000000" +803A 03069 ; BITMAP "11000000" +803A 03070 ; BITMAP "11000000" +803A 03071 ; BITMAP "11100000" +803A 03072 ; BITMAP "11100000" +803A 03073 ; +803A 03074 ; BITMAP "00012222" +803A 03075 ; BITMAP "00000122" +803A 03076 ; BITMAP "00000002" +803A 03077 ; BITMAP "00000000" +803A 03078 ; BITMAP "00000000" +803A 03079 ; BITMAP "00000000" +803A 03080 ; BITMAP "00000000" +803A 03081 ; BITMAP "00000000" +803A 03082 ; +803A 03083 ; BITMAP "23310111" +803A 03084 ; BITMAP "23301111" +803A 03085 ; BITMAP "23201111" +803A 03086 ; BITMAP "23111111" +803A 03087 ; BITMAP "22111111" +803A 03088 ; BITMAP "22011111" +803A 03089 ; BITMAP "21111111" +803A 03090 ; BITMAP "21111111" +803A 03091 ; +803A 03092 ; BITMAP "11111111" +803A 03093 ; BITMAP "11111110" +803A 03094 ; BITMAP "11111110" +803A 03095 ; BITMAP "11101110" +803A 03096 ; BITMAP "11101110" +803A 03097 ; BITMAP "11011100" +803A 03098 ; BITMAP "11011100" +803A 03099 ; BITMAP "10011100" +803A 03100 ; +803A 03101 ; BITMAP "00012333" +803A 03102 ; BITMAP "00123333" +803A 03103 ; BITMAP "00123333" +803A 03104 ; BITMAP "01223333" +803A 03105 ; BITMAP "01223333" +803A 03106 ; BITMAP "01233333" +803A 03107 ; BITMAP "12233333" +803A 03108 ; BITMAP "12333332" +803A 03109 ; +803A 03110 ; BITMAP "33201110" +803A 03111 ; BITMAP "33201102" +803A 03112 ; BITMAP "33111123" +803A 03113 ; BITMAP "32111122" +803A 03114 ; BITMAP "21111100" +803A 03115 ; BITMAP "21111011" +803A 03116 ; BITMAP "11123201" +803A 03117 ; BITMAP "11133311" +803A 03118 ; +803A 03119 ; BITMAP "23331122" +803A 03120 ; BITMAP "33201110" +803A 03121 ; BITMAP "32111111" +803A 03122 ; BITMAP "11111111" +803A 03123 ; BITMAP "11111111" +803A 03124 ; BITMAP "11111111" +803A 03125 ; BITMAP "11111111" +803A 03126 ; BITMAP "11111111" +803A 03127 ; +803A 03128 ; BITMAP "10111111" +803A 03129 ; BITMAP "11111111" +803A 03130 ; BITMAP "11101111" +803A 03131 ; BITMAP "11111111" +803A 03132 ; BITMAP "11111111" +803A 03133 ; BITMAP "11111111" +803A 03134 ; BITMAP "11111111" +803A 03135 ; BITMAP "11111111" +803A 03136 ; +803A 03137 ; BITMAP "10000001" +803A 03138 ; BITMAP "11100001" +803A 03139 ; BITMAP "11111001" +803A 03140 ; BITMAP "11111001" +803A 03141 ; BITMAP "11111001" +803A 03142 ; BITMAP "11111011" +803A 03143 ; BITMAP "11110011" +803A 03144 ; BITMAP "11100011" +803A 03145 ; +803A 03146 ; BITMAP "11110000" +803A 03147 ; BITMAP "11110000" +803A 03148 ; BITMAP "11110000" +803A 03149 ; BITMAP "11111000" +803A 03150 ; BITMAP "11111000" +803A 03151 ; BITMAP "11111000" +803A 03152 ; BITMAP "11111100" +803A 03153 ; BITMAP "11111100" +803A 03154 ; +803A 03155 ; BITMAP "00000000" +803A 03156 ; BITMAP "00000001" +803A 03157 ; BITMAP "00000012" +803A 03158 ; BITMAP "00000222" +803A 03159 ; BITMAP "00002322" +803A 03160 ; BITMAP "00013332" +803A 03161 ; BITMAP "00023333" +803A 03162 ; BITMAP "00133333" +803A 03163 ; +803A 03164 ; BITMAP "22222222" +803A 03165 ; BITMAP "22222222" +803A 03166 ; BITMAP "22222222" +803A 03167 ; BITMAP "22222222" +803A 03168 ; BITMAP "22222221" +803A 03169 ; BITMAP "22222221" +803A 03170 ; BITMAP "22222210" +803A 03171 ; BITMAP "22222211" +803A 03172 ; +803A 03173 ; BITMAP "21111111" +803A 03174 ; BITMAP "11111111" +803A 03175 ; BITMAP "11111111" +803A 03176 ; BITMAP "11111111" +803A 03177 ; BITMAP "11111111" +803A 03178 ; BITMAP "11111111" +803A 03179 ; BITMAP "11111110" +803A 03180 ; BITMAP "11111110" +803A 03181 ; +803A 03182 ; BITMAP "10111001" +803A 03183 ; BITMAP "11111001" +803A 03184 ; BITMAP "11111012" +803A 03185 ; BITMAP "11110012" +803A 03186 ; BITMAP "11110122" +803A 03187 ; BITMAP "11110122" +803A 03188 ; BITMAP "11101222" +803A 03189 ; BITMAP "11001123" +803A 03190 ; +803A 03191 ; BITMAP "23333222" +803A 03192 ; BITMAP "23332232" +803A 03193 ; BITMAP "23223331" +803A 03194 ; BITMAP "32233321" +803A 03195 ; BITMAP "22333321" +803A 03196 ; BITMAP "23333321" +803A 03197 ; BITMAP "33332211" +803A 03198 ; BITMAP "33332211" +803A 03199 ; +803A 03200 ; BITMAP "11133311" +803A 03201 ; BITMAP "11112101" +803A 03202 ; BITMAP "11110111" +803A 03203 ; BITMAP "11111111" +803A 03204 ; BITMAP "11111111" +803A 03205 ; BITMAP "11111111" +803A 03206 ; BITMAP "11111111" +803A 03207 ; BITMAP "11111111" +803A 03208 ; +803A 03209 ; BITMAP "11111111" +803A 03210 ; BITMAP "11111111" +803A 03211 ; BITMAP "11111111" +803A 03212 ; BITMAP "11110111" +803A 03213 ; BITMAP "11100111" +803A 03214 ; BITMAP "11101111" +803A 03215 ; BITMAP "11001111" +803A 03216 ; BITMAP "10011111" +803A 03217 ; +803A 03218 ; BITMAP "11111111" +803A 03219 ; BITMAP "11111111" +803A 03220 ; BITMAP "11111111" +803A 03221 ; BITMAP "11111111" +803A 03222 ; BITMAP "11111111" +803A 03223 ; BITMAP "11111111" +803A 03224 ; BITMAP "11111111" +803A 03225 ; BITMAP "11111111" +803A 03226 ; +803A 03227 ; BITMAP "11100011" +803A 03228 ; BITMAP "11000111" +803A 03229 ; BITMAP "11000111" +803A 03230 ; BITMAP "11000111" +803A 03231 ; BITMAP "11000111" +803A 03232 ; BITMAP "11001111" +803A 03233 ; BITMAP "10001111" +803A 03234 ; BITMAP "10001111" +803A 03235 ; +803A 03236 ; BITMAP "11111110" +803A 03237 ; BITMAP "11111110" +803A 03238 ; BITMAP "11111111" +803A 03239 ; BITMAP "11111111" +803A 03240 ; BITMAP "11111111" +803A 03241 ; BITMAP "11111111" +803A 03242 ; BITMAP "11111111" +803A 03243 ; BITMAP "11111111" +803A 03244 ; +803A 03245 ; BITMAP "00000000" +803A 03246 ; BITMAP "00000000" +803A 03247 ; BITMAP "00000000" +803A 03248 ; BITMAP "00000000" +803A 03249 ; BITMAP "10000000" +803A 03250 ; BITMAP "10000000" +803A 03251 ; BITMAP "10000000" +803A 03252 ; BITMAP "11000000" +803A 03253 ; +803A 03254 ; BITMAP "00000000" +803A 03255 ; BITMAP "00000000" +803A 03256 ; BITMAP "00000000" +803A 03257 ; BITMAP "00000000" +803A 03258 ; BITMAP "00000000" +803A 03259 ; BITMAP "00100000" +803A 03260 ; BITMAP "00100001" +803A 03261 ; BITMAP "00101102" +803A 03262 ; +803A 03263 ; BITMAP "00233333" +803A 03264 ; BITMAP "01333323" +803A 03265 ; BITMAP "02333323" +803A 03266 ; BITMAP "13333223" +803A 03267 ; BITMAP "23333223" +803A 03268 ; BITMAP "23333223" +803A 03269 ; BITMAP "33332233" +803A 03270 ; BITMAP "33332233" +803A 03271 ; +803A 03272 ; +803A 03273 ; ' Width = 12, height = 16 +803A 03274 ; image_pattern: +803A 03275 CVB_IMAGE_PATTERN: +803A 03276 ; DATA BYTE $80,$81,$81,$81,$82,$83,$84,$84,$84,$84,$84,$84 +803A 8081818182838484 03277 DB $80,$81,$81,$81,$82,$83,$84,$84 +8042 84848484 03278 DB $84,$84,$84,$84 +8046 03279 ; DATA BYTE $81,$81,$81,$85,$86,$84,$84,$84,$84,$84,$84,$84 +8046 8181818586848484 03280 DB $81,$81,$81,$85,$86,$84,$84,$84 +804E 84848484 03281 DB $84,$84,$84,$84 +8052 03282 ; DATA BYTE $81,$81,$87,$88,$84,$84,$84,$84,$84,$84,$84,$84 +8052 8181878884848484 03283 DB $81,$81,$87,$88,$84,$84,$84,$84 +805A 84848484 03284 DB $84,$84,$84,$84 +805E 03285 ; DATA BYTE $81,$81,$89,$8a,$8b,$8c,$84,$84,$84,$84,$84,$84 +805E 8181898A8B8C8484 03286 DB $81,$81,$89,$8A,$8B,$8C,$84,$84 +8066 84848484 03287 DB $84,$84,$84,$84 +806A 03288 ; DATA BYTE $81,$8d,$8e,$8f,$90,$91,$92,$93,$84,$84,$84,$84 +806A 818D8E8F90919293 03289 DB $81,$8D,$8E,$8F,$90,$91,$92,$93 +8072 84848484 03290 DB $84,$84,$84,$84 +8076 03291 ; DATA BYTE $81,$94,$95,$96,$81,$97,$98,$99,$84,$84,$84,$84 +8076 8194959681979899 03292 DB $81,$94,$95,$96,$81,$97,$98,$99 +807E 84848484 03293 DB $84,$84,$84,$84 +8082 03294 ; DATA BYTE $9a,$84,$9b,$9c,$9d,$9e,$9f,$a0,$a1,$a2,$84,$84 +8082 9A849B9C9D9E9FA0 03295 DB $9A,$84,$9B,$9C,$9D,$9E,$9F,$A0 +808A A1A28484 03296 DB $A1,$A2,$84,$84 +808E 03297 ; DATA BYTE $a3,$84,$a4,$a5,$a6,$a7,$a8,$a9,$81,$aa,$84,$84 +808E A384A4A5A6A7A8A9 03298 DB $A3,$84,$A4,$A5,$A6,$A7,$A8,$A9 +8096 81AA8484 03299 DB $81,$AA,$84,$84 +809A 03300 ; DATA BYTE $ab,$84,$ac,$ad,$ae,$af,$b0,$b1,$81,$b2,$b3,$84 +809A AB84ACADAEAFB0B1 03301 DB $AB,$84,$AC,$AD,$AE,$AF,$B0,$B1 +80A2 81B2B384 03302 DB $81,$B2,$B3,$84 +80A6 03303 ; DATA BYTE $b4,$84,$b5,$b6,$b7,$b8,$b9,$ba,$81,$81,$bb,$bc +80A6 B484B5B6B7B8B9BA 03304 DB $B4,$84,$B5,$B6,$B7,$B8,$B9,$BA +80AE 8181BBBC 03305 DB $81,$81,$BB,$BC +80B2 03306 ; DATA BYTE $bd,$84,$84,$be,$81,$bf,$c0,$c1,$c2,$81,$81,$81 +80B2 BD8484BE81BFC0C1 03307 DB $BD,$84,$84,$BE,$81,$BF,$C0,$C1 +80BA C2818181 03308 DB $C2,$81,$81,$81 +80BE 03309 ; DATA BYTE $c3,$84,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$81,$81 +80BE C384C4C5C6C7C8C9 03310 DB $C3,$84,$C4,$C5,$C6,$C7,$C8,$C9 +80C6 CACB8181 03311 DB $CA,$CB,$81,$81 +80CA 03312 ; DATA BYTE $cc,$cd,$ce,$cf,$d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7 +80CA CCCDCECFD0D1D2D3 03313 DB $CC,$CD,$CE,$CF,$D0,$D1,$D2,$D3 +80D2 D4D5D6D7 03314 DB $D4,$D5,$D6,$D7 +80D6 03315 ; DATA BYTE $81,$d8,$d9,$da,$db,$dc,$dd,$de,$df,$d4,$d4,$e0 +80D6 81D8D9DADBDCDDDE 03316 DB $81,$D8,$D9,$DA,$DB,$DC,$DD,$DE +80DE DFD4D4E0 03317 DB $DF,$D4,$D4,$E0 +80E2 03318 ; DATA BYTE $81,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$d4,$d4,$e9 +80E2 81E1E2E3E4E5E6E7 03319 DB $81,$E1,$E2,$E3,$E4,$E5,$E6,$E7 +80EA E8D4D4E9 03320 DB $E8,$D4,$D4,$E9 +80EE 03321 ; DATA BYTE $ea,$eb,$ec,$ed,$ee,$ef,$f0,$f1,$f2,$f3,$f4,$f5 +80EE EAEBECEDEEEFF0F1 03322 DB $EA,$EB,$EC,$ED,$EE,$EF,$F0,$F1 +80F6 F2F3F4F5 03323 DB $F2,$F3,$F4,$F5 +80FA 03324 BANK_2_FREE: EQU $BFFF-$ +80FA FFFFFFFFFFFFFFFF 03325 TIMES $BFFF-$ DB $FF +BFFF 01 03326 DB $01 +C000 03327 ROM_END: +C000 03328 IF CVBASIC_BANK_SWITCHING + 03329 FORG CVBASIC_BANK_ROM_SIZE*1024+16-6 ; Go to final of ROM minus vectors + 03330 ELSE + 03331 TIMES $FFFA-$ DB $FF + 03332 ENDIF + 03333 +0000 E3C2 03334 DW NMI_HANDLER +0002 2BC9 03335 DW START +0004 E2C2 03336 DW IRQ_HANDLER +0006 03337 + 03338 FORG $34010 + 03339 +8000 03340 ORG $8000 +8000 03341 +8000 03342 ; CHR data +8000 0000000000000000 03343 DB $00,$00,$00,$00,$00,$00,$00,$00 +8008 0000000000000000 03344 DB $00,$00,$00,$00,$00,$00,$00,$00 +8010 0000000000000000 03345 DB $00,$00,$00,$00,$00,$00,$00,$00 +8018 0000000000000000 03346 DB $00,$00,$00,$00,$00,$00,$00,$00 +8020 0000000000000000 03347 DB $00,$00,$00,$00,$00,$00,$00,$00 +8028 0000000000000000 03348 DB $00,$00,$00,$00,$00,$00,$00,$00 +8030 0000000000000000 03349 DB $00,$00,$00,$00,$00,$00,$00,$00 +8038 0000000000000000 03350 DB $00,$00,$00,$00,$00,$00,$00,$00 +8040 0000000000000000 03351 DB $00,$00,$00,$00,$00,$00,$00,$00 +8048 0000000000000000 03352 DB $00,$00,$00,$00,$00,$00,$00,$00 +8050 0000000000000000 03353 DB $00,$00,$00,$00,$00,$00,$00,$00 +8058 0000000000000000 03354 DB $00,$00,$00,$00,$00,$00,$00,$00 +8060 0000000000000000 03355 DB $00,$00,$00,$00,$00,$00,$00,$00 +8068 0000000000000000 03356 DB $00,$00,$00,$00,$00,$00,$00,$00 +8070 0000000000000000 03357 DB $00,$00,$00,$00,$00,$00,$00,$00 +8078 0000000000000000 03358 DB $00,$00,$00,$00,$00,$00,$00,$00 +8080 0000000000000000 03359 DB $00,$00,$00,$00,$00,$00,$00,$00 +8088 0000000000000000 03360 DB $00,$00,$00,$00,$00,$00,$00,$00 +8090 0000000000000000 03361 DB $00,$00,$00,$00,$00,$00,$00,$00 +8098 0000000000000000 03362 DB $00,$00,$00,$00,$00,$00,$00,$00 +80A0 0000000000000000 03363 DB $00,$00,$00,$00,$00,$00,$00,$00 +80A8 0000000000000000 03364 DB $00,$00,$00,$00,$00,$00,$00,$00 +80B0 0000000000000000 03365 DB $00,$00,$00,$00,$00,$00,$00,$00 +80B8 0000000000000000 03366 DB $00,$00,$00,$00,$00,$00,$00,$00 +80C0 0000000000000000 03367 DB $00,$00,$00,$00,$00,$00,$00,$00 +80C8 0000000000000000 03368 DB $00,$00,$00,$00,$00,$00,$00,$00 +80D0 0000000000000000 03369 DB $00,$00,$00,$00,$00,$00,$00,$00 +80D8 0000000000000000 03370 DB $00,$00,$00,$00,$00,$00,$00,$00 +80E0 0000000000000000 03371 DB $00,$00,$00,$00,$00,$00,$00,$00 +80E8 0000000000000000 03372 DB $00,$00,$00,$00,$00,$00,$00,$00 +80F0 0000000000000000 03373 DB $00,$00,$00,$00,$00,$00,$00,$00 +80F8 0000000000000000 03374 DB $00,$00,$00,$00,$00,$00,$00,$00 +8100 0000000000000000 03375 DB $00,$00,$00,$00,$00,$00,$00,$00 +8108 0000000000000000 03376 DB $00,$00,$00,$00,$00,$00,$00,$00 +8110 0000000000000000 03377 DB $00,$00,$00,$00,$00,$00,$00,$00 +8118 0000000000000000 03378 DB $00,$00,$00,$00,$00,$00,$00,$00 +8120 0000000000000000 03379 DB $00,$00,$00,$00,$00,$00,$00,$00 +8128 0000000000000000 03380 DB $00,$00,$00,$00,$00,$00,$00,$00 +8130 0000000000000000 03381 DB $00,$00,$00,$00,$00,$00,$00,$00 +8138 0000000000000000 03382 DB $00,$00,$00,$00,$00,$00,$00,$00 +8140 0000000000000000 03383 DB $00,$00,$00,$00,$00,$00,$00,$00 +8148 0000000000000000 03384 DB $00,$00,$00,$00,$00,$00,$00,$00 +8150 0000000000000000 03385 DB $00,$00,$00,$00,$00,$00,$00,$00 +8158 0000000000000000 03386 DB $00,$00,$00,$00,$00,$00,$00,$00 +8160 0000000000000000 03387 DB $00,$00,$00,$00,$00,$00,$00,$00 +8168 0000000000000000 03388 DB $00,$00,$00,$00,$00,$00,$00,$00 +8170 0000000000000000 03389 DB $00,$00,$00,$00,$00,$00,$00,$00 +8178 0000000000000000 03390 DB $00,$00,$00,$00,$00,$00,$00,$00 +8180 0000000000000000 03391 DB $00,$00,$00,$00,$00,$00,$00,$00 +8188 0000000000000000 03392 DB $00,$00,$00,$00,$00,$00,$00,$00 +8190 0000000000000000 03393 DB $00,$00,$00,$00,$00,$00,$00,$00 +8198 0000000000000000 03394 DB $00,$00,$00,$00,$00,$00,$00,$00 +81A0 0000000000000000 03395 DB $00,$00,$00,$00,$00,$00,$00,$00 +81A8 0000000000000000 03396 DB $00,$00,$00,$00,$00,$00,$00,$00 +81B0 0000000000000000 03397 DB $00,$00,$00,$00,$00,$00,$00,$00 +81B8 0000000000000000 03398 DB $00,$00,$00,$00,$00,$00,$00,$00 +81C0 0000000000000000 03399 DB $00,$00,$00,$00,$00,$00,$00,$00 +81C8 0000000000000000 03400 DB $00,$00,$00,$00,$00,$00,$00,$00 +81D0 0000000000000000 03401 DB $00,$00,$00,$00,$00,$00,$00,$00 +81D8 0000000000000000 03402 DB $00,$00,$00,$00,$00,$00,$00,$00 +81E0 0000000000000000 03403 DB $00,$00,$00,$00,$00,$00,$00,$00 +81E8 0000000000000000 03404 DB $00,$00,$00,$00,$00,$00,$00,$00 +81F0 0000000000000000 03405 DB $00,$00,$00,$00,$00,$00,$00,$00 +81F8 0000000000000000 03406 DB $00,$00,$00,$00,$00,$00,$00,$00 +8200 0000000000000000 03407 DB $00,$00,$00,$00,$00,$00,$00,$00 +8208 0000000000000000 03408 DB $00,$00,$00,$00,$00,$00,$00,$00 +8210 2020202020002000 03409 DB $20,$20,$20,$20,$20,$00,$20,$00 +8218 2020202020002000 03410 DB $20,$20,$20,$20,$20,$00,$20,$00 +8220 5050500000000000 03411 DB $50,$50,$50,$00,$00,$00,$00,$00 +8228 5050500000000000 03412 DB $50,$50,$50,$00,$00,$00,$00,$00 +8230 5050F850F8505000 03413 DB $50,$50,$F8,$50,$F8,$50,$50,$00 +8238 5050F850F8505000 03414 DB $50,$50,$F8,$50,$F8,$50,$50,$00 +8240 2078A07028F02000 03415 DB $20,$78,$A0,$70,$28,$F0,$20,$00 +8248 2078A07028F02000 03416 DB $20,$78,$A0,$70,$28,$F0,$20,$00 +8250 C0C8102040981800 03417 DB $C0,$C8,$10,$20,$40,$98,$18,$00 +8258 C0C8102040981800 03418 DB $C0,$C8,$10,$20,$40,$98,$18,$00 +8260 40A040A0A8906800 03419 DB $40,$A0,$40,$A0,$A8,$90,$68,$00 +8268 40A040A0A8906800 03420 DB $40,$A0,$40,$A0,$A8,$90,$68,$00 +8270 6020400000000000 03421 DB $60,$20,$40,$00,$00,$00,$00,$00 +8278 6020400000000000 03422 DB $60,$20,$40,$00,$00,$00,$00,$00 +8280 1020404040201000 03423 DB $10,$20,$40,$40,$40,$20,$10,$00 +8288 1020404040201000 03424 DB $10,$20,$40,$40,$40,$20,$10,$00 +8290 4020101010204000 03425 DB $40,$20,$10,$10,$10,$20,$40,$00 +8298 4020101010204000 03426 DB $40,$20,$10,$10,$10,$20,$40,$00 +82A0 00A8702070A80000 03427 DB $00,$A8,$70,$20,$70,$A8,$00,$00 +82A8 00A8702070A80000 03428 DB $00,$A8,$70,$20,$70,$A8,$00,$00 +82B0 002020F820200000 03429 DB $00,$20,$20,$F8,$20,$20,$00,$00 +82B8 002020F820200000 03430 DB $00,$20,$20,$F8,$20,$20,$00,$00 +82C0 0000000000602040 03431 DB $00,$00,$00,$00,$00,$60,$20,$40 +82C8 0000000000602040 03432 DB $00,$00,$00,$00,$00,$60,$20,$40 +82D0 000000FC00000000 03433 DB $00,$00,$00,$FC,$00,$00,$00,$00 +82D8 000000FC00000000 03434 DB $00,$00,$00,$FC,$00,$00,$00,$00 +82E0 0000000000006000 03435 DB $00,$00,$00,$00,$00,$00,$60,$00 +82E8 0000000000006000 03436 DB $00,$00,$00,$00,$00,$00,$60,$00 +82F0 0008102040800000 03437 DB $00,$08,$10,$20,$40,$80,$00,$00 +82F8 0008102040800000 03438 DB $00,$08,$10,$20,$40,$80,$00,$00 +8300 708898A8C8887000 03439 DB $70,$88,$98,$A8,$C8,$88,$70,$00 +8308 708898A8C8887000 03440 DB $70,$88,$98,$A8,$C8,$88,$70,$00 +8310 206020202020F800 03441 DB $20,$60,$20,$20,$20,$20,$F8,$00 +8318 206020202020F800 03442 DB $20,$60,$20,$20,$20,$20,$F8,$00 +8320 708808106080F800 03443 DB $70,$88,$08,$10,$60,$80,$F8,$00 +8328 708808106080F800 03444 DB $70,$88,$08,$10,$60,$80,$F8,$00 +8330 7088083008887000 03445 DB $70,$88,$08,$30,$08,$88,$70,$00 +8338 7088083008887000 03446 DB $70,$88,$08,$30,$08,$88,$70,$00 +8340 30509090F8101000 03447 DB $30,$50,$90,$90,$F8,$10,$10,$00 +8348 30509090F8101000 03448 DB $30,$50,$90,$90,$F8,$10,$10,$00 +8350 F880F0080808F000 03449 DB $F8,$80,$F0,$08,$08,$08,$F0,$00 +8358 F880F0080808F000 03450 DB $F8,$80,$F0,$08,$08,$08,$F0,$00 +8360 304080F088887000 03451 DB $30,$40,$80,$F0,$88,$88,$70,$00 +8368 304080F088887000 03452 DB $30,$40,$80,$F0,$88,$88,$70,$00 +8370 F808102020202000 03453 DB $F8,$08,$10,$20,$20,$20,$20,$00 +8378 F808102020202000 03454 DB $F8,$08,$10,$20,$20,$20,$20,$00 +8380 7088887088887000 03455 DB $70,$88,$88,$70,$88,$88,$70,$00 +8388 7088887088887000 03456 DB $70,$88,$88,$70,$88,$88,$70,$00 +8390 7088887808106000 03457 DB $70,$88,$88,$78,$08,$10,$60,$00 +8398 7088887808106000 03458 DB $70,$88,$88,$78,$08,$10,$60,$00 +83A0 0000006000600000 03459 DB $00,$00,$00,$60,$00,$60,$00,$00 +83A8 0000006000600000 03460 DB $00,$00,$00,$60,$00,$60,$00,$00 +83B0 0000006000602040 03461 DB $00,$00,$00,$60,$00,$60,$20,$40 +83B8 0000006000602040 03462 DB $00,$00,$00,$60,$00,$60,$20,$40 +83C0 1020408040201000 03463 DB $10,$20,$40,$80,$40,$20,$10,$00 +83C8 1020408040201000 03464 DB $10,$20,$40,$80,$40,$20,$10,$00 +83D0 0000F800F8000000 03465 DB $00,$00,$F8,$00,$F8,$00,$00,$00 +83D8 0000F800F8000000 03466 DB $00,$00,$F8,$00,$F8,$00,$00,$00 +83E0 0804020102040800 03467 DB $08,$04,$02,$01,$02,$04,$08,$00 +83E8 0804020102040800 03468 DB $08,$04,$02,$01,$02,$04,$08,$00 +83F0 7088081020002000 03469 DB $70,$88,$08,$10,$20,$00,$20,$00 +83F8 7088081020002000 03470 DB $70,$88,$08,$10,$20,$00,$20,$00 +8400 708898A898807000 03471 DB $70,$88,$98,$A8,$98,$80,$70,$00 +8408 708898A898807000 03472 DB $70,$88,$98,$A8,$98,$80,$70,$00 +8410 20508888F8888800 03473 DB $20,$50,$88,$88,$F8,$88,$88,$00 +8418 20508888F8888800 03474 DB $20,$50,$88,$88,$F8,$88,$88,$00 +8420 F08888F08888F000 03475 DB $F0,$88,$88,$F0,$88,$88,$F0,$00 +8428 F08888F08888F000 03476 DB $F0,$88,$88,$F0,$88,$88,$F0,$00 +8430 7088808080887000 03477 DB $70,$88,$80,$80,$80,$88,$70,$00 +8438 7088808080887000 03478 DB $70,$88,$80,$80,$80,$88,$70,$00 +8440 F08888888888F000 03479 DB $F0,$88,$88,$88,$88,$88,$F0,$00 +8448 F08888888888F000 03480 DB $F0,$88,$88,$88,$88,$88,$F0,$00 +8450 F88080F08080F800 03481 DB $F8,$80,$80,$F0,$80,$80,$F8,$00 +8458 F88080F08080F800 03482 DB $F8,$80,$80,$F0,$80,$80,$F8,$00 +8460 F88080F080808000 03483 DB $F8,$80,$80,$F0,$80,$80,$80,$00 +8468 F88080F080808000 03484 DB $F8,$80,$80,$F0,$80,$80,$80,$00 +8470 708880B888887000 03485 DB $70,$88,$80,$B8,$88,$88,$70,$00 +8478 708880B888887000 03486 DB $70,$88,$80,$B8,$88,$88,$70,$00 +8480 888888F888888800 03487 DB $88,$88,$88,$F8,$88,$88,$88,$00 +8488 888888F888888800 03488 DB $88,$88,$88,$F8,$88,$88,$88,$00 +8490 7020202020207000 03489 DB $70,$20,$20,$20,$20,$20,$70,$00 +8498 7020202020207000 03490 DB $70,$20,$20,$20,$20,$20,$70,$00 +84A0 0808080888887000 03491 DB $08,$08,$08,$08,$88,$88,$70,$00 +84A8 0808080888887000 03492 DB $08,$08,$08,$08,$88,$88,$70,$00 +84B0 8890A0C0A0908800 03493 DB $88,$90,$A0,$C0,$A0,$90,$88,$00 +84B8 8890A0C0A0908800 03494 DB $88,$90,$A0,$C0,$A0,$90,$88,$00 +84C0 808080808080F800 03495 DB $80,$80,$80,$80,$80,$80,$F8,$00 +84C8 808080808080F800 03496 DB $80,$80,$80,$80,$80,$80,$F8,$00 +84D0 88D8A8A888888800 03497 DB $88,$D8,$A8,$A8,$88,$88,$88,$00 +84D8 88D8A8A888888800 03498 DB $88,$D8,$A8,$A8,$88,$88,$88,$00 +84E0 88C8C8A898988800 03499 DB $88,$C8,$C8,$A8,$98,$98,$88,$00 +84E8 88C8C8A898988800 03500 DB $88,$C8,$C8,$A8,$98,$98,$88,$00 +84F0 7088888888887000 03501 DB $70,$88,$88,$88,$88,$88,$70,$00 +84F8 7088888888887000 03502 DB $70,$88,$88,$88,$88,$88,$70,$00 +8500 F08888F080808000 03503 DB $F0,$88,$88,$F0,$80,$80,$80,$00 +8508 F08888F080808000 03504 DB $F0,$88,$88,$F0,$80,$80,$80,$00 +8510 7088888888A89068 03505 DB $70,$88,$88,$88,$88,$A8,$90,$68 +8518 7088888888A89068 03506 DB $70,$88,$88,$88,$88,$A8,$90,$68 +8520 F08888F0A0908800 03507 DB $F0,$88,$88,$F0,$A0,$90,$88,$00 +8528 F08888F0A0908800 03508 DB $F0,$88,$88,$F0,$A0,$90,$88,$00 +8530 7088807008887000 03509 DB $70,$88,$80,$70,$08,$88,$70,$00 +8538 7088807008887000 03510 DB $70,$88,$80,$70,$08,$88,$70,$00 +8540 F820202020202000 03511 DB $F8,$20,$20,$20,$20,$20,$20,$00 +8548 F820202020202000 03512 DB $F8,$20,$20,$20,$20,$20,$20,$00 +8550 8888888888887000 03513 DB $88,$88,$88,$88,$88,$88,$70,$00 +8558 8888888888887000 03514 DB $88,$88,$88,$88,$88,$88,$70,$00 +8560 8888888850502000 03515 DB $88,$88,$88,$88,$50,$50,$20,$00 +8568 8888888850502000 03516 DB $88,$88,$88,$88,$50,$50,$20,$00 +8570 888888A8A8D88800 03517 DB $88,$88,$88,$A8,$A8,$D8,$88,$00 +8578 888888A8A8D88800 03518 DB $88,$88,$88,$A8,$A8,$D8,$88,$00 +8580 8888502050888800 03519 DB $88,$88,$50,$20,$50,$88,$88,$00 +8588 8888502050888800 03520 DB $88,$88,$50,$20,$50,$88,$88,$00 +8590 8888887020202000 03521 DB $88,$88,$88,$70,$20,$20,$20,$00 +8598 8888887020202000 03522 DB $88,$88,$88,$70,$20,$20,$20,$00 +85A0 F80810204080F800 03523 DB $F8,$08,$10,$20,$40,$80,$F8,$00 +85A8 F80810204080F800 03524 DB $F8,$08,$10,$20,$40,$80,$F8,$00 +85B0 7860606060607800 03525 DB $78,$60,$60,$60,$60,$60,$78,$00 +85B8 7860606060607800 03526 DB $78,$60,$60,$60,$60,$60,$78,$00 +85C0 0080402010080000 03527 DB $00,$80,$40,$20,$10,$08,$00,$00 +85C8 0080402010080000 03528 DB $00,$80,$40,$20,$10,$08,$00,$00 +85D0 F03030303030F000 03529 DB $F0,$30,$30,$30,$30,$30,$F0,$00 +85D8 F03030303030F000 03530 DB $F0,$30,$30,$30,$30,$30,$F0,$00 +85E0 2050880000000000 03531 DB $20,$50,$88,$00,$00,$00,$00,$00 +85E8 2050880000000000 03532 DB $20,$50,$88,$00,$00,$00,$00,$00 +85F0 000000000000F800 03533 DB $00,$00,$00,$00,$00,$00,$F8,$00 +85F8 000000000000F800 03534 DB $00,$00,$00,$00,$00,$00,$F8,$00 +8600 4020100000000000 03535 DB $40,$20,$10,$00,$00,$00,$00,$00 +8608 4020100000000000 03536 DB $40,$20,$10,$00,$00,$00,$00,$00 +8610 0000689888986800 03537 DB $00,$00,$68,$98,$88,$98,$68,$00 +8618 0000689888986800 03538 DB $00,$00,$68,$98,$88,$98,$68,$00 +8620 8080F0888888F000 03539 DB $80,$80,$F0,$88,$88,$88,$F0,$00 +8628 8080F0888888F000 03540 DB $80,$80,$F0,$88,$88,$88,$F0,$00 +8630 0000788080807800 03541 DB $00,$00,$78,$80,$80,$80,$78,$00 +8638 0000788080807800 03542 DB $00,$00,$78,$80,$80,$80,$78,$00 +8640 0808689888986800 03543 DB $08,$08,$68,$98,$88,$98,$68,$00 +8648 0808689888986800 03544 DB $08,$08,$68,$98,$88,$98,$68,$00 +8650 00007088F8807000 03545 DB $00,$00,$70,$88,$F8,$80,$70,$00 +8658 00007088F8807000 03546 DB $00,$00,$70,$88,$F8,$80,$70,$00 +8660 304840E040404000 03547 DB $30,$48,$40,$E0,$40,$40,$40,$00 +8668 304840E040404000 03548 DB $30,$48,$40,$E0,$40,$40,$40,$00 +8670 0000788888780870 03549 DB $00,$00,$78,$88,$88,$78,$08,$70 +8678 0000788888780870 03550 DB $00,$00,$78,$88,$88,$78,$08,$70 +8680 8080F08888888800 03551 DB $80,$80,$F0,$88,$88,$88,$88,$00 +8688 8080F08888888800 03552 DB $80,$80,$F0,$88,$88,$88,$88,$00 +8690 2000602020207000 03553 DB $20,$00,$60,$20,$20,$20,$70,$00 +8698 2000602020207000 03554 DB $20,$00,$60,$20,$20,$20,$70,$00 +86A0 0800180888887000 03555 DB $08,$00,$18,$08,$88,$88,$70,$00 +86A8 0800180888887000 03556 DB $08,$00,$18,$08,$88,$88,$70,$00 +86B0 80808890E0908800 03557 DB $80,$80,$88,$90,$E0,$90,$88,$00 +86B8 80808890E0908800 03558 DB $80,$80,$88,$90,$E0,$90,$88,$00 +86C0 6020202020207000 03559 DB $60,$20,$20,$20,$20,$20,$70,$00 +86C8 6020202020207000 03560 DB $60,$20,$20,$20,$20,$20,$70,$00 +86D0 0000D0A8A8A8A800 03561 DB $00,$00,$D0,$A8,$A8,$A8,$A8,$00 +86D8 0000D0A8A8A8A800 03562 DB $00,$00,$D0,$A8,$A8,$A8,$A8,$00 +86E0 0000B0C888888800 03563 DB $00,$00,$B0,$C8,$88,$88,$88,$00 +86E8 0000B0C888888800 03564 DB $00,$00,$B0,$C8,$88,$88,$88,$00 +86F0 0000708888887000 03565 DB $00,$00,$70,$88,$88,$88,$70,$00 +86F8 0000708888887000 03566 DB $00,$00,$70,$88,$88,$88,$70,$00 +8700 0000F0888888F080 03567 DB $00,$00,$F0,$88,$88,$88,$F0,$80 +8708 0000F0888888F080 03568 DB $00,$00,$F0,$88,$88,$88,$F0,$80 +8710 0000788888887808 03569 DB $00,$00,$78,$88,$88,$88,$78,$08 +8718 0000788888887808 03570 DB $00,$00,$78,$88,$88,$88,$78,$08 +8720 0000B8C080808000 03571 DB $00,$00,$B8,$C0,$80,$80,$80,$00 +8728 0000B8C080808000 03572 DB $00,$00,$B8,$C0,$80,$80,$80,$00 +8730 000078807008F000 03573 DB $00,$00,$78,$80,$70,$08,$F0,$00 +8738 000078807008F000 03574 DB $00,$00,$78,$80,$70,$08,$F0,$00 +8740 2020F82020202000 03575 DB $20,$20,$F8,$20,$20,$20,$20,$00 +8748 2020F82020202000 03576 DB $20,$20,$F8,$20,$20,$20,$20,$00 +8750 0000888888986800 03577 DB $00,$00,$88,$88,$88,$98,$68,$00 +8758 0000888888986800 03578 DB $00,$00,$88,$88,$88,$98,$68,$00 +8760 0000888888502000 03579 DB $00,$00,$88,$88,$88,$50,$20,$00 +8768 0000888888502000 03580 DB $00,$00,$88,$88,$88,$50,$20,$00 +8770 000088A8A8A85000 03581 DB $00,$00,$88,$A8,$A8,$A8,$50,$00 +8778 000088A8A8A85000 03582 DB $00,$00,$88,$A8,$A8,$A8,$50,$00 +8780 0000885020508800 03583 DB $00,$00,$88,$50,$20,$50,$88,$00 +8788 0000885020508800 03584 DB $00,$00,$88,$50,$20,$50,$88,$00 +8790 0000888898680870 03585 DB $00,$00,$88,$88,$98,$68,$08,$70 +8798 0000888898680870 03586 DB $00,$00,$88,$88,$98,$68,$08,$70 +87A0 0000F8102040F800 03587 DB $00,$00,$F8,$10,$20,$40,$F8,$00 +87A8 0000F8102040F800 03588 DB $00,$00,$F8,$10,$20,$40,$F8,$00 +87B0 1820204020201800 03589 DB $18,$20,$20,$40,$20,$20,$18,$00 +87B8 1820204020201800 03590 DB $18,$20,$20,$40,$20,$20,$18,$00 +87C0 2020202020202000 03591 DB $20,$20,$20,$20,$20,$20,$20,$00 +87C8 2020202020202000 03592 DB $20,$20,$20,$20,$20,$20,$20,$00 +87D0 C02020102020C000 03593 DB $C0,$20,$20,$10,$20,$20,$C0,$00 +87D8 C02020102020C000 03594 DB $C0,$20,$20,$10,$20,$20,$C0,$00 +87E0 000040A810000000 03595 DB $00,$00,$40,$A8,$10,$00,$00,$00 +87E8 000040A810000000 03596 DB $00,$00,$40,$A8,$10,$00,$00,$00 +87F0 707020F820705000 03597 DB $70,$70,$20,$F8,$20,$70,$50,$00 +87F8 707020F820705000 03598 DB $70,$70,$20,$F8,$20,$70,$50,$00 +8800 F0F0F08000000000 03599 DB $F0,$F0,$F0,$80,$00,$00,$00,$00 +8808 0F0F0F7FFFFFFFFF 03600 DB $0F,$0F,$0F,$7F,$FF,$FF,$FF,$FF +8810 0000000000000000 03601 DB $00,$00,$00,$00,$00,$00,$00,$00 +8818 FFFFFFFFFFFFFFFF 03602 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8820 0000000000030F3F 03603 DB $00,$00,$00,$00,$00,$03,$0F,$3F +8828 FFFFFFFFFFFFFFFF 03604 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8830 01074F7FFFFFFFFF 03605 DB $01,$07,$4F,$7F,$FF,$FF,$FF,$FF +8838 FFFFFFFFFFFFFFFF 03606 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8840 FFFFFFFFFFFFFFFF 03607 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8848 FFFFFFFFFFFFFFFF 03608 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8850 00000103070F1F3F 03609 DB $00,$00,$01,$03,$07,$0F,$1F,$3F +8858 FFFFFFFFFFFFFFFF 03610 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8860 7FFFFFFFFFFFFFFF 03611 DB $7F,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8868 FFFFFFFFFFFFFFFF 03612 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8870 000000000303070F 03613 DB $00,$00,$00,$00,$03,$03,$07,$0F +8878 FFFFFFFFFFFFFFFF 03614 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8880 3F7FFFFFFFFFFFFF 03615 DB $3F,$7F,$FF,$FF,$FF,$FF,$FF,$FF +8888 FFFFFFFFFFFFFFFF 03616 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8890 0F1F1F3F7FFFFFFF 03617 DB $0F,$1F,$1F,$3F,$7F,$FF,$FF,$FF +8898 FFFFFFFFFFFFFFFF 03618 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +88A0 FFFFFFFFFCF0E3C7 03619 DB $FF,$FF,$FF,$FF,$FC,$F0,$E3,$C7 +88A8 FFFFFFFFFFFFFCF8 03620 DB $FF,$FF,$FF,$FF,$FF,$FF,$FC,$F8 +88B0 FFFFFFEF00FFE7FF 03621 DB $FF,$FF,$FF,$EF,$00,$FF,$E7,$FF +88B8 FFFFFFFFFF000000 03622 DB $FF,$FF,$FF,$FF,$FF,$00,$00,$00 +88C0 FFFFFFFFFF3FF7F9 03623 DB $FF,$FF,$FF,$FF,$FF,$3F,$F7,$F9 +88C8 FFFFFFFFFFFF0F07 03624 DB $FF,$FF,$FF,$FF,$FF,$FF,$0F,$07 +88D0 00010303070F0F1F 03625 DB $00,$01,$03,$03,$07,$0F,$0F,$1F +88D8 FFFFFFFFFFFFFFFF 03626 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +88E0 FFFFFFFFFEFEFCFC 03627 DB $FF,$FF,$FF,$FF,$FE,$FE,$FC,$FC +88E8 FFFFFFFFFFFFFFFF 03628 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +88F0 CF9F1F3F7F7EF0E0 03629 DB $CF,$9F,$1F,$3F,$7F,$7E,$F0,$E0 +88F8 F0E0E0C080810F1F 03630 DB $F0,$E0,$E0,$C0,$80,$81,$0F,$1F +8900 FFFFFFFFFF010000 03631 DB $FF,$FF,$FF,$FF,$FF,$01,$00,$00 +8908 0000000000FEFFFF 03632 DB $00,$00,$00,$00,$00,$FE,$FF,$FF +8910 FEFFFFFFFFFF3F0F 03633 DB $FE,$FF,$FF,$FF,$FF,$FF,$3F,$0F +8918 010000000000C0F0 03634 DB $01,$00,$00,$00,$00,$00,$C0,$F0 +8920 3FE7C3E1E1E0E0F0 03635 DB $3F,$E7,$C3,$E1,$E1,$E0,$E0,$F0 +8928 FF1F070300000000 03636 DB $FF,$1F,$07,$03,$00,$00,$00,$00 +8930 FFFFFFFFFFFF7F1F 03637 DB $FF,$FF,$FF,$FF,$FF,$FF,$7F,$1F +8938 FFFFFFFFFF7F3F3F 03638 DB $FF,$FF,$FF,$FF,$FF,$7F,$3F,$3F +8940 1F3F3F3F7F7FFFFF 03639 DB $1F,$3F,$3F,$3F,$7F,$7F,$FF,$FF +8948 FFFFFFFFFFFFFFFF 03640 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8950 FDFDFDFAFAF8F8F8 03641 DB $FD,$FD,$FD,$FA,$FA,$F8,$F8,$F8 +8958 FEFEFEFDFDFFFFFF 03642 DB $FE,$FE,$FE,$FD,$FD,$FF,$FF,$FF +8960 C080000000000000 03643 DB $C0,$80,$00,$00,$00,$00,$00,$00 +8968 3F7FFFFFFFFFFFFF 03644 DB $3F,$7F,$FF,$FF,$FF,$FF,$FF,$FF +8970 0F07070301010101 03645 DB $0F,$07,$07,$03,$01,$01,$01,$01 +8978 F0F8F8FCFEFEFEFE 03646 DB $F0,$F8,$F8,$FC,$FE,$FE,$FE,$FE +8980 F0F0F8F8F8F8F8FC 03647 DB $F0,$F0,$F8,$F8,$F8,$F8,$F8,$FC +8988 0000000000000000 03648 DB $00,$00,$00,$00,$00,$00,$00,$00 +8990 1F0F0F07070F0703 03649 DB $1F,$0F,$0F,$07,$07,$0F,$07,$03 +8998 1F1F0F0F0F070707 03650 DB $1F,$1F,$0F,$0F,$0F,$07,$07,$07 +89A0 0001010303030707 03651 DB $00,$01,$01,$03,$03,$03,$07,$07 +89A8 FFFFFFFFFFFFFFFF 03652 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +89B0 F4F4F4F0FCFCF7F7 03653 DB $F4,$F4,$F4,$F0,$FC,$FC,$F7,$F7 +89B8 FBFBFBFFFBFBF8F8 03654 DB $FB,$FB,$FB,$FF,$FB,$FB,$F8,$F8 +89C0 000000021300E0F0 03655 DB $00,$00,$00,$02,$13,$00,$E0,$F0 +89C8 FFFFFFFFFFFF1F0F 03656 DB $FF,$FF,$FF,$FF,$FF,$FF,$1F,$0F +89D0 0000001F18070E0E 03657 DB $00,$00,$00,$1F,$18,$07,$0E,$0E +89D8 FFFFFFFFFFF8F0F1 03658 DB $FF,$FF,$FF,$FF,$FF,$F8,$F0,$F1 +89E0 010303870F7FC3F8 03659 DB $01,$03,$03,$87,$0F,$7F,$C3,$F8 +89E8 FEFCFCF8F0003CFF 03660 DB $FE,$FC,$FC,$F8,$F0,$00,$3C,$FF +89F0 FCFEFEFEFEFEF0F1 03661 DB $FC,$FE,$FE,$FE,$FE,$FE,$F0,$F1 +89F8 0000000000000000 03662 DB $00,$00,$00,$00,$00,$00,$00,$00 +8A00 0302060474C60F0C 03663 DB $03,$02,$06,$04,$74,$C6,$0F,$0C +8A08 0707030303010003 03664 DB $07,$07,$03,$03,$03,$01,$00,$03 +8A10 FF1F030100000000 03665 DB $FF,$1F,$03,$01,$00,$00,$00,$00 +8A18 FFFFFFFFFFFFFFFF 03666 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8A20 FFFFFFFFFFFF7F7F 03667 DB $FF,$FF,$FF,$FF,$FF,$FF,$7F,$7F +8A28 FFFFFFFFFFFFFFFF 03668 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8A30 070707070707070F 03669 DB $07,$07,$07,$07,$07,$07,$07,$0F +8A38 FFFFFFFFFFFFFFFF 03670 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8A40 F7C4A8AB9EBFFEDC 03671 DB $F7,$C4,$A8,$AB,$9E,$BF,$FE,$DC +8A48 F8FBF7C43878F9FB 03672 DB $F8,$FB,$F7,$C4,$38,$78,$F9,$FB +8A50 FC0617F7073D0302 03673 DB $FC,$06,$17,$F7,$07,$3D,$03,$02 +8A58 03F9E800C0C0FCFD 03674 DB $03,$F9,$E8,$00,$C0,$C0,$FC,$FD +8A60 18193B3D3C3C1C1C 03675 DB $18,$19,$3B,$3D,$3C,$3C,$1C,$1C +8A68 E7E6C4C2C3C3E3E3 03676 DB $E7,$E6,$C4,$C2,$C3,$C3,$E3,$E3 +8A70 F699761940000000 03677 DB $F6,$99,$76,$19,$40,$00,$00,$00 +8A78 F970C0E6BFFFFFFF 03678 DB $F9,$70,$C0,$E6,$BF,$FF,$FF,$FF +8A80 1FFFC7C743434387 03679 DB $1F,$FF,$C7,$C7,$43,$43,$43,$87 +8A88 80003838BCBCBC78 03680 DB $80,$00,$38,$38,$BC,$BC,$BC,$78 +8A90 8089818DCDFDFDEF 03681 DB $80,$89,$81,$8D,$CD,$FD,$FD,$EF +8A98 0706060202020200 03682 DB $07,$06,$06,$02,$02,$02,$02,$00 +8AA0 7F7F3F3F3F1F1F0F 03683 DB $7F,$7F,$3F,$3F,$3F,$1F,$1F,$0F +8AA8 FFFFFFFFFFFFFFFF 03684 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8AB0 0F0F070F0F07070F 03685 DB $0F,$0F,$07,$0F,$0F,$07,$07,$0F +8AB8 FFFFFFFFFFFFFFFF 03686 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8AC0 D4E4F4FBF8FCFCFC 03687 DB $D4,$E4,$F4,$FB,$F8,$FC,$FC,$FC +8AC8 FBFBFBFCFFFFFFFF 03688 DB $FB,$FB,$FB,$FC,$FF,$FF,$FF,$FF +8AD0 06040CA000000000 03689 DB $06,$04,$0C,$A0,$00,$00,$00,$00 +8AD8 F9FBF35FFFFFFFFF 03690 DB $F9,$FB,$F3,$5F,$FF,$FF,$FF,$FF +8AE0 0E1F1E1F1F0B813F 03691 DB $0E,$1F,$1E,$1F,$1F,$0B,$81,$3F +8AE8 F1E0E1E0E0F4FEC0 03692 DB $F1,$E0,$E1,$E0,$E0,$F4,$FE,$C0 +8AF0 0000020E86808000 03693 DB $00,$00,$02,$0E,$86,$80,$80,$00 +8AF8 FFFFFFFF7F7F7FFF 03694 DB $FF,$FF,$FF,$FF,$7F,$7F,$7F,$FF +8B00 8707070707070F0F 03695 DB $87,$07,$07,$07,$07,$07,$0F,$0F +8B08 78F8F8F8F8F8F0F0 03696 DB $78,$F8,$F8,$F8,$F8,$F8,$F0,$F0 +8B10 EBF0FEF8F0F0F0F0 03697 DB $EB,$F0,$FE,$F8,$F0,$F0,$F0,$F0 +8B18 040F01070F0F0F0F 03698 DB $04,$0F,$01,$07,$0F,$0F,$0F,$0F +8B20 0F07070303010000 03699 DB $0F,$07,$07,$03,$03,$01,$00,$00 +8B28 FFFFFFFFFFFFFFFF 03700 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8B30 FFFFFFFFFFFFFF3F 03701 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$3F +8B38 FFFFFFFFFFFFFFFF 03702 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8B40 0F07070707030707 03703 DB $0F,$07,$07,$07,$07,$03,$07,$07 +8B48 FFFFFFFFFFFFFFFF 03704 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8B50 FEFFFFFFFFFFFFFF 03705 DB $FE,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8B58 FFFFFFFFFFFFFFFF 03706 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8B60 000200008087C3C0 03707 DB $00,$02,$00,$00,$80,$87,$C3,$C0 +8B68 FFFDFFFFFFF8FCFF 03708 DB $FF,$FD,$FF,$FF,$FF,$F8,$FC,$FF +8B70 3000000003FFFFC0 03709 DB $30,$00,$00,$00,$03,$FF,$FF,$C0 +8B78 CFFFFFFFFC00003F 03710 DB $CF,$FF,$FF,$FF,$FC,$00,$00,$3F +8B80 00000038F0C00000 03711 DB $00,$00,$00,$38,$F0,$C0,$00,$00 +8B88 FFFFFFC70F3FFFFF 03712 DB $FF,$FF,$FF,$C7,$0F,$3F,$FF,$FF +8B90 0B03030303030307 03713 DB $0B,$03,$03,$03,$03,$03,$03,$07 +8B98 F4FCFCFCFCFCFCF8 03714 DB $F4,$FC,$FC,$FC,$FC,$FC,$FC,$F8 +8BA0 F0F0F0F0F0F0F0E8 03715 DB $F0,$F0,$F0,$F0,$F0,$F0,$F0,$E8 +8BA8 0F0F0F0F0F0F0F07 03716 DB $0F,$0F,$0F,$0F,$0F,$0F,$0F,$07 +8BB0 1F0F030000000000 03717 DB $1F,$0F,$03,$00,$00,$00,$00,$00 +8BB8 FFFFFFFFFFFFFFFF 03718 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8BC0 FFFFFFFF3F0F0703 03719 DB $FF,$FF,$FF,$FF,$3F,$0F,$07,$03 +8BC8 FFFFFFFFFFFFFFFF 03720 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8BD0 0707030707070703 03721 DB $07,$07,$03,$07,$07,$07,$07,$03 +8BD8 FFFFFFFFFFFFFFFF 03722 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8BE0 E0E0F0F4F8FAFCFE 03723 DB $E0,$E0,$F0,$F4,$F8,$FA,$FC,$FE +8BE8 FFFFFFFBFFFDFFFF 03724 DB $FF,$FF,$FF,$FB,$FF,$FD,$FF,$FF +8BF0 00000000060E1F1F 03725 DB $00,$00,$00,$00,$06,$0E,$1F,$1F +8BF8 FFFFFFFFF9F1E0E0 03726 DB $FF,$FF,$FF,$FF,$F9,$F1,$E0,$E0 +8C00 070F1F3F7FFEDEF5 03727 DB $07,$0F,$1F,$3F,$7F,$FE,$DE,$F5 +8C08 F8F0E0C08001230E 03728 DB $F8,$F0,$E0,$C0,$80,$01,$23,$0E +8C10 C8C8A8E276C0709E 03729 DB $C8,$C8,$A8,$E2,$76,$C0,$70,$9E +8C18 0707070D891B1B33 03730 DB $07,$07,$07,$0D,$89,$1B,$1B,$33 +8C20 0000000000008020 03731 DB $00,$00,$00,$00,$00,$00,$80,$20 +8C28 FFFFFFFFFFFF7F1F 03732 DB $FF,$FF,$FF,$FF,$FF,$FF,$7F,$1F +8C30 0703030703030303 03733 DB $07,$03,$03,$07,$03,$03,$03,$03 +8C38 FFFFFFFFFFFFFFFF 03734 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8C40 FFFFFFFFFFFDFCEA 03735 DB $FF,$FF,$FF,$FF,$FF,$FD,$FC,$EA +8C48 FFFFFFFFFFFEF8F0 03736 DB $FF,$FF,$FF,$FF,$FF,$FE,$F8,$F0 +8C50 FEFBE8A61C3DB27C 03737 DB $FE,$FB,$E8,$A6,$1C,$3D,$B2,$7C +8C58 FFFCF1C183030707 03738 DB $FF,$FC,$F1,$C1,$83,$03,$07,$07 +8C60 00003F3F20305050 03739 DB $00,$00,$3F,$3F,$20,$30,$50,$50 +8C68 FFFFC0C0DFCF8F8F 03740 DB $FF,$FF,$C0,$C0,$DF,$CF,$8F,$8F +8C70 3F7FF88000000103 03741 DB $3F,$7F,$F8,$80,$00,$00,$01,$03 +8C78 C080077FFFFFFFFF 03742 DB $C0,$80,$07,$7F,$FF,$FF,$FF,$FF +8C80 CF09163C6FD9F39E 03743 DB $CF,$09,$16,$3C,$6F,$D9,$F3,$9E +8C88 3CFCF8F1F1E3C7C7 03744 DB $3C,$FC,$F8,$F1,$F1,$E3,$C7,$C7 +8C90 23FC46D9DD12FA26 03745 DB $23,$FC,$46,$D9,$DD,$12,$FA,$26 +8C98 7666ECCC98B83070 03746 DB $76,$66,$EC,$CC,$98,$B8,$30,$70 +8CA0 1010060100C00000 03747 DB $10,$10,$06,$01,$00,$C0,$00,$00 +8CA8 0F0F010000000000 03748 DB $0F,$0F,$01,$00,$00,$00,$00,$00 +8CB0 0000008040201006 03749 DB $00,$00,$00,$80,$40,$20,$10,$06 +8CB8 FFFFFF7F3F1F0F01 03750 DB $FF,$FF,$FF,$7F,$3F,$1F,$0F,$01 +8CC0 0101000000000000 03751 DB $01,$01,$00,$00,$00,$00,$00,$00 +8CC8 FFFFFFFFFFFFFFFF 03752 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8CD0 FFFFFFFFFA7F173E 03753 DB $FF,$FF,$FF,$FF,$FA,$7F,$17,$3E +8CD8 FFFFFFFEFCF8F8F0 03754 DB $FF,$FF,$FF,$FE,$FC,$F8,$F8,$F0 +8CE0 C499B373E7EE5FFD 03755 DB $C4,$99,$B3,$73,$E7,$EE,$5F,$FD +8CE8 E0C0000000000000 03756 DB $E0,$C0,$00,$00,$00,$00,$00,$00 +8CF0 E4F46CE8F0406004 03757 DB $E4,$F4,$6C,$E8,$F0,$40,$60,$04 +8CF8 0F0F1F1F1F9F9F9B 03758 DB $0F,$0F,$1F,$1F,$1F,$9F,$9F,$9B +8D00 5050585858D8182A 03759 DB $50,$50,$58,$58,$58,$D8,$18,$2A +8D08 8F8F87878707C7C7 03760 DB $8F,$8F,$87,$87,$87,$07,$C7,$C7 +8D10 070F1E3F7F0B060E 03761 DB $07,$0F,$1E,$3F,$7F,$0B,$06,$0E +8D18 FFFFFFFEFCFCF8F1 03762 DB $FF,$FF,$FF,$FE,$FC,$FC,$F8,$F1 +8D20 64CE789339E36FE4 03763 DB $64,$CE,$78,$93,$39,$E3,$6F,$E4 +8D28 8E1C1D397377E6CE 03764 DB $8E,$1C,$1D,$39,$73,$77,$E6,$CE +8D30 C9E898D0226640CC 03765 DB $C9,$E8,$98,$D0,$22,$66,$40,$CC +8D38 60C0C08080000000 03766 DB $60,$C0,$C0,$80,$80,$00,$00,$00 +8D40 0000000000000000 03767 DB $00,$00,$00,$00,$00,$00,$00,$00 +8D48 0000000000000000 03768 DB $00,$00,$00,$00,$00,$00,$00,$00 +8D50 0100000000000000 03769 DB $01,$00,$00,$00,$00,$00,$00,$00 +8D58 0000000000000000 03770 DB $00,$00,$00,$00,$00,$00,$00,$00 +8D60 0040201008040600 03771 DB $00,$40,$20,$10,$08,$04,$06,$00 +8D68 FF3F1F0F07030100 03772 DB $FF,$3F,$1F,$0F,$07,$03,$01,$00 +8D70 00000000000000C0 03773 DB $00,$00,$00,$00,$00,$00,$00,$C0 +8D78 FFFFFFFFFFFFFF3F 03774 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$3F +8D80 2E2C2C3C7D757767 03775 DB $2E,$2C,$2C,$3C,$7D,$75,$77,$67 +8D88 F0F0F0E0E0E0E0F0 03776 DB $F0,$F0,$F0,$E0,$E0,$E0,$E0,$F0 +8D90 BC7EFEFEF8FDFDFF 03777 DB $BC,$7E,$FE,$FE,$F8,$FD,$FD,$FF +8D98 0101010103020200 03778 DB $01,$01,$01,$01,$03,$02,$02,$00 +8DA0 0E9A880808081113 03779 DB $0E,$9A,$88,$08,$08,$08,$11,$13 +8DA8 990D070707070F0F 03780 DB $99,$0D,$07,$07,$07,$07,$0F,$0F +8DB0 0C0C01070684D1C5 03781 DB $0C,$0C,$01,$07,$06,$84,$D1,$C5 +8DB8 E7E7FFFFFFFFEEE8 03782 DB $E7,$E7,$FF,$FF,$FF,$FF,$EE,$E8 +8DC0 0F193B7EEFCE9933 03783 DB $0F,$19,$3B,$7E,$EF,$CE,$99,$33 +8DC8 F1E3C7870E1C3C79 03784 DB $F1,$E3,$C7,$87,$0E,$1C,$3C,$79 +8DD0 9EF91B7B677ED8BF 03785 DB $9E,$F9,$1B,$7B,$67,$7E,$D8,$BF +8DD8 CC9CB83070E0E0C0 03786 DB $CC,$9C,$B8,$30,$70,$E0,$E0,$C0 +8DE0 F8F8F0C000000101 03787 DB $F8,$F8,$F0,$C0,$00,$00,$01,$01 +8DE8 0000000000000000 03788 DB $00,$00,$00,$00,$00,$00,$00,$00 +8DF0 00000000C0C0E0E0 03789 DB $00,$00,$00,$00,$C0,$C0,$E0,$E0 +8DF8 0000000000000000 03790 DB $00,$00,$00,$00,$00,$00,$00,$00 +8E00 1004000000000000 03791 DB $10,$04,$00,$00,$00,$00,$00,$00 +8E08 0F03010000000000 03792 DB $0F,$03,$01,$00,$00,$00,$00,$00 +8E10 776F4F7F3F1F7F7F 03793 DB $77,$6F,$4F,$7F,$3F,$1F,$7F,$7F +8E18 E0E0E0C0C0C08080 03794 DB $E0,$E0,$E0,$C0,$C0,$C0,$80,$80 +8E20 FFFEFEEEEEDCDC9C 03795 DB $FF,$FE,$FE,$EE,$EE,$DC,$DC,$9C +8E28 0000000000000000 03796 DB $00,$00,$00,$00,$00,$00,$00,$00 +8E30 172F2F4F4F5F9FBE 03797 DB $17,$2F,$2F,$4F,$4F,$5F,$9F,$BE +8E38 0F1F1F3F3F3F7F7F 03798 DB $0F,$1F,$1F,$3F,$3F,$3F,$7F,$7F +8E40 CECCFDBC7C7BE9FF 03799 DB $CE,$CC,$FD,$BC,$7C,$7B,$E9,$FF +8E48 E0E1C3C380801C1C 03800 DB $E0,$E1,$C3,$C3,$80,$80,$1C,$1C +8E50 7CCEBFFFFFFFFFFF 03801 DB $7C,$CE,$BF,$FF,$FF,$FF,$FF,$FF +8E58 F3E0C00000000000 03802 DB $F3,$E0,$C0,$00,$00,$00,$00,$00 +8E60 BFFFEFFFFFFFFFFF 03803 DB $BF,$FF,$EF,$FF,$FF,$FF,$FF,$FF +8E68 0000000000000000 03804 DB $00,$00,$00,$00,$00,$00,$00,$00 +8E70 81E1F9F9F9FBF3E3 03805 DB $81,$E1,$F9,$F9,$F9,$FB,$F3,$E3 +8E78 0000000000000000 03806 DB $00,$00,$00,$00,$00,$00,$00,$00 +8E80 F0F0F0F8F8F8FCFC 03807 DB $F0,$F0,$F0,$F8,$F8,$F8,$FC,$FC +8E88 0000000000000000 03808 DB $00,$00,$00,$00,$00,$00,$00,$00 +8E90 00010200041E0F3F 03809 DB $00,$01,$02,$00,$04,$1E,$0F,$3F +8E98 000001070F0F1F1F 03810 DB $00,$00,$01,$07,$0F,$0F,$1F,$1F +8EA0 0000000001010203 03811 DB $00,$00,$00,$00,$01,$01,$02,$03 +8EA8 FFFFFFFFFEFEFCFC 03812 DB $FF,$FF,$FF,$FF,$FE,$FE,$FC,$FC +8EB0 7FFFFFFFFFFFFEFE 03813 DB $7F,$FF,$FF,$FF,$FF,$FF,$FE,$FE +8EB8 8000000000000000 03814 DB $80,$00,$00,$00,$00,$00,$00,$00 +8EC0 B9F9FAF2F4F4E8CD 03815 DB $B9,$F9,$FA,$F2,$F4,$F4,$E8,$CD +8EC8 0000010103030703 03816 DB $00,$00,$01,$01,$03,$03,$07,$03 +8ED0 78724F9D3D7DF3F3 03817 DB $78,$72,$4F,$9D,$3D,$7D,$F3,$F3 +8ED8 FFFFFEFEFEFEFCFC 03818 DB $FF,$FF,$FE,$FE,$FE,$FE,$FC,$FC +8EE0 FFF5F7FFFFFFFFFF 03819 DB $FF,$F5,$F7,$FF,$FF,$FF,$FF,$FF +8EE8 1C08000000000000 03820 DB $1C,$08,$00,$00,$00,$00,$00,$00 +8EF0 FFFFFFF7E7EFCF9F 03821 DB $FF,$FF,$FF,$F7,$E7,$EF,$CF,$9F +8EF8 0000000000000000 03822 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F00 FFFFFFFFFFFFFFFF 03823 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF +8F08 0000000000000000 03824 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F10 E3C7C7C7C7CF8F8F 03825 DB $E3,$C7,$C7,$C7,$C7,$CF,$8F,$8F +8F18 0000000000000000 03826 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F20 FEFEFFFFFFFFFFFF 03827 DB $FE,$FE,$FF,$FF,$FF,$FF,$FF,$FF +8F28 0000000000000000 03828 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F30 00000000808080C0 03829 DB $00,$00,$00,$00,$80,$80,$80,$C0 +8F38 0000000000000000 03830 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F40 000000000020212C 03831 DB $00,$00,$00,$00,$00,$20,$21,$2C +8F48 0000000000000001 03832 DB $00,$00,$00,$00,$00,$00,$00,$01 +8F50 1F7D3DF97979F3F3 03833 DB $1F,$7D,$3D,$F9,$79,$79,$F3,$F3 +8F58 3F3F7F7FFFFFFFFF 03834 DB $3F,$3F,$7F,$7F,$FF,$FF,$FF,$FF +8F60 0000000000000000 03835 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F68 0000000000000000 03836 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F70 0000000000000000 03837 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F78 0000000000000000 03838 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F80 0000000000000000 03839 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F88 0000000000000000 03840 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F90 0000000000000000 03841 DB $00,$00,$00,$00,$00,$00,$00,$00 +8F98 0000000000000000 03842 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FA0 0000000000000000 03843 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FA8 0000000000000000 03844 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FB0 0000000000000000 03845 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FB8 0000000000000000 03846 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FC0 0000000000000000 03847 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FC8 0000000000000000 03848 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FD0 0000000000000000 03849 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FD8 0000000000000000 03850 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FE0 0000000000000000 03851 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FE8 0000000000000000 03852 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FF0 0000000000000000 03853 DB $00,$00,$00,$00,$00,$00,$00,$00 +8FF8 0000000000000000 03854 DB $00,$00,$00,$00,$00,$00,$00,$00 +9000 0000000000000000 03855 DB $00,$00,$00,$00,$00,$00,$00,$00 +9008 0000000000000000 03856 DB $00,$00,$00,$00,$00,$00,$00,$00 +9010 0000000000000000 03857 DB $00,$00,$00,$00,$00,$00,$00,$00 +9018 0000000000000000 03858 DB $00,$00,$00,$00,$00,$00,$00,$00 +9020 0000000000000000 03859 DB $00,$00,$00,$00,$00,$00,$00,$00 +9028 0000000000000000 03860 DB $00,$00,$00,$00,$00,$00,$00,$00 +9030 0000000000000000 03861 DB $00,$00,$00,$00,$00,$00,$00,$00 +9038 0000000000000000 03862 DB $00,$00,$00,$00,$00,$00,$00,$00 +9040 0000000000000000 03863 DB $00,$00,$00,$00,$00,$00,$00,$00 +9048 0000000000000000 03864 DB $00,$00,$00,$00,$00,$00,$00,$00 +9050 0000000000000000 03865 DB $00,$00,$00,$00,$00,$00,$00,$00 +9058 0000000000000000 03866 DB $00,$00,$00,$00,$00,$00,$00,$00 +9060 0000000000000000 03867 DB $00,$00,$00,$00,$00,$00,$00,$00 +9068 0000000000000000 03868 DB $00,$00,$00,$00,$00,$00,$00,$00 +9070 0000000000000000 03869 DB $00,$00,$00,$00,$00,$00,$00,$00 +9078 0000000000000000 03870 DB $00,$00,$00,$00,$00,$00,$00,$00 +9080 0000000000000000 03871 DB $00,$00,$00,$00,$00,$00,$00,$00 +9088 0000000000000000 03872 DB $00,$00,$00,$00,$00,$00,$00,$00 +9090 0000000000000000 03873 DB $00,$00,$00,$00,$00,$00,$00,$00 +9098 0000000000000000 03874 DB $00,$00,$00,$00,$00,$00,$00,$00 +90A0 0000000000000000 03875 DB $00,$00,$00,$00,$00,$00,$00,$00 +90A8 0000000000000000 03876 DB $00,$00,$00,$00,$00,$00,$00,$00 +90B0 0000000000000000 03877 DB $00,$00,$00,$00,$00,$00,$00,$00 +90B8 0000000000000000 03878 DB $00,$00,$00,$00,$00,$00,$00,$00 +90C0 0000000000000000 03879 DB $00,$00,$00,$00,$00,$00,$00,$00 +90C8 0000000000000000 03880 DB $00,$00,$00,$00,$00,$00,$00,$00 +90D0 0000000000000000 03881 DB $00,$00,$00,$00,$00,$00,$00,$00 +90D8 0000000000000000 03882 DB $00,$00,$00,$00,$00,$00,$00,$00 +90E0 0000000000000000 03883 DB $00,$00,$00,$00,$00,$00,$00,$00 +90E8 0000000000000000 03884 DB $00,$00,$00,$00,$00,$00,$00,$00 +90F0 0000000000000000 03885 DB $00,$00,$00,$00,$00,$00,$00,$00 +90F8 0000000000000000 03886 DB $00,$00,$00,$00,$00,$00,$00,$00 +9100 0000000000000000 03887 DB $00,$00,$00,$00,$00,$00,$00,$00 +9108 0000000000000000 03888 DB $00,$00,$00,$00,$00,$00,$00,$00 +9110 0000000000000000 03889 DB $00,$00,$00,$00,$00,$00,$00,$00 +9118 0000000000000000 03890 DB $00,$00,$00,$00,$00,$00,$00,$00 +9120 0000000000000000 03891 DB $00,$00,$00,$00,$00,$00,$00,$00 +9128 0000000000000000 03892 DB $00,$00,$00,$00,$00,$00,$00,$00 +9130 0000000000000000 03893 DB $00,$00,$00,$00,$00,$00,$00,$00 +9138 0000000000000000 03894 DB $00,$00,$00,$00,$00,$00,$00,$00 +9140 0000000000000000 03895 DB $00,$00,$00,$00,$00,$00,$00,$00 +9148 0000000000000000 03896 DB $00,$00,$00,$00,$00,$00,$00,$00 +9150 0000000000000000 03897 DB $00,$00,$00,$00,$00,$00,$00,$00 +9158 0000000000000000 03898 DB $00,$00,$00,$00,$00,$00,$00,$00 +9160 0000000000000000 03899 DB $00,$00,$00,$00,$00,$00,$00,$00 +9168 0000000000000000 03900 DB $00,$00,$00,$00,$00,$00,$00,$00 +9170 0000000000000000 03901 DB $00,$00,$00,$00,$00,$00,$00,$00 +9178 0000000000000000 03902 DB $00,$00,$00,$00,$00,$00,$00,$00 +9180 0000000000000000 03903 DB $00,$00,$00,$00,$00,$00,$00,$00 +9188 0000000000000000 03904 DB $00,$00,$00,$00,$00,$00,$00,$00 +9190 0000000000000000 03905 DB $00,$00,$00,$00,$00,$00,$00,$00 +9198 0000000000000000 03906 DB $00,$00,$00,$00,$00,$00,$00,$00 +91A0 0000000000000000 03907 DB $00,$00,$00,$00,$00,$00,$00,$00 +91A8 0000000000000000 03908 DB $00,$00,$00,$00,$00,$00,$00,$00 +91B0 0000000000000000 03909 DB $00,$00,$00,$00,$00,$00,$00,$00 +91B8 0000000000000000 03910 DB $00,$00,$00,$00,$00,$00,$00,$00 +91C0 0000000000000000 03911 DB $00,$00,$00,$00,$00,$00,$00,$00 +91C8 0000000000000000 03912 DB $00,$00,$00,$00,$00,$00,$00,$00 +91D0 0000000000000000 03913 DB $00,$00,$00,$00,$00,$00,$00,$00 +91D8 0000000000000000 03914 DB $00,$00,$00,$00,$00,$00,$00,$00 +91E0 0000000000000000 03915 DB $00,$00,$00,$00,$00,$00,$00,$00 +91E8 0000000000000000 03916 DB $00,$00,$00,$00,$00,$00,$00,$00 +91F0 0000000000000000 03917 DB $00,$00,$00,$00,$00,$00,$00,$00 +91F8 0000000000000000 03918 DB $00,$00,$00,$00,$00,$00,$00,$00 +9200 0000000000000000 03919 DB $00,$00,$00,$00,$00,$00,$00,$00 +9208 0000000000000000 03920 DB $00,$00,$00,$00,$00,$00,$00,$00 +9210 0000000000000000 03921 DB $00,$00,$00,$00,$00,$00,$00,$00 +9218 0000000000000000 03922 DB $00,$00,$00,$00,$00,$00,$00,$00 +9220 0000000000000000 03923 DB $00,$00,$00,$00,$00,$00,$00,$00 +9228 0000000000000000 03924 DB $00,$00,$00,$00,$00,$00,$00,$00 +9230 0000000000000000 03925 DB $00,$00,$00,$00,$00,$00,$00,$00 +9238 0000000000000000 03926 DB $00,$00,$00,$00,$00,$00,$00,$00 +9240 0000000000000000 03927 DB $00,$00,$00,$00,$00,$00,$00,$00 +9248 0000000000000000 03928 DB $00,$00,$00,$00,$00,$00,$00,$00 +9250 0000000000000000 03929 DB $00,$00,$00,$00,$00,$00,$00,$00 +9258 0000000000000000 03930 DB $00,$00,$00,$00,$00,$00,$00,$00 +9260 0000000000000000 03931 DB $00,$00,$00,$00,$00,$00,$00,$00 +9268 0000000000000000 03932 DB $00,$00,$00,$00,$00,$00,$00,$00 +9270 0000000000000000 03933 DB $00,$00,$00,$00,$00,$00,$00,$00 +9278 0000000000000000 03934 DB $00,$00,$00,$00,$00,$00,$00,$00 +9280 0000000000000000 03935 DB $00,$00,$00,$00,$00,$00,$00,$00 +9288 0000000000000000 03936 DB $00,$00,$00,$00,$00,$00,$00,$00 +9290 0000000000000000 03937 DB $00,$00,$00,$00,$00,$00,$00,$00 +9298 0000000000000000 03938 DB $00,$00,$00,$00,$00,$00,$00,$00 +92A0 0000000000000000 03939 DB $00,$00,$00,$00,$00,$00,$00,$00 +92A8 0000000000000000 03940 DB $00,$00,$00,$00,$00,$00,$00,$00 +92B0 0000000000000000 03941 DB $00,$00,$00,$00,$00,$00,$00,$00 +92B8 0000000000000000 03942 DB $00,$00,$00,$00,$00,$00,$00,$00 +92C0 0000000000000000 03943 DB $00,$00,$00,$00,$00,$00,$00,$00 +92C8 0000000000000000 03944 DB $00,$00,$00,$00,$00,$00,$00,$00 +92D0 0000000000000000 03945 DB $00,$00,$00,$00,$00,$00,$00,$00 +92D8 0000000000000000 03946 DB $00,$00,$00,$00,$00,$00,$00,$00 +92E0 0000000000000000 03947 DB $00,$00,$00,$00,$00,$00,$00,$00 +92E8 0000000000000000 03948 DB $00,$00,$00,$00,$00,$00,$00,$00 +92F0 0000000000000000 03949 DB $00,$00,$00,$00,$00,$00,$00,$00 +92F8 0000000000000000 03950 DB $00,$00,$00,$00,$00,$00,$00,$00 +9300 0000000000000000 03951 DB $00,$00,$00,$00,$00,$00,$00,$00 +9308 0000000000000000 03952 DB $00,$00,$00,$00,$00,$00,$00,$00 +9310 0000000000000000 03953 DB $00,$00,$00,$00,$00,$00,$00,$00 +9318 0000000000000000 03954 DB $00,$00,$00,$00,$00,$00,$00,$00 +9320 0000000000000000 03955 DB $00,$00,$00,$00,$00,$00,$00,$00 +9328 0000000000000000 03956 DB $00,$00,$00,$00,$00,$00,$00,$00 +9330 0000000000000000 03957 DB $00,$00,$00,$00,$00,$00,$00,$00 +9338 0000000000000000 03958 DB $00,$00,$00,$00,$00,$00,$00,$00 +9340 0000000000000000 03959 DB $00,$00,$00,$00,$00,$00,$00,$00 +9348 0000000000000000 03960 DB $00,$00,$00,$00,$00,$00,$00,$00 +9350 0000000000000000 03961 DB $00,$00,$00,$00,$00,$00,$00,$00 +9358 0000000000000000 03962 DB $00,$00,$00,$00,$00,$00,$00,$00 +9360 0000000000000000 03963 DB $00,$00,$00,$00,$00,$00,$00,$00 +9368 0000000000000000 03964 DB $00,$00,$00,$00,$00,$00,$00,$00 +9370 0000000000000000 03965 DB $00,$00,$00,$00,$00,$00,$00,$00 +9378 0000000000000000 03966 DB $00,$00,$00,$00,$00,$00,$00,$00 +9380 0000000000000000 03967 DB $00,$00,$00,$00,$00,$00,$00,$00 +9388 0000000000000000 03968 DB $00,$00,$00,$00,$00,$00,$00,$00 +9390 0000000000000000 03969 DB $00,$00,$00,$00,$00,$00,$00,$00 +9398 0000000000000000 03970 DB $00,$00,$00,$00,$00,$00,$00,$00 +93A0 0000000000000000 03971 DB $00,$00,$00,$00,$00,$00,$00,$00 +93A8 0000000000000000 03972 DB $00,$00,$00,$00,$00,$00,$00,$00 +93B0 0000000000000000 03973 DB $00,$00,$00,$00,$00,$00,$00,$00 +93B8 0000000000000000 03974 DB $00,$00,$00,$00,$00,$00,$00,$00 +93C0 0000000000000000 03975 DB $00,$00,$00,$00,$00,$00,$00,$00 +93C8 0000000000000000 03976 DB $00,$00,$00,$00,$00,$00,$00,$00 +93D0 0000000000000000 03977 DB $00,$00,$00,$00,$00,$00,$00,$00 +93D8 0000000000000000 03978 DB $00,$00,$00,$00,$00,$00,$00,$00 +93E0 0000000000000000 03979 DB $00,$00,$00,$00,$00,$00,$00,$00 +93E8 0000000000000000 03980 DB $00,$00,$00,$00,$00,$00,$00,$00 +93F0 0000000000000000 03981 DB $00,$00,$00,$00,$00,$00,$00,$00 +93F8 0000000000000000 03982 DB $00,$00,$00,$00,$00,$00,$00,$00 +9400 0000000000000000 03983 DB $00,$00,$00,$00,$00,$00,$00,$00 +9408 0000000000000000 03984 DB $00,$00,$00,$00,$00,$00,$00,$00 +9410 0000000000000000 03985 DB $00,$00,$00,$00,$00,$00,$00,$00 +9418 0000000000000000 03986 DB $00,$00,$00,$00,$00,$00,$00,$00 +9420 0000000000000000 03987 DB $00,$00,$00,$00,$00,$00,$00,$00 +9428 0000000000000000 03988 DB $00,$00,$00,$00,$00,$00,$00,$00 +9430 0000000000000000 03989 DB $00,$00,$00,$00,$00,$00,$00,$00 +9438 0000000000000000 03990 DB $00,$00,$00,$00,$00,$00,$00,$00 +9440 0000000000000000 03991 DB $00,$00,$00,$00,$00,$00,$00,$00 +9448 0000000000000000 03992 DB $00,$00,$00,$00,$00,$00,$00,$00 +9450 0000000000000000 03993 DB $00,$00,$00,$00,$00,$00,$00,$00 +9458 0000000000000000 03994 DB $00,$00,$00,$00,$00,$00,$00,$00 +9460 0000000000000000 03995 DB $00,$00,$00,$00,$00,$00,$00,$00 +9468 0000000000000000 03996 DB $00,$00,$00,$00,$00,$00,$00,$00 +9470 0000000000000000 03997 DB $00,$00,$00,$00,$00,$00,$00,$00 +9478 0000000000000000 03998 DB $00,$00,$00,$00,$00,$00,$00,$00 +9480 0000000000000000 03999 DB $00,$00,$00,$00,$00,$00,$00,$00 +9488 0000000000000000 04000 DB $00,$00,$00,$00,$00,$00,$00,$00 +9490 0000000000000000 04001 DB $00,$00,$00,$00,$00,$00,$00,$00 +9498 0000000000000000 04002 DB $00,$00,$00,$00,$00,$00,$00,$00 +94A0 0000000000000000 04003 DB $00,$00,$00,$00,$00,$00,$00,$00 +94A8 0000000000000000 04004 DB $00,$00,$00,$00,$00,$00,$00,$00 +94B0 0000000000000000 04005 DB $00,$00,$00,$00,$00,$00,$00,$00 +94B8 0000000000000000 04006 DB $00,$00,$00,$00,$00,$00,$00,$00 +94C0 0000000000000000 04007 DB $00,$00,$00,$00,$00,$00,$00,$00 +94C8 0000000000000000 04008 DB $00,$00,$00,$00,$00,$00,$00,$00 +94D0 0000000000000000 04009 DB $00,$00,$00,$00,$00,$00,$00,$00 +94D8 0000000000000000 04010 DB $00,$00,$00,$00,$00,$00,$00,$00 +94E0 0000000000000000 04011 DB $00,$00,$00,$00,$00,$00,$00,$00 +94E8 0000000000000000 04012 DB $00,$00,$00,$00,$00,$00,$00,$00 +94F0 0000000000000000 04013 DB $00,$00,$00,$00,$00,$00,$00,$00 +94F8 0000000000000000 04014 DB $00,$00,$00,$00,$00,$00,$00,$00 +9500 0000000000000000 04015 DB $00,$00,$00,$00,$00,$00,$00,$00 +9508 0000000000000000 04016 DB $00,$00,$00,$00,$00,$00,$00,$00 +9510 0000000000000000 04017 DB $00,$00,$00,$00,$00,$00,$00,$00 +9518 0000000000000000 04018 DB $00,$00,$00,$00,$00,$00,$00,$00 +9520 0000000000000000 04019 DB $00,$00,$00,$00,$00,$00,$00,$00 +9528 0000000000000000 04020 DB $00,$00,$00,$00,$00,$00,$00,$00 +9530 0000000000000000 04021 DB $00,$00,$00,$00,$00,$00,$00,$00 +9538 0000000000000000 04022 DB $00,$00,$00,$00,$00,$00,$00,$00 +9540 0000000000000000 04023 DB $00,$00,$00,$00,$00,$00,$00,$00 +9548 0000000000000000 04024 DB $00,$00,$00,$00,$00,$00,$00,$00 +9550 0000000000000000 04025 DB $00,$00,$00,$00,$00,$00,$00,$00 +9558 0000000000000000 04026 DB $00,$00,$00,$00,$00,$00,$00,$00 +9560 0000000000000000 04027 DB $00,$00,$00,$00,$00,$00,$00,$00 +9568 0000000000000000 04028 DB $00,$00,$00,$00,$00,$00,$00,$00 +9570 0000000000000000 04029 DB $00,$00,$00,$00,$00,$00,$00,$00 +9578 0000000000000000 04030 DB $00,$00,$00,$00,$00,$00,$00,$00 +9580 0000000000000000 04031 DB $00,$00,$00,$00,$00,$00,$00,$00 +9588 0000000000000000 04032 DB $00,$00,$00,$00,$00,$00,$00,$00 +9590 0000000000000000 04033 DB $00,$00,$00,$00,$00,$00,$00,$00 +9598 0000000000000000 04034 DB $00,$00,$00,$00,$00,$00,$00,$00 +95A0 0000000000000000 04035 DB $00,$00,$00,$00,$00,$00,$00,$00 +95A8 0000000000000000 04036 DB $00,$00,$00,$00,$00,$00,$00,$00 +95B0 0000000000000000 04037 DB $00,$00,$00,$00,$00,$00,$00,$00 +95B8 0000000000000000 04038 DB $00,$00,$00,$00,$00,$00,$00,$00 +95C0 0000000000000000 04039 DB $00,$00,$00,$00,$00,$00,$00,$00 +95C8 0000000000000000 04040 DB $00,$00,$00,$00,$00,$00,$00,$00 +95D0 0000000000000000 04041 DB $00,$00,$00,$00,$00,$00,$00,$00 +95D8 0000000000000000 04042 DB $00,$00,$00,$00,$00,$00,$00,$00 +95E0 0000000000000000 04043 DB $00,$00,$00,$00,$00,$00,$00,$00 +95E8 0000000000000000 04044 DB $00,$00,$00,$00,$00,$00,$00,$00 +95F0 0000000000000000 04045 DB $00,$00,$00,$00,$00,$00,$00,$00 +95F8 0000000000000000 04046 DB $00,$00,$00,$00,$00,$00,$00,$00 +9600 0000000000000000 04047 DB $00,$00,$00,$00,$00,$00,$00,$00 +9608 0000000000000000 04048 DB $00,$00,$00,$00,$00,$00,$00,$00 +9610 0000000000000000 04049 DB $00,$00,$00,$00,$00,$00,$00,$00 +9618 0000000000000000 04050 DB $00,$00,$00,$00,$00,$00,$00,$00 +9620 0000000000000000 04051 DB $00,$00,$00,$00,$00,$00,$00,$00 +9628 0000000000000000 04052 DB $00,$00,$00,$00,$00,$00,$00,$00 +9630 0000000000000000 04053 DB $00,$00,$00,$00,$00,$00,$00,$00 +9638 0000000000000000 04054 DB $00,$00,$00,$00,$00,$00,$00,$00 +9640 0000000000000000 04055 DB $00,$00,$00,$00,$00,$00,$00,$00 +9648 0000000000000000 04056 DB $00,$00,$00,$00,$00,$00,$00,$00 +9650 0000000000000000 04057 DB $00,$00,$00,$00,$00,$00,$00,$00 +9658 0000000000000000 04058 DB $00,$00,$00,$00,$00,$00,$00,$00 +9660 0000000000000000 04059 DB $00,$00,$00,$00,$00,$00,$00,$00 +9668 0000000000000000 04060 DB $00,$00,$00,$00,$00,$00,$00,$00 +9670 0000000000000000 04061 DB $00,$00,$00,$00,$00,$00,$00,$00 +9678 0000000000000000 04062 DB $00,$00,$00,$00,$00,$00,$00,$00 +9680 0000000000000000 04063 DB $00,$00,$00,$00,$00,$00,$00,$00 +9688 0000000000000000 04064 DB $00,$00,$00,$00,$00,$00,$00,$00 +9690 0000000000000000 04065 DB $00,$00,$00,$00,$00,$00,$00,$00 +9698 0000000000000000 04066 DB $00,$00,$00,$00,$00,$00,$00,$00 +96A0 0000000000000000 04067 DB $00,$00,$00,$00,$00,$00,$00,$00 +96A8 0000000000000000 04068 DB $00,$00,$00,$00,$00,$00,$00,$00 +96B0 0000000000000000 04069 DB $00,$00,$00,$00,$00,$00,$00,$00 +96B8 0000000000000000 04070 DB $00,$00,$00,$00,$00,$00,$00,$00 +96C0 0000000000000000 04071 DB $00,$00,$00,$00,$00,$00,$00,$00 +96C8 0000000000000000 04072 DB $00,$00,$00,$00,$00,$00,$00,$00 +96D0 0000000000000000 04073 DB $00,$00,$00,$00,$00,$00,$00,$00 +96D8 0000000000000000 04074 DB $00,$00,$00,$00,$00,$00,$00,$00 +96E0 0000000000000000 04075 DB $00,$00,$00,$00,$00,$00,$00,$00 +96E8 0000000000000000 04076 DB $00,$00,$00,$00,$00,$00,$00,$00 +96F0 0000000000000000 04077 DB $00,$00,$00,$00,$00,$00,$00,$00 +96F8 0000000000000000 04078 DB $00,$00,$00,$00,$00,$00,$00,$00 +9700 0000000000000000 04079 DB $00,$00,$00,$00,$00,$00,$00,$00 +9708 0000000000000000 04080 DB $00,$00,$00,$00,$00,$00,$00,$00 +9710 0000000000000000 04081 DB $00,$00,$00,$00,$00,$00,$00,$00 +9718 0000000000000000 04082 DB $00,$00,$00,$00,$00,$00,$00,$00 +9720 0000000000000000 04083 DB $00,$00,$00,$00,$00,$00,$00,$00 +9728 0000000000000000 04084 DB $00,$00,$00,$00,$00,$00,$00,$00 +9730 0000000000000000 04085 DB $00,$00,$00,$00,$00,$00,$00,$00 +9738 0000000000000000 04086 DB $00,$00,$00,$00,$00,$00,$00,$00 +9740 0000000000000000 04087 DB $00,$00,$00,$00,$00,$00,$00,$00 +9748 0000000000000000 04088 DB $00,$00,$00,$00,$00,$00,$00,$00 +9750 0000000000000000 04089 DB $00,$00,$00,$00,$00,$00,$00,$00 +9758 0000000000000000 04090 DB $00,$00,$00,$00,$00,$00,$00,$00 +9760 0000000000000000 04091 DB $00,$00,$00,$00,$00,$00,$00,$00 +9768 0000000000000000 04092 DB $00,$00,$00,$00,$00,$00,$00,$00 +9770 0000000000000000 04093 DB $00,$00,$00,$00,$00,$00,$00,$00 +9778 0000000000000000 04094 DB $00,$00,$00,$00,$00,$00,$00,$00 +9780 0000000000000000 04095 DB $00,$00,$00,$00,$00,$00,$00,$00 +9788 0000000000000000 04096 DB $00,$00,$00,$00,$00,$00,$00,$00 +9790 0000000000000000 04097 DB $00,$00,$00,$00,$00,$00,$00,$00 +9798 0000000000000000 04098 DB $00,$00,$00,$00,$00,$00,$00,$00 +97A0 0000000000000000 04099 DB $00,$00,$00,$00,$00,$00,$00,$00 +97A8 0000000000000000 04100 DB $00,$00,$00,$00,$00,$00,$00,$00 +97B0 0000000000000000 04101 DB $00,$00,$00,$00,$00,$00,$00,$00 +97B8 0000000000000000 04102 DB $00,$00,$00,$00,$00,$00,$00,$00 +97C0 0000000000000000 04103 DB $00,$00,$00,$00,$00,$00,$00,$00 +97C8 0000000000000000 04104 DB $00,$00,$00,$00,$00,$00,$00,$00 +97D0 0000000000000000 04105 DB $00,$00,$00,$00,$00,$00,$00,$00 +97D8 0000000000000000 04106 DB $00,$00,$00,$00,$00,$00,$00,$00 +97E0 0000000000000000 04107 DB $00,$00,$00,$00,$00,$00,$00,$00 +97E8 0000000000000000 04108 DB $00,$00,$00,$00,$00,$00,$00,$00 +97F0 0000000000000000 04109 DB $00,$00,$00,$00,$00,$00,$00,$00 +97F8 0000000000000000 04110 DB $00,$00,$00,$00,$00,$00,$00,$00 +9800 0000000000000000 04111 DB $00,$00,$00,$00,$00,$00,$00,$00 +9808 0000000000000000 04112 DB $00,$00,$00,$00,$00,$00,$00,$00 +9810 0000000000000000 04113 DB $00,$00,$00,$00,$00,$00,$00,$00 +9818 0000000000000000 04114 DB $00,$00,$00,$00,$00,$00,$00,$00 +9820 0000000000000000 04115 DB $00,$00,$00,$00,$00,$00,$00,$00 +9828 0000000000000000 04116 DB $00,$00,$00,$00,$00,$00,$00,$00 +9830 0000000000000000 04117 DB $00,$00,$00,$00,$00,$00,$00,$00 +9838 0000000000000000 04118 DB $00,$00,$00,$00,$00,$00,$00,$00 +9840 0000000000000000 04119 DB $00,$00,$00,$00,$00,$00,$00,$00 +9848 0000000000000000 04120 DB $00,$00,$00,$00,$00,$00,$00,$00 +9850 0000000000000000 04121 DB $00,$00,$00,$00,$00,$00,$00,$00 +9858 0000000000000000 04122 DB $00,$00,$00,$00,$00,$00,$00,$00 +9860 0000000000000000 04123 DB $00,$00,$00,$00,$00,$00,$00,$00 +9868 0000000000000000 04124 DB $00,$00,$00,$00,$00,$00,$00,$00 +9870 0000000000000000 04125 DB $00,$00,$00,$00,$00,$00,$00,$00 +9878 0000000000000000 04126 DB $00,$00,$00,$00,$00,$00,$00,$00 +9880 0000000000000000 04127 DB $00,$00,$00,$00,$00,$00,$00,$00 +9888 0000000000000000 04128 DB $00,$00,$00,$00,$00,$00,$00,$00 +9890 0000000000000000 04129 DB $00,$00,$00,$00,$00,$00,$00,$00 +9898 0000000000000000 04130 DB $00,$00,$00,$00,$00,$00,$00,$00 +98A0 0000000000000000 04131 DB $00,$00,$00,$00,$00,$00,$00,$00 +98A8 0000000000000000 04132 DB $00,$00,$00,$00,$00,$00,$00,$00 +98B0 0000000000000000 04133 DB $00,$00,$00,$00,$00,$00,$00,$00 +98B8 0000000000000000 04134 DB $00,$00,$00,$00,$00,$00,$00,$00 +98C0 0000000000000000 04135 DB $00,$00,$00,$00,$00,$00,$00,$00 +98C8 0000000000000000 04136 DB $00,$00,$00,$00,$00,$00,$00,$00 +98D0 0000000000000000 04137 DB $00,$00,$00,$00,$00,$00,$00,$00 +98D8 0000000000000000 04138 DB $00,$00,$00,$00,$00,$00,$00,$00 +98E0 0000000000000000 04139 DB $00,$00,$00,$00,$00,$00,$00,$00 +98E8 0000000000000000 04140 DB $00,$00,$00,$00,$00,$00,$00,$00 +98F0 0000000000000000 04141 DB $00,$00,$00,$00,$00,$00,$00,$00 +98F8 0000000000000000 04142 DB $00,$00,$00,$00,$00,$00,$00,$00 +9900 0000000000000000 04143 DB $00,$00,$00,$00,$00,$00,$00,$00 +9908 0000000000000000 04144 DB $00,$00,$00,$00,$00,$00,$00,$00 +9910 0000000000000000 04145 DB $00,$00,$00,$00,$00,$00,$00,$00 +9918 0000000000000000 04146 DB $00,$00,$00,$00,$00,$00,$00,$00 +9920 0000000000000000 04147 DB $00,$00,$00,$00,$00,$00,$00,$00 +9928 0000000000000000 04148 DB $00,$00,$00,$00,$00,$00,$00,$00 +9930 0000000000000000 04149 DB $00,$00,$00,$00,$00,$00,$00,$00 +9938 0000000000000000 04150 DB $00,$00,$00,$00,$00,$00,$00,$00 +9940 0000000000000000 04151 DB $00,$00,$00,$00,$00,$00,$00,$00 +9948 0000000000000000 04152 DB $00,$00,$00,$00,$00,$00,$00,$00 +9950 0000000000000000 04153 DB $00,$00,$00,$00,$00,$00,$00,$00 +9958 0000000000000000 04154 DB $00,$00,$00,$00,$00,$00,$00,$00 +9960 0000000000000000 04155 DB $00,$00,$00,$00,$00,$00,$00,$00 +9968 0000000000000000 04156 DB $00,$00,$00,$00,$00,$00,$00,$00 +9970 0000000000000000 04157 DB $00,$00,$00,$00,$00,$00,$00,$00 +9978 0000000000000000 04158 DB $00,$00,$00,$00,$00,$00,$00,$00 +9980 0000000000000000 04159 DB $00,$00,$00,$00,$00,$00,$00,$00 +9988 0000000000000000 04160 DB $00,$00,$00,$00,$00,$00,$00,$00 +9990 0000000000000000 04161 DB $00,$00,$00,$00,$00,$00,$00,$00 +9998 0000000000000000 04162 DB $00,$00,$00,$00,$00,$00,$00,$00 +99A0 0000000000000000 04163 DB $00,$00,$00,$00,$00,$00,$00,$00 +99A8 0000000000000000 04164 DB $00,$00,$00,$00,$00,$00,$00,$00 +99B0 0000000000000000 04165 DB $00,$00,$00,$00,$00,$00,$00,$00 +99B8 0000000000000000 04166 DB $00,$00,$00,$00,$00,$00,$00,$00 +99C0 0000000000000000 04167 DB $00,$00,$00,$00,$00,$00,$00,$00 +99C8 0000000000000000 04168 DB $00,$00,$00,$00,$00,$00,$00,$00 +99D0 0000000000000000 04169 DB $00,$00,$00,$00,$00,$00,$00,$00 +99D8 0000000000000000 04170 DB $00,$00,$00,$00,$00,$00,$00,$00 +99E0 0000000000000000 04171 DB $00,$00,$00,$00,$00,$00,$00,$00 +99E8 0000000000000000 04172 DB $00,$00,$00,$00,$00,$00,$00,$00 +99F0 0000000000000000 04173 DB $00,$00,$00,$00,$00,$00,$00,$00 +99F8 0000000000000000 04174 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A00 0000000000000000 04175 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A08 0000000000000000 04176 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A10 0000000000000000 04177 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A18 0000000000000000 04178 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A20 0000000000000000 04179 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A28 0000000000000000 04180 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A30 0000000000000000 04181 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A38 0000000000000000 04182 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A40 0000000000000000 04183 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A48 0000000000000000 04184 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A50 0000000000000000 04185 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A58 0000000000000000 04186 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A60 0000000000000000 04187 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A68 0000000000000000 04188 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A70 0000000000000000 04189 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A78 0000000000000000 04190 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A80 0000000000000000 04191 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A88 0000000000000000 04192 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A90 0000000000000000 04193 DB $00,$00,$00,$00,$00,$00,$00,$00 +9A98 0000000000000000 04194 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AA0 0000000000000000 04195 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AA8 0000000000000000 04196 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AB0 0000000000000000 04197 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AB8 0000000000000000 04198 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AC0 0000000000000000 04199 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AC8 0000000000000000 04200 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AD0 0000000000000000 04201 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AD8 0000000000000000 04202 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AE0 0000000000000000 04203 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AE8 0000000000000000 04204 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AF0 0000000000000000 04205 DB $00,$00,$00,$00,$00,$00,$00,$00 +9AF8 0000000000000000 04206 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B00 0000000000000000 04207 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B08 0000000000000000 04208 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B10 0000000000000000 04209 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B18 0000000000000000 04210 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B20 0000000000000000 04211 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B28 0000000000000000 04212 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B30 0000000000000000 04213 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B38 0000000000000000 04214 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B40 0000000000000000 04215 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B48 0000000000000000 04216 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B50 0000000000000000 04217 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B58 0000000000000000 04218 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B60 0000000000000000 04219 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B68 0000000000000000 04220 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B70 0000000000000000 04221 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B78 0000000000000000 04222 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B80 0000000000000000 04223 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B88 0000000000000000 04224 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B90 0000000000000000 04225 DB $00,$00,$00,$00,$00,$00,$00,$00 +9B98 0000000000000000 04226 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BA0 0000000000000000 04227 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BA8 0000000000000000 04228 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BB0 0000000000000000 04229 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BB8 0000000000000000 04230 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BC0 0000000000000000 04231 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BC8 0000000000000000 04232 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BD0 0000000000000000 04233 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BD8 0000000000000000 04234 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BE0 0000000000000000 04235 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BE8 0000000000000000 04236 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BF0 0000000000000000 04237 DB $00,$00,$00,$00,$00,$00,$00,$00 +9BF8 0000000000000000 04238 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C00 0000000000000000 04239 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C08 0000000000000000 04240 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C10 0000000000000000 04241 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C18 0000000000000000 04242 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C20 0000000000000000 04243 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C28 0000000000000000 04244 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C30 0000000000000000 04245 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C38 0000000000000000 04246 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C40 0000000000000000 04247 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C48 0000000000000000 04248 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C50 0000000000000000 04249 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C58 0000000000000000 04250 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C60 0000000000000000 04251 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C68 0000000000000000 04252 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C70 0000000000000000 04253 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C78 0000000000000000 04254 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C80 0000000000000000 04255 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C88 0000000000000000 04256 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C90 0000000000000000 04257 DB $00,$00,$00,$00,$00,$00,$00,$00 +9C98 0000000000000000 04258 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CA0 0000000000000000 04259 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CA8 0000000000000000 04260 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CB0 0000000000000000 04261 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CB8 0000000000000000 04262 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CC0 0000000000000000 04263 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CC8 0000000000000000 04264 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CD0 0000000000000000 04265 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CD8 0000000000000000 04266 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CE0 0000000000000000 04267 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CE8 0000000000000000 04268 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CF0 0000000000000000 04269 DB $00,$00,$00,$00,$00,$00,$00,$00 +9CF8 0000000000000000 04270 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D00 0000000000000000 04271 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D08 0000000000000000 04272 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D10 0000000000000000 04273 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D18 0000000000000000 04274 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D20 0000000000000000 04275 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D28 0000000000000000 04276 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D30 0000000000000000 04277 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D38 0000000000000000 04278 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D40 0000000000000000 04279 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D48 0000000000000000 04280 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D50 0000000000000000 04281 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D58 0000000000000000 04282 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D60 0000000000000000 04283 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D68 0000000000000000 04284 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D70 0000000000000000 04285 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D78 0000000000000000 04286 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D80 0000000000000000 04287 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D88 0000000000000000 04288 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D90 0000000000000000 04289 DB $00,$00,$00,$00,$00,$00,$00,$00 +9D98 0000000000000000 04290 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DA0 0000000000000000 04291 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DA8 0000000000000000 04292 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DB0 0000000000000000 04293 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DB8 0000000000000000 04294 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DC0 0000000000000000 04295 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DC8 0000000000000000 04296 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DD0 0000000000000000 04297 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DD8 0000000000000000 04298 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DE0 0000000000000000 04299 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DE8 0000000000000000 04300 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DF0 0000000000000000 04301 DB $00,$00,$00,$00,$00,$00,$00,$00 +9DF8 0000000000000000 04302 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E00 0000000000000000 04303 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E08 0000000000000000 04304 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E10 0000000000000000 04305 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E18 0000000000000000 04306 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E20 0000000000000000 04307 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E28 0000000000000000 04308 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E30 0000000000000000 04309 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E38 0000000000000000 04310 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E40 0000000000000000 04311 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E48 0000000000000000 04312 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E50 0000000000000000 04313 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E58 0000000000000000 04314 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E60 0000000000000000 04315 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E68 0000000000000000 04316 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E70 0000000000000000 04317 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E78 0000000000000000 04318 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E80 0000000000000000 04319 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E88 0000000000000000 04320 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E90 0000000000000000 04321 DB $00,$00,$00,$00,$00,$00,$00,$00 +9E98 0000000000000000 04322 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EA0 0000000000000000 04323 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EA8 0000000000000000 04324 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EB0 0000000000000000 04325 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EB8 0000000000000000 04326 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EC0 0000000000000000 04327 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EC8 0000000000000000 04328 DB $00,$00,$00,$00,$00,$00,$00,$00 +9ED0 0000000000000000 04329 DB $00,$00,$00,$00,$00,$00,$00,$00 +9ED8 0000000000000000 04330 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EE0 0000000000000000 04331 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EE8 0000000000000000 04332 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EF0 0000000000000000 04333 DB $00,$00,$00,$00,$00,$00,$00,$00 +9EF8 0000000000000000 04334 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F00 0000000000000000 04335 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F08 0000000000000000 04336 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F10 0000000000000000 04337 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F18 0000000000000000 04338 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F20 0000000000000000 04339 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F28 0000000000000000 04340 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F30 0000000000000000 04341 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F38 0000000000000000 04342 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F40 0000000000000000 04343 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F48 0000000000000000 04344 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F50 0000000000000000 04345 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F58 0000000000000000 04346 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F60 0000000000000000 04347 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F68 0000000000000000 04348 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F70 0000000000000000 04349 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F78 0000000000000000 04350 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F80 0000000000000000 04351 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F88 0000000000000000 04352 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F90 0000000000000000 04353 DB $00,$00,$00,$00,$00,$00,$00,$00 +9F98 0000000000000000 04354 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FA0 0000000000000000 04355 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FA8 0000000000000000 04356 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FB0 0000000000000000 04357 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FB8 0000000000000000 04358 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FC0 0000000000000000 04359 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FC8 0000000000000000 04360 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FD0 0000000000000000 04361 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FD8 0000000000000000 04362 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FE0 0000000000000000 04363 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FE8 0000000000000000 04364 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FF0 0000000000000000 04365 DB $00,$00,$00,$00,$00,$00,$00,$00 +9FF8 0000000000000000 04366 DB $00,$00,$00,$00,$00,$00,$00,$00 + +00000 ERRORS FOUND +00000 WARNINGS FOUND + +114722 PROGRAM BYTES + +LABEL VALUE/ADDRESS + +AUDIO_FREQ1 0042 +AUDIO_FREQ2 0044 +AUDIO_FREQ3 0046 +AUDIO_NOISE 004c +AUDIO_VOL1 0048 +AUDIO_VOL2 0049 +AUDIO_VOL3 004a +AUDIO_VOL4HW 004b +BANKSEL c000 +BANK_0_FREE 34fb +BANK_1_FREE 3de2 +BANK_2_FREE 3f05 +BASE_RAM 0050 +CHRRAM_BANK 001c +CLEAR_SPRITES c57a +CLEAR_SPRITES.1 c57e +CLS c0c6 +CLS.1 c0c8 +CLS.2 c0d3 +CLS.3 c0d5 +COLECO 0000 +CONT1 4016 +CONT2 4017 +CONT_BITS 001d +CONVERT_JOYSTICK c42e +COPY_CHRRAM c909 +COPY_CHRRAM.1 c917 +COPY_PAGE c91e +COPY_PAGE.1 c920 +CPM 0000 +CPYBLK c07a +CPYBLK.1 c07a +CURSOR 000c +CV1 cafc +CV2 caff +CVBASIC_BANK_ROM_SIZE 0100 +CVBASIC_BANK_SWITCHING 0001 +CVBASIC_COMPRESSION 0000 +CVBASIC_MUSIC_PLAYER 0001 +CVB_DISPLAY_SOME_TEXT 8000 +CVB_IMAGE_PATTERN 803a +CVB_TUNE_1 8000 +DISSCR c073 +EINSTEIN 0000 +ENASCR c06c +FLICKER 0011 +FRAME 0012 +IRQ_HANDLER c2e2 +JOY1_DATA 0020 +JOY2_DATA 0021 +KEY1_DATA 0022 +KEY2_DATA 0023 +LDIRVM c03a +LDIRVM.1 c069 +LDIRVM2 c02b +LDIRVM2.1 c039 +LDIRVM4 c01e +LFSR 001e +MEMOTECH 0000 +MODE 000e +MODE_0 c577 +MSX 0000 +MUSIC_BANK 0030 +MUSIC_BASS c741 +MUSIC_BASS.1 c751 +MUSIC_CLARINET c78f +MUSIC_CLARINET.1 c7ad +MUSIC_CLARINET.2 c7c5 +MUSIC_CLARINET.3 c79f +MUSIC_COUNTER_1 0039 +MUSIC_COUNTER_2 003c +MUSIC_COUNTER_3 003f +MUSIC_COUNTER_4 0041 +MUSIC_DRUM 0040 +MUSIC_FLUTE c6f3 +MUSIC_FLUTE.1 c707 +MUSIC_FLUTE.2 c71f +MUSIC_GENERATE c5cb +MUSIC_GENERATE.1 c5dc +MUSIC_GENERATE.10 c68f +MUSIC_GENERATE.11 c6cd +MUSIC_GENERATE.12 c6a8 +MUSIC_GENERATE.14 c6bd +MUSIC_GENERATE.15 c69d +MUSIC_GENERATE.2 c65c +MUSIC_GENERATE.3 c5f0 +MUSIC_GENERATE.4 c5ff +MUSIC_GENERATE.5 c61a +MUSIC_GENERATE.6 c630 +MUSIC_GENERATE.7 c646 +MUSIC_GENERATE.8 c66d +MUSIC_GENERATE.9 c67e +MUSIC_HARDWARE c85d +MUSIC_HARDWARE.1 c8e3 +MUSIC_HARDWARE.2 c8e5 +MUSIC_HARDWARE.3 c891 +MUSIC_HARDWARE.4 c8ad +MUSIC_HARDWARE.5 c8d3 +MUSIC_HARDWARE.6 c8e8 +MUSIC_HARDWARE.7 c8fd +MUSIC_HARDWARE.8 c902 +MUSIC_HARDWARE.9 c87f +MUSIC_INIT c588 +MUSIC_INSTRUMENT_1 0037 +MUSIC_INSTRUMENT_2 003a +MUSIC_INSTRUMENT_3 003d +MUSIC_MODE 004e +MUSIC_NOTE2FREQ c737 +MUSIC_NOTES_TABLE c7dd +MUSIC_NOTE_1 0038 +MUSIC_NOTE_2 003b +MUSIC_NOTE_3 003e +MUSIC_NOTE_COUNTER 0036 +MUSIC_PIANO c769 +MUSIC_PIANO.1 c777 +MUSIC_PLAY c5a6 +MUSIC_PLAYING 004f +MUSIC_POINTER 0034 +MUSIC_SILENCE c903 +MUSIC_START 0032 +MUSIC_TICK 004d +MUSIC_TIMING 0031 +NABU 0000 +NES_CHR_BANKS 0001 +NES_NAMETABLE 0000 +NES_PRG_BANKS 0010 +NMI_HANDLER c2e3 +NMI_HANDLER.0 c30c +NMI_HANDLER.1 c362 +NMI_HANDLER.10 c3ce +NMI_HANDLER.11 c35e +NMI_HANDLER.12 c3eb +NMI_HANDLER.14 c3e7 +NMI_HANDLER.2 c34c +NMI_HANDLER.3 c354 +NMI_HANDLER.4 c32f +NMI_HANDLER.5 c2fc +NMI_HANDLER.6 c2fe +NMI_HANDLER.7 c33e +NMI_HANDLER.8 c3d4 +NMI_HANDLER.9 c3f2 +NTSC 000f +OAMADDR 2003 +PENCIL 0000 +POINTER 0008 +PPUADDR 2006 +PPUBUF 0100 +PPUCTRL 2000 +PPUDATA 2007 +PPUMASK 2001 +PPUSCROLL 2005 +PPUSTATUS 2002 +PPU_CTRL 0016 +PPU_MASK 0017 +PPU_POINTER 0014 +PPU_SOURCE 0000 +PPU_TEMP 0015 +PRINT_CHAR c55e +PRINT_CHAR.1 c573 +PRINT_DIGIT c52f +PRINT_DIGIT.2 c531 +PRINT_DIGIT.3 c558 +PRINT_DIGIT.4 c54f +PRINT_DIGIT.6 c556 +PRINT_NUMBER c4ef +PRINT_NUMBER1 c520 +PRINT_NUMBER2 c515 +PRINT_NUMBER3 c50a +PRINT_NUMBER4 c4ff +PRINT_NUMBER5 c4f4 +PRINT_STRING c492 +PRINT_STRING.1 c4ee +PRINT_STRING.2 c4a4 +PRINT_STRING_CURSOR c48e +PRINT_STRING_CURSOR_CONSTANT c46a +PSG 0000 +PV2000 0000 +RAM_END ca4b +RAM_SIZE 0800 +RANDOM c2b3 +RANDOM.0 c2c1 +READ_POINTER 000a +RESULT 0006 +ROM_END c000 +SCROLL_X 0018 +SCROLL_Y 001a +SG1000 0000 +SGM 0000 +SMS 0000 +SORD 0000 +SPRITE_DATA 0024 +SPRITE_PAGE 0002 +SPRRAM 4014 +STACK 01ff +START c92b +START.1 c953 +START.2 c9de +START.3 c9fd +START.4 ca0f +START.5 c979 +START.6 c97d +START.7 c990 +START.8 c999 +START.9 c99f +SVI 0000 +TEMP 0002 +TEMP2 0004 +TI99 0000 +UPDATE_SPRITE c107 +VDP 0000 +VDPR 0000 +VDP_STATUS 0010 +WAIT c463 +WAIT.1 c465 +WRTVRM c000 +WRTVRM.1 c01b +_ABS16 c125 +_DIV16 c223 +_DIV16.1 c235 +_DIV16.2 c23d +_DIV16.3 c261 +_DIV16S c1e8 +_DIV16S.1 c20c +_DIV16S.2 c219 +_DIV16S.3 c222 +_MOD16 c26d +_MOD16.1 c27f +_MOD16.2 c287 +_MOD16.3 c2ab +_MOD16S c1b1 +_MOD16S.1 c1d1 +_MOD16S.2 c1de +_MOD16S.3 c1e7 +_MUL16 c178 +_MUL16.1 c192 +_MUL16.2 c1a5 +_NEG16 c12a +_NEG16.1 c136 +_PEEK16 c169 +_PEEK8 c160 +_READ16 c14b +_READ8 c155 +_READ8.1 c15f +_SGN16 c138 +_SGN16.1 c149 +_SGN16.2 c147 diff --git a/cvbasic.c b/cvbasic.c index c699c59..41ca485 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -6944,9 +6944,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "ERROR: More than 4 CHRROM pages for bank-switched cartridge.\n"); } if (bank_rom_size == 256) { - fprintf(output, "\nFORG $34000\n"); + fprintf(output, "\nFORG $34010\n"); } else { - fprintf(output, "\nFORG $74000\n"); + fprintf(output, "\nFORG $74010\n"); } fprintf(output, "\nORG $8000\n"); } diff --git a/cvbasic_nes_epilogue.asm b/cvbasic_nes_epilogue.asm index 63be4b0..7f8ded4 100644 --- a/cvbasic_nes_epilogue.asm +++ b/cvbasic_nes_epilogue.asm @@ -1,5 +1,9 @@ rom_end: + if CVBASIC_BANK_SWITCHING + forg CVBASIC_BANK_ROM_SIZE*1024+16-6 ; Go to final of ROM minus vectors + else times $fffa-$ db $ff + endif dw nmi_handler dw START diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index e04b0e4..fc625fd 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -1623,28 +1623,28 @@ START: IF CVBASIC_BANK_SWITCHING ; Copy CHRROM to CHRRAM - LDA #$1D - STA $C000 + LDA #$00+CVBASIC_BANK_ROM_SIZE/16-3 + STA BANKSEL LDX #$80 JSR copy_chrram - LDA #$3D - STA $C000 + LDA #$20+CVBASIC_BANK_ROM_SIZE/16-3 + STA BANKSEL LDX #$A0 JSR copy_chrram - LDA #$1E - STA $C000 + LDA #$40+CVBASIC_BANK_ROM_SIZE/16-2 + STA BANKSEL LDX #$80 JSR copy_chrram - LDA #$3E - STA $C000 + LDA #$60+CVBASIC_BANK_ROM_SIZE/16-2 + STA BANKSEL LDX #$A0 JSR copy_chrram LDA #$00 ; BANK SELECT 1 - STA $C000 + STA BANKSEL ENDIF ; Clear 2K of pattern memory diff --git a/examples/bank_nes.bas b/examples/bank_nes.bas index cfbba0a..3f2ca58 100644 --- a/examples/bank_nes.bas +++ b/examples/bank_nes.bas @@ -16,14 +16,15 @@ PALETTE 1,$16 PALETTE 2,$27 PALETTE 3,$38 - WAIT SCREEN DISABLE - SCREEN image_pattern,0,0,12,16,12 - WAIT - SCREEN ENABLE + WAIT BANK SELECT 2 ' Select bank 2 to access. + SCREEN image_pattern,0,132,12,16,12 + WAIT + SCREEN ENABLE + GOSUB display_some_text WHILE 1: WEND @@ -184,13 +185,13 @@ tune_1: DATA BYTE 7 display_some_text: PROCEDURE - PRINT AT $0210,"Hi!" + PRINT AT $01d1,"Hi!" - PRINT AT $0250,"This is bank-" + PRINT AT $0211,"This is bank-" - PRINT AT $0270,"switching demo." + PRINT AT $0231,"switching demo." - PRINT AT $02B0,":)" + PRINT AT $0271,":)" END From 0500d8ccb58bb0606debe26eb506c2f03dd2539e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 14:44:05 -0600 Subject: [PATCH 080/155] NES adjustments in bank-switching demo --- bank.lst | 4620 ----------------------------------------- examples/bank_nes.bas | 2 +- 2 files changed, 1 insertion(+), 4621 deletions(-) delete mode 100644 bank.lst diff --git a/bank.lst b/bank.lst deleted file mode 100644 index 3686b5b..0000000 --- a/bank.lst +++ /dev/null @@ -1,4620 +0,0 @@ - 00001 ; CVBasic compiler v0.9.0 Aug/25/2025 - 00002 ; Command: ./cvbasic --nes examples/bank_nes.bas bank.asm - 00003 ; Created: Tue Aug 26 14:39:32 2025 - 00004 - 00005 COLECO: EQU 0 - 00006 SG1000: EQU 0 - 00007 MSX: EQU 0 - 00008 SGM: EQU 0 - 00009 SVI: EQU 0 - 00010 SORD: EQU 0 - 00011 MEMOTECH: EQU 0 - 00012 EINSTEIN: EQU 0 - 00013 CPM: EQU 0 - 00014 PENCIL: EQU 0 - 00015 PV2000: EQU 0 - 00016 TI99: EQU 0 - 00017 NABU: EQU 0 - 00018 SMS: EQU 0 - 00019 NES_PRG_BANKS: EQU 16 ; Each one 16K. - 00020 NES_CHR_BANKS: EQU 1 ; Each one 4K. - 00021 NES_NAMETABLE: EQU 0 - 00022 - 00023 CVBASIC_MUSIC_PLAYER: EQU 1 - 00024 CVBASIC_COMPRESSION: EQU 0 - 00025 CVBASIC_BANK_SWITCHING: EQU 1 - 00026 CVBASIC_BANK_ROM_SIZE: EQU 256 - 00027 - 00028 BASE_RAM: EQU $0050 ; Base of RAM - 00029 RAM_SIZE: EQU $0800 ; Base of RAM - 00030 STACK: EQU $01FF ; Base stack pointer - 00031 VDP: EQU $00 ; VDP port (write) - 00032 VDPR: EQU $00 ; VDP port (read) - 00033 PSG: EQU $00 ; PSG port (write) - 00034 - 00035 FORG $00000 - 00036 ; - 00037 ; CVBasic prologue (BASIC compiler, 6502 target) - 00038 ; - 00039 ; by Oscar Toledo G. - 00040 ; https://nanochess.org/ - 00041 ; - 00042 ; Creation date: May/13/2025. - 00043 ; Revision date: Jul/20/2025. Added code to load sprites and read controllers. - 00044 ; Revision date: Aug/23/2025. Support for writing VRAM and PRINT. - 00045 ; Revision date: Aug/24/2025. Support for scrolling, SCREEN, and DISABLE/ENABLE. - 00046 ; Added music player. - 00047 ; Revision date: Aug/25/2025. Added support for 256K and 512K ROM. - 00048 ; Revision date: Aug/26/2025. Added support for CHRRAM selection. - 00049 ; - 00050 - 00051 CPU 6502 - 00052 - 00053 ; - 00054 ; Platforms supported: - 00055 ; o NES/Famicom - 00056 ; - 00057 - 00058 ; - 00059 ; CVBasic variables in zero page. - 00060 ; - 00061 - 00062 PPU_SOURCE: EQU $00 ; Used in NMI for source address for PPU copy - 00063 ; This is a block of 8 bytes that should stay together. - 00064 TEMP: EQU $02 - 00065 TEMP2: EQU $04 - 00066 RESULT: EQU $06 - 00067 POINTER: EQU $08 - 00068 - 00069 READ_POINTER: EQU $0A - 00070 CURSOR: EQU $0C - 00071 MODE: EQU $0E - 00072 NTSC: EQU $0F - 00073 - 00074 VDP_STATUS: EQU $10 - 00075 FLICKER: EQU $11 - 00076 FRAME: EQU $12 - 00077 PPU_POINTER: EQU $14 - 00078 PPU_TEMP: EQU $15 ; Used in NMI to save X - 00079 PPU_CTRL: EQU $16 - 00080 PPU_MASK: EQU $17 - 00081 SCROLL_X: EQU $18 - 00082 SCROLL_Y: EQU $1A - 00083 CHRRAM_BANK: EQU $1C - 00084 CONT_BITS: EQU $1D - 00085 LFSR: EQU $1E - 00086 - 00087 JOY1_DATA: EQU $20 - 00088 JOY2_DATA: EQU $21 - 00089 KEY1_DATA: EQU $22 - 00090 KEY2_DATA: EQU $23 - 00091 SPRITE_DATA: EQU $24 - 00092 - 00093 IF CVBASIC_MUSIC_PLAYER - 00094 MUSIC_PLAYING: EQU $4F - 00095 MUSIC_BANK: EQU $30 - 00096 MUSIC_TIMING: EQU $31 - 00097 MUSIC_START: EQU $32 - 00098 MUSIC_POINTER: EQU $34 - 00099 MUSIC_NOTE_COUNTER: EQU $36 - 00100 MUSIC_INSTRUMENT_1: EQU $37 - 00101 MUSIC_NOTE_1: EQU $38 - 00102 MUSIC_COUNTER_1: EQU $39 - 00103 MUSIC_INSTRUMENT_2: EQU $3A - 00104 MUSIC_NOTE_2: EQU $3B - 00105 MUSIC_COUNTER_2: EQU $3C - 00106 MUSIC_INSTRUMENT_3: EQU $3D - 00107 MUSIC_NOTE_3: EQU $3E - 00108 MUSIC_COUNTER_3: EQU $3F - 00109 MUSIC_DRUM: EQU $40 - 00110 MUSIC_COUNTER_4: EQU $41 - 00111 AUDIO_FREQ1: EQU $42 - 00112 AUDIO_FREQ2: EQU $44 - 00113 AUDIO_FREQ3: EQU $46 - 00114 AUDIO_VOL1: EQU $48 - 00115 AUDIO_VOL2: EQU $49 - 00116 AUDIO_VOL3: EQU $4A - 00117 AUDIO_VOL4HW: EQU $4B - 00118 AUDIO_NOISE: EQU $4C - 00119 MUSIC_TICK: EQU $4D - 00120 MUSIC_MODE: EQU $4E - 00121 ENDIF - 00122 - 00123 SPRITE_PAGE: EQU $02 - 00124 PPUBUF: EQU $0100 - 00125 BANKSEL: EQU $C000 - 00126 - 00127 FORG $0000 - 00128 ; The ORG address doesn't matter here - 00129 ; iNES cartridge header -0000 4E45531A 00130 DB "NES",$1A -0004 10 00131 DB NES_PRG_BANKS -0005 00132 IF CVBASIC_BANK_SWITCHING -0005 00 00133 DB 0 ; It has CHRRAM -0006 E2 00134 DB $E2|NES_NAMETABLE ; Cartridge type LSB -0007 10 00135 DB $10 ; Cartridge type MSB -0008 00 00136 DB $00 ; Number of 8K RAM pages. -0009 00137 ELSE -0009 00138 DB NES_CHR_BANKS -0009 00139 DB $00|NES_NAMETABLE ; Cartridge type LSB -0009 00140 DB $00 ; Cartridge type MSB -0009 00141 DB $00 ; Number of 8K RAM pages. -0009 00142 ENDIF -0009 00000000000000 00143 DB $00,$00,$00,$00,$00,$00,$00 ; Reserved -0010 00144 -0010 00145 IF CVBASIC_BANK_SWITCHING -0010 00146 IF CVBASIC_BANK_ROM_SIZE-512 - 00147 FORG $3C010 -C000 00148 ORG $C000 -C000 00149 ELSE -C000 00150 FORG $7C010 -C000 00151 ORG $C000 -C000 00152 ENDIF -C000 00153 ELSE -C000 00154 FORG $0010 -C000 00155 ORG $8000 -C000 00156 ENDIF -C000 00157 -C000 00158 PPUCTRL: EQU $2000 -C000 00159 PPUMASK: EQU $2001 -C000 00160 PPUSTATUS: EQU $2002 -C000 00161 OAMADDR: EQU $2003 -C000 00162 PPUSCROLL: EQU $2005 -C000 00163 PPUADDR: EQU $2006 -C000 00164 PPUDATA: EQU $2007 -C000 00165 SPRRAM: EQU $4014 -C000 00166 CONT1: EQU $4016 -C000 00167 CONT2: EQU $4017 -C000 00168 -C000 00169 ; -C000 00170 ; NES architecture prevents direct access to VRAM except -C000 00171 ; during the VBLANK. -C000 00172 ; -C000 00173 WRTVRM: -C000 48 00174 PHA -C001 8A 00175 TXA -C002 A614 00176 LDX PPU_POINTER -C004 9D0201 00177 STA PPUBUF+2,X -C007 68 00178 PLA -C008 9D0001 00179 STA PPUBUF,X -C00B 98 00180 TYA -C00C 0940 00181 ORA #$40 -C00E 9D0101 00182 STA PPUBUF+1,X -C011 E8 00183 INX -C012 E8 00184 INX -C013 E8 00185 INX -C014 8614 00186 STX PPU_POINTER -C016 E040 00187 CPX #$40 -C018 B001 00188 BCS .1 -C01A 60 00189 RTS -C01B 00190 .1: -C01B 4C63C4 00191 JMP WAIT -C01E 00192 -C01E 00193 LDIRVM4: -C01E 202BC0 00194 JSR LDIRVM2 -C021 202BC0 00195 JSR LDIRVM2 -C024 202BC0 00196 JSR LDIRVM2 -C027 202BC0 00197 JSR LDIRVM2 -C02A 60 00198 RTS -C02B 00199 -C02B 00200 LDIRVM2: -C02B 203AC0 00201 JSR LDIRVM -C02E A508 00202 LDA POINTER -C030 18 00203 CLC -C031 6504 00204 ADC TEMP2 -C033 8508 00205 STA POINTER -C035 9002 00206 BCC .1 -C037 E609 00207 INC POINTER+1 -C039 00208 .1: -C039 60 00209 RTS -C03A 00210 -C03A 00211 LDIRVM: -C03A A614 00212 LDX PPU_POINTER -C03C A508 00213 LDA POINTER -C03E 9D0001 00214 STA PPUBUF,X -C041 A509 00215 LDA POINTER+1 -C043 9D0101 00216 STA PPUBUF+1,X -C046 A900 00217 LDA #0 -C048 38 00218 SEC -C049 E504 00219 SBC TEMP2 -C04B 9D0201 00220 STA PPUBUF+2,X -C04E A502 00221 LDA TEMP -C050 38 00222 SEC -C051 FD0201 00223 SBC PPUBUF+2,X -C054 9D0301 00224 STA PPUBUF+3,X -C057 A503 00225 LDA TEMP+1 -C059 E900 00226 SBC #0 -C05B 9D0401 00227 STA PPUBUF+4,X -C05E 8A 00228 TXA -C05F 18 00229 CLC -C060 6905 00230 ADC #5 -C062 8514 00231 STA PPU_POINTER -C064 C940 00232 CMP #$40 -C066 B001 00233 BCS .1 -C068 60 00234 RTS -C069 00235 .1: -C069 4C63C4 00236 JMP WAIT -C06C 00237 -C06C 00238 ENASCR: -C06C A517 00239 LDA PPU_MASK -C06E 0918 00240 ORA #$18 -C070 8517 00241 STA PPU_MASK -C072 60 00242 RTS -C073 00243 -C073 00244 DISSCR: -C073 A517 00245 LDA PPU_MASK -C075 29E7 00246 AND #$E7 -C077 8517 00247 STA PPU_MASK -C079 60 00248 RTS -C07A 00249 -C07A 00250 CPYBLK: -C07A 00251 .1: -C07A A504 00252 LDA TEMP2 -C07C 48 00253 PHA -C07D A505 00254 LDA TEMP2+1 -C07F 48 00255 PHA -C080 8A 00256 TXA -C081 48 00257 PHA -C082 98 00258 TYA -C083 48 00259 PHA -C084 A502 00260 LDA TEMP -C086 48 00261 PHA -C087 A503 00262 LDA TEMP+1 -C089 48 00263 PHA -C08A A900 00264 LDA #0 -C08C 8505 00265 STA TEMP2+1 -C08E 203AC0 00266 JSR LDIRVM -C091 68 00267 PLA -C092 8503 00268 STA TEMP+1 -C094 68 00269 PLA -C095 8502 00270 STA TEMP -C097 68 00271 PLA -C098 8505 00272 STA TEMP2+1 -C09A 68 00273 PLA -C09B 8504 00274 STA TEMP2 -C09D A502 00275 LDA TEMP -C09F 18 00276 CLC -C0A0 6504 00277 ADC TEMP2 -C0A2 8502 00278 STA TEMP -C0A4 A503 00279 LDA TEMP+1 -C0A6 6505 00280 ADC TEMP2+1 -C0A8 8503 00281 STA TEMP+1 -C0AA A604 00282 LDX TEMP2 -C0AC A405 00283 LDY TEMP2+1 -C0AE 68 00284 PLA -C0AF 8505 00285 STA TEMP2+1 -C0B1 68 00286 PLA -C0B2 8504 00287 STA TEMP2 -C0B4 A508 00288 LDA POINTER -C0B6 18 00289 CLC -C0B7 6920 00290 ADC #$20 ; !!! Variation for scrolling -C0B9 8508 00291 STA POINTER -C0BB A509 00292 LDA POINTER+1 -C0BD 6900 00293 ADC #$00 -C0BF 8509 00294 STA POINTER+1 -C0C1 C605 00295 DEC TEMP2+1 -C0C3 D0B5 00296 BNE .1 -C0C5 60 00297 RTS -C0C6 00298 -C0C6 00299 CLS: -C0C6 A980 00300 LDA #$80 -C0C8 00301 .1: -C0C8 48 00302 PHA -C0C9 A614 00303 LDX PPU_POINTER -C0CB C98F 00304 CMP #$8F -C0CD D004 00305 BNE .2 -C0CF A900 00306 LDA #$00 -C0D1 F002 00307 BEQ .3 -C0D3 00308 -C0D3 A920 00309 .2: LDA #$20 -C0D5 9D0301 00310 .3: STA PPUBUF+3,X -C0D8 A940 00311 LDA #$40 -C0DA 9D0201 00312 STA PPUBUF+2,X -C0DD A900 00313 LDA #$00 -C0DF 9D0001 00314 STA PPUBUF,X -C0E2 68 00315 PLA -C0E3 9D0101 00316 STA PPUBUF+1,X -C0E6 48 00317 PHA -C0E7 18 00318 CLC -C0E8 7E0101 00319 ROR PPUBUF+1,X -C0EB 7E0001 00320 ROR PPUBUF,X -C0EE 38 00321 SEC -C0EF 7E0101 00322 ROR PPUBUF+1,X -C0F2 7E0001 00323 ROR PPUBUF,X -C0F5 E8 00324 INX -C0F6 E8 00325 INX -C0F7 E8 00326 INX -C0F8 E8 00327 INX -C0F9 8614 00328 STX PPU_POINTER -C0FB 2063C4 00329 JSR WAIT -C0FE 68 00330 PLA -C0FF 18 00331 CLC -C100 6901 00332 ADC #1 -C102 C990 00333 CMP #$90 -C104 D0C2 00334 BNE .1 -C106 60 00335 RTS -C107 00336 -C107 00337 UPDATE_SPRITE: -C107 0A 00338 ASL A -C108 0A 00339 ASL A -C109 8508 00340 STA POINTER -C10B A902 00341 LDA #SPRITE_PAGE -C10D 8509 00342 STA POINTER+1 -C10F A000 00343 LDY #0 -C111 A524 00344 LDA SPRITE_DATA+0 -C113 9108 00345 STA (POINTER),Y -C115 C8 00346 INY -C116 A525 00347 LDA SPRITE_DATA+1 -C118 9108 00348 STA (POINTER),Y -C11A C8 00349 INY -C11B A526 00350 LDA SPRITE_DATA+2 -C11D 9108 00351 STA (POINTER),Y -C11F C8 00352 INY -C120 A527 00353 LDA SPRITE_DATA+3 -C122 9108 00354 STA (POINTER),Y -C124 60 00355 RTS -C125 00356 -C125 00357 _ABS16: -C125 48 00358 PHA -C126 98 00359 TYA -C127 100D 00360 BPL _NEG16.1 -C129 68 00361 PLA -C12A 00362 _NEG16: -C12A 49FF 00363 EOR #$FF -C12C 18 00364 CLC -C12D 6901 00365 ADC #1 -C12F 48 00366 PHA -C130 98 00367 TYA -C131 49FF 00368 EOR #$FF -C133 6900 00369 ADC #0 -C135 A8 00370 TAY -C136 00371 .1: -C136 68 00372 PLA -C137 60 00373 RTS -C138 00374 -C138 00375 _SGN16: -C138 8402 00376 STY TEMP -C13A 0502 00377 ORA TEMP -C13C F00B 00378 BEQ .1 -C13E 98 00379 TYA -C13F 3006 00380 BMI .2 -C141 A900 00381 LDA #0 -C143 A8 00382 TAY -C144 A901 00383 LDA #1 -C146 60 00384 RTS -C147 00385 -C147 A9FF 00386 .2: LDA #$FF -C149 A8 00387 .1: TAY -C14A 60 00388 RTS -C14B 00389 -C14B 00390 _READ16: -C14B 2055C1 00391 JSR _READ8 -C14E 48 00392 PHA -C14F 2055C1 00393 JSR _READ8 -C152 A8 00394 TAY -C153 68 00395 PLA -C154 60 00396 RTS -C155 00397 -C155 00398 _READ8: -C155 A000 00399 LDY #0 -C157 B10A 00400 LDA (READ_POINTER),Y -C159 E60A 00401 INC READ_POINTER -C15B D002 00402 BNE .1 -C15D E60B 00403 INC READ_POINTER+1 -C15F 00404 .1: -C15F 60 00405 RTS -C160 00406 -C160 00407 _PEEK8: -C160 8508 00408 STA POINTER -C162 8409 00409 STY POINTER+1 -C164 A000 00410 LDY #0 -C166 B108 00411 LDA (POINTER),Y -C168 60 00412 RTS -C169 00413 -C169 00414 _PEEK16: -C169 8508 00415 STA POINTER -C16B 8409 00416 STY POINTER+1 -C16D A000 00417 LDY #0 -C16F B108 00418 LDA (POINTER),Y -C171 48 00419 PHA -C172 C8 00420 INY -C173 B108 00421 LDA (POINTER),Y -C175 A8 00422 TAY -C176 68 00423 PLA -C177 60 00424 RTS -C178 00425 -C178 00426 ; temp2 contains left side (dividend) -C178 00427 ; temp contains right side (divisor) -C178 00428 -C178 00429 ; 16-bit multiplication. -C178 00430 _MUL16: -C178 68 00431 PLA -C179 8506 00432 STA RESULT -C17B 68 00433 PLA -C17C 8507 00434 STA RESULT+1 -C17E 68 00435 PLA -C17F 8505 00436 STA TEMP2+1 -C181 68 00437 PLA -C182 8504 00438 STA TEMP2 -C184 A507 00439 LDA RESULT+1 -C186 48 00440 PHA -C187 A506 00441 LDA RESULT -C189 48 00442 PHA -C18A A900 00443 LDA #0 -C18C 8506 00444 STA RESULT -C18E 8507 00445 STA RESULT+1 -C190 A20F 00446 LDX #15 -C192 00447 .1: -C192 4605 00448 LSR TEMP2+1 -C194 6604 00449 ROR TEMP2 -C196 900D 00450 BCC .2 -C198 A506 00451 LDA RESULT -C19A 18 00452 CLC -C19B 6502 00453 ADC TEMP -C19D 8506 00454 STA RESULT -C19F A507 00455 LDA RESULT+1 -C1A1 6503 00456 ADC TEMP+1 -C1A3 8507 00457 STA RESULT+1 -C1A5 0602 00458 .2: ASL TEMP -C1A7 2603 00459 ROL TEMP+1 -C1A9 CA 00460 DEX -C1AA 10E6 00461 BPL .1 -C1AC A506 00462 LDA RESULT -C1AE A407 00463 LDY RESULT+1 -C1B0 60 00464 RTS -C1B1 00465 -C1B1 00466 ; 16-bit signed modulo. -C1B1 00467 _MOD16S: -C1B1 68 00468 PLA -C1B2 8506 00469 STA RESULT -C1B4 68 00470 PLA -C1B5 8507 00471 STA RESULT+1 -C1B7 68 00472 PLA -C1B8 8505 00473 STA TEMP2+1 -C1BA 68 00474 PLA -C1BB 8504 00475 STA TEMP2 -C1BD A507 00476 LDA RESULT+1 -C1BF 48 00477 PHA -C1C0 A506 00478 LDA RESULT -C1C2 48 00479 PHA -C1C3 A405 00480 LDY TEMP2+1 -C1C5 08 00481 PHP -C1C6 1009 00482 BPL .1 -C1C8 A504 00483 LDA TEMP2 -C1CA 202AC1 00484 JSR _NEG16 -C1CD 8504 00485 STA TEMP2 -C1CF 8405 00486 STY TEMP2+1 -C1D1 00487 .1: -C1D1 A403 00488 LDY TEMP+1 -C1D3 1009 00489 BPL .2 -C1D5 A502 00490 LDA TEMP -C1D7 202AC1 00491 JSR _NEG16 -C1DA 8502 00492 STA TEMP -C1DC 8403 00493 STY TEMP+1 -C1DE 00494 .2: -C1DE 207FC2 00495 JSR _MOD16.1 -C1E1 28 00496 PLP -C1E2 1003 00497 BPL .3 -C1E4 4C2AC1 00498 JMP _NEG16 -C1E7 00499 .3: -C1E7 60 00500 RTS -C1E8 00501 -C1E8 00502 ; 16-bit signed division. -C1E8 00503 _DIV16S: -C1E8 68 00504 PLA -C1E9 8506 00505 STA RESULT -C1EB 68 00506 PLA -C1EC 8507 00507 STA RESULT+1 -C1EE 68 00508 PLA -C1EF 8505 00509 STA TEMP2+1 -C1F1 68 00510 PLA -C1F2 8504 00511 STA TEMP2 -C1F4 A507 00512 LDA RESULT+1 -C1F6 48 00513 PHA -C1F7 A506 00514 LDA RESULT -C1F9 48 00515 PHA -C1FA A503 00516 LDA TEMP+1 -C1FC 4505 00517 EOR TEMP2+1 -C1FE 08 00518 PHP -C1FF A405 00519 LDY TEMP2+1 -C201 1009 00520 BPL .1 -C203 A504 00521 LDA TEMP2 -C205 202AC1 00522 JSR _NEG16 -C208 8504 00523 STA TEMP2 -C20A 8405 00524 STY TEMP2+1 -C20C 00525 .1: -C20C A403 00526 LDY TEMP+1 -C20E 1009 00527 BPL .2 -C210 A502 00528 LDA TEMP -C212 202AC1 00529 JSR _NEG16 -C215 8502 00530 STA TEMP -C217 8403 00531 STY TEMP+1 -C219 00532 .2: -C219 2035C2 00533 JSR _DIV16.1 -C21C 28 00534 PLP -C21D 1003 00535 BPL .3 -C21F 4C2AC1 00536 JMP _NEG16 -C222 00537 .3: -C222 60 00538 RTS -C223 00539 -C223 00540 _DIV16: -C223 68 00541 PLA -C224 8506 00542 STA RESULT -C226 68 00543 PLA -C227 8507 00544 STA RESULT+1 -C229 68 00545 PLA -C22A 8505 00546 STA TEMP2+1 -C22C 68 00547 PLA -C22D 8504 00548 STA TEMP2 -C22F A507 00549 LDA RESULT+1 -C231 48 00550 PHA -C232 A506 00551 LDA RESULT -C234 48 00552 PHA -C235 00553 .1: -C235 A900 00554 LDA #0 -C237 8506 00555 STA RESULT -C239 8507 00556 STA RESULT+1 -C23B A20F 00557 LDX #15 -C23D 00558 .2: -C23D 2604 00559 ROL TEMP2 -C23F 2605 00560 ROL TEMP2+1 -C241 2606 00561 ROL RESULT -C243 2607 00562 ROL RESULT+1 -C245 A506 00563 LDA RESULT -C247 38 00564 SEC -C248 E502 00565 SBC TEMP -C24A 8506 00566 STA RESULT -C24C A507 00567 LDA RESULT+1 -C24E E503 00568 SBC TEMP+1 -C250 8507 00569 STA RESULT+1 -C252 B00D 00570 BCS .3 -C254 A506 00571 LDA RESULT -C256 6502 00572 ADC TEMP -C258 8506 00573 STA RESULT -C25A A507 00574 LDA RESULT+1 -C25C 6503 00575 ADC TEMP+1 -C25E 8507 00576 STA RESULT+1 -C260 18 00577 CLC -C261 00578 .3: -C261 CA 00579 DEX -C262 10D9 00580 BPL .2 -C264 2604 00581 ROL TEMP2 -C266 2605 00582 ROL TEMP2+1 -C268 A504 00583 LDA TEMP2 -C26A A405 00584 LDY TEMP2+1 -C26C 60 00585 RTS -C26D 00586 -C26D 00587 _MOD16: -C26D 68 00588 PLA -C26E 8506 00589 STA RESULT -C270 68 00590 PLA -C271 8507 00591 STA RESULT+1 -C273 68 00592 PLA -C274 8505 00593 STA TEMP2+1 -C276 68 00594 PLA -C277 8504 00595 STA TEMP2 -C279 A507 00596 LDA RESULT+1 -C27B 48 00597 PHA -C27C A506 00598 LDA RESULT -C27E 48 00599 PHA -C27F 00600 .1: -C27F A900 00601 LDA #0 -C281 8506 00602 STA RESULT -C283 8507 00603 STA RESULT+1 -C285 A20F 00604 LDX #15 -C287 00605 .2: -C287 2604 00606 ROL TEMP2 -C289 2605 00607 ROL TEMP2+1 -C28B 2606 00608 ROL RESULT -C28D 2607 00609 ROL RESULT+1 -C28F A506 00610 LDA RESULT -C291 38 00611 SEC -C292 E502 00612 SBC TEMP -C294 8506 00613 STA RESULT -C296 A507 00614 LDA RESULT+1 -C298 E503 00615 SBC TEMP+1 -C29A 8507 00616 STA RESULT+1 -C29C B00D 00617 BCS .3 -C29E A506 00618 LDA RESULT -C2A0 6502 00619 ADC TEMP -C2A2 8506 00620 STA RESULT -C2A4 A507 00621 LDA RESULT+1 -C2A6 6503 00622 ADC TEMP+1 -C2A8 8507 00623 STA RESULT+1 -C2AA 18 00624 CLC -C2AB 00625 .3: -C2AB CA 00626 DEX -C2AC 10D9 00627 BPL .2 -C2AE A506 00628 LDA RESULT -C2B0 A407 00629 LDY RESULT+1 -C2B2 60 00630 RTS -C2B3 00631 -C2B3 00632 ; Random number generator. -C2B3 00633 ; From my game Mecha Eight. -C2B3 00634 RANDOM: -C2B3 A51E 00635 LDA LFSR -C2B5 051F 00636 ORA LFSR+1 -C2B7 D008 00637 BNE .0 -C2B9 A911 00638 LDA #$11 -C2BB 851E 00639 STA LFSR -C2BD A978 00640 LDA #$78 -C2BF 851F 00641 STA LFSR+1 -C2C1 A51F 00642 .0: LDA LFSR+1 -C2C3 6A 00643 ROR A -C2C4 6A 00644 ROR A -C2C5 6A 00645 ROR A -C2C6 451F 00646 EOR LFSR+1 -C2C8 8502 00647 STA TEMP -C2CA A51F 00648 LDA LFSR+1 -C2CC 6A 00649 ROR A -C2CD 6A 00650 ROR A -C2CE 4502 00651 EOR TEMP -C2D0 8502 00652 STA TEMP -C2D2 A51E 00653 LDA LFSR -C2D4 0A 00654 ASL A -C2D5 0A 00655 ASL A -C2D6 4502 00656 EOR TEMP -C2D8 2A 00657 ROL A -C2D9 661F 00658 ROR LFSR+1 -C2DB 661E 00659 ROR LFSR -C2DD A51E 00660 LDA LFSR -C2DF A41F 00661 LDY LFSR+1 -C2E1 60 00662 RTS -C2E2 00663 -C2E2 00664 IRQ_HANDLER: -C2E2 40 00665 RTI -C2E3 00666 -C2E3 00667 NMI_HANDLER: -C2E3 48 00668 PHA -C2E4 8A 00669 TXA -C2E5 48 00670 PHA -C2E6 98 00671 TYA -C2E7 48 00672 PHA -C2E8 00673 -C2E8 00674 IF CVBASIC_BANK_SWITCHING -C2E8 ADFFBF 00675 LDA $BFFF -C2EB 48 00676 PHA -C2EC 00677 ENDIF -C2EC 00678 ; Load sprites -C2EC A50E 00679 LDA MODE -C2EE 2904 00680 AND #4 ; Flicker enabled? -C2F0 D00A 00681 BNE .5 ; No, jump. -C2F2 A511 00682 LDA FLICKER -C2F4 18 00683 CLC -C2F5 6920 00684 ADC #32 -C2F7 8511 00685 STA FLICKER -C2F9 4CFEC2 00686 JMP .6 -C2FC 00687 .5: -C2FC A900 00688 LDA #$00 -C2FE 00689 .6: -C2FE 8D0320 00690 STA OAMADDR -C301 A902 00691 LDA #SPRITE_PAGE -C303 8D1440 00692 STA SPRRAM ; Use DMA for sprite loading -C306 00693 -C306 00694 ; Screen changes -C306 A514 00695 LDA PPU_POINTER ; Any change? -C308 F058 00696 BEQ .1 ; No, jump. -C30A A200 00697 LDX #$00 -C30C BC0001 00698 .0: LDY PPUBUF,X -C30F E8 00699 INX -C310 BD0001 00700 LDA PPUBUF,X -C313 E8 00701 INX -C314 8D0620 00702 STA PPUADDR ; High-byte of VRAM address. -C317 2A 00703 ROL A -C318 8C0620 00704 STY PPUADDR ; Low-byte of VRAM address. -C31B B02F 00705 BCS .2 ; Fill routine. -C31D 301F 00706 BMI .7 ; Single byte routine. -C31F 00707 ; Copy routine. -C31F BD0101 00708 LDA PPUBUF+1,X -C322 8500 00709 STA PPU_SOURCE -C324 BD0201 00710 LDA PPUBUF+2,X -C327 8501 00711 STA PPU_SOURCE+1 -C329 BC0001 00712 LDY PPUBUF,X ; Negative counter. -C32C E8 00713 INX -C32D E8 00714 INX -C32E E8 00715 INX -C32F 00716 .4: -C32F B100 00717 LDA (PPU_SOURCE),Y -C331 8D0720 00718 STA PPUDATA -C334 C8 00719 INY -C335 D0F8 00720 BNE .4 -C337 E414 00721 CPX PPU_POINTER -C339 D0D1 00722 BNE .0 -C33B 4C5EC3 00723 JMP .11 -C33E 00724 -C33E 00725 ; Single byte -C33E 00726 .7: -C33E BD0001 00727 LDA PPUBUF,X -C341 E8 00728 INX -C342 8D0720 00729 STA PPUDATA -C345 E414 00730 CPX PPU_POINTER -C347 D0C3 00731 BNE .0 -C349 4C5EC3 00732 JMP .11 -C34C 00733 -C34C 00734 ; Filling data -C34C 00735 .2: -C34C BC0001 00736 LDY PPUBUF,X -C34F E8 00737 INX -C350 BD0001 00738 LDA PPUBUF,X -C353 E8 00739 INX -C354 00740 .3: -C354 8D0720 00741 STA PPUDATA -C357 88 00742 DEY -C358 D0FA 00743 BNE .3 -C35A E414 00744 CPX PPU_POINTER -C35C D0AE 00745 BNE .0 -C35E 00746 -C35E 00747 .11: -C35E A900 00748 LDA #0 -C360 8514 00749 STA PPU_POINTER -C362 00750 .1: -C362 00751 -C362 00752 ; Final settings for PPU -C362 A900 00753 LDA #0 -C364 8D0620 00754 STA PPUADDR -C367 8D0620 00755 STA PPUADDR -C36A A518 00756 LDA SCROLL_X -C36C 8D0520 00757 STA PPUSCROLL -C36F A51A 00758 LDA SCROLL_Y -C371 8D0520 00759 STA PPUSCROLL -C374 A516 00760 LDA PPU_CTRL -C376 4A 00761 LSR A -C377 4A 00762 LSR A -C378 8515 00763 STA PPU_TEMP -C37A A51B 00764 LDA SCROLL_Y+1 -C37C 6A 00765 ROR A -C37D 2615 00766 ROL PPU_TEMP -C37F A519 00767 LDA SCROLL_X+1 -C381 6A 00768 ROR A -C382 2615 00769 ROL PPU_TEMP -C384 A515 00770 LDA PPU_TEMP -C386 8D0020 00771 STA PPUCTRL -C389 A517 00772 LDA PPU_MASK -C38B 8D0120 00773 STA PPUMASK -C38E 00774 -C38E AD0220 00775 LDA PPUSTATUS ; VDP interruption clear. -C391 8510 00776 STA VDP_STATUS -C393 00777 -C393 00778 ; Read controllers -C393 A901 00779 LDA #$01 -C395 8D1640 00780 STA CONT1 -C398 851D 00781 STA CONT_BITS -C39A 4A 00782 LSR A -C39B 8D1640 00783 STA CONT1 -C39E 00784 -C39E AD1640 00785 LDA CONT1 -C3A1 4A 00786 LSR A -C3A2 261D 00787 ROL CONT_BITS -C3A4 90F8 00788 BCC $-6 -C3A6 00789 -C3A6 202EC4 00790 JSR CONVERT_JOYSTICK -C3A9 8520 00791 STA JOY1_DATA -C3AB 8622 00792 STX KEY1_DATA -C3AD 00793 -C3AD A901 00794 LDA #$01 -C3AF 8D1640 00795 STA CONT1 -C3B2 851D 00796 STA CONT_BITS -C3B4 4A 00797 LSR A -C3B5 8D1640 00798 STA CONT1 -C3B8 00799 -C3B8 AD1740 00800 LDA CONT2 -C3BB 4A 00801 LSR A -C3BC 261D 00802 ROL CONT_BITS -C3BE 90F8 00803 BCC $-6 -C3C0 00804 -C3C0 202EC4 00805 JSR CONVERT_JOYSTICK -C3C3 8521 00806 STA JOY2_DATA -C3C5 8623 00807 STX KEY2_DATA -C3C7 00808 -C3C7 00809 IF CVBASIC_MUSIC_PLAYER -C3C7 A54E 00810 LDA MUSIC_MODE -C3C9 F003 00811 BEQ .10 -C3CB 205DC8 00812 JSR MUSIC_HARDWARE -C3CE 00813 .10: -C3CE 00814 ENDIF -C3CE E612 00815 INC FRAME -C3D0 D002 00816 BNE .8 -C3D2 E613 00817 INC FRAME+1 -C3D4 00818 .8: -C3D4 E61E 00819 INC LFSR ; Make LFSR more random -C3D6 E61E 00820 INC LFSR -C3D8 E61E 00821 INC LFSR -C3DA 00822 IF CVBASIC_MUSIC_PLAYER -C3DA A50F 00823 LDA NTSC -C3DC F00D 00824 BEQ .12 -C3DE A64D 00825 LDX MUSIC_TICK -C3E0 E8 00826 INX -C3E1 E006 00827 CPX #6 -C3E3 D002 00828 BNE .14 -C3E5 A200 00829 LDX #0 -C3E7 864D 00830 .14: STX MUSIC_TICK -C3E9 F007 00831 BEQ .9 -C3EB 00832 .12: -C3EB A54E 00833 LDA MUSIC_MODE -C3ED F003 00834 BEQ .9 -C3EF 20CBC5 00835 JSR MUSIC_GENERATE -C3F2 00836 .9: -C3F2 00837 ENDIF -C3F2 00838 ; This is like saving extra registers, because these -C3F2 00839 ; are used by the compiled code, and we don't want -C3F2 00840 ; any reentrancy. -C3F2 A502 00841 LDA TEMP+0 -C3F4 48 00842 PHA -C3F5 A503 00843 LDA TEMP+1 -C3F7 48 00844 PHA -C3F8 A504 00845 LDA TEMP+2 -C3FA 48 00846 PHA -C3FB A505 00847 LDA TEMP+3 -C3FD 48 00848 PHA -C3FE A506 00849 LDA TEMP+4 -C400 48 00850 PHA -C401 A507 00851 LDA TEMP+5 -C403 48 00852 PHA -C404 A508 00853 LDA TEMP+6 -C406 48 00854 PHA -C407 A509 00855 LDA TEMP+7 -C409 48 00856 PHA -C40A 00857 -C40A 68 00858 PLA -C40B 8509 00859 STA TEMP+7 -C40D 68 00860 PLA -C40E 8508 00861 STA TEMP+6 -C410 68 00862 PLA -C411 8507 00863 STA TEMP+5 -C413 68 00864 PLA -C414 8506 00865 STA TEMP+4 -C416 68 00866 PLA -C417 8505 00867 STA TEMP+3 -C419 68 00868 PLA -C41A 8504 00869 STA TEMP+2 -C41C 68 00870 PLA -C41D 8503 00871 STA TEMP+1 -C41F 68 00872 PLA -C420 8502 00873 STA TEMP+0 -C422 00874 -C422 00875 IF CVBASIC_BANK_SWITCHING -C422 68 00876 PLA -C423 051C 00877 ORA CHRRAM_BANK -C425 8D00C0 00878 STA BANKSEL -C428 00879 ENDIF -C428 68 00880 PLA -C429 A8 00881 TAY -C42A 68 00882 PLA -C42B AA 00883 TAX -C42C 68 00884 PLA -C42D 40 00885 RTI -C42E 00886 -C42E 00887 CONVERT_JOYSTICK: -C42E A900 00888 LDA #0 -C430 A20F 00889 LDX #15 -C432 661D 00890 ROR CONT_BITS -C434 9002 00891 BCC $+4 -C436 0902 00892 ORA #2 -C438 661D 00893 ROR CONT_BITS -C43A 9002 00894 BCC $+4 -C43C 0908 00895 ORA #8 -C43E 661D 00896 ROR CONT_BITS -C440 9002 00897 BCC $+4 -C442 0904 00898 ORA #4 -C444 661D 00899 ROR CONT_BITS -C446 9002 00900 BCC $+4 -C448 0901 00901 ORA #1 -C44A 661D 00902 ROR CONT_BITS -C44C 9002 00903 BCC $+4 -C44E A20B 00904 LDX #11 -C450 661D 00905 ROR CONT_BITS -C452 9002 00906 BCC $+4 -C454 A20A 00907 LDX #10 -C456 661D 00908 ROR CONT_BITS -C458 9002 00909 BCC $+4 -C45A 0940 00910 ORA #$40 -C45C 661D 00911 ROR CONT_BITS -C45E 9002 00912 BCC $+4 -C460 0980 00913 ORA #$80 -C462 60 00914 RTS -C463 00915 -C463 00916 WAIT: -C463 A512 00917 LDA FRAME -C465 C512 00918 .1: CMP FRAME -C467 F0FC 00919 BEQ .1 -C469 60 00920 RTS -C46A 00921 -C46A 00922 PRINT_STRING_CURSOR_CONSTANT: -C46A 68 00923 PLA -C46B 8502 00924 STA TEMP -C46D 68 00925 PLA -C46E 8503 00926 STA TEMP+1 -C470 A001 00927 LDY #1 -C472 B102 00928 LDA (TEMP),Y -C474 850C 00929 STA CURSOR -C476 C8 00930 INY -C477 B102 00931 LDA (TEMP),Y -C479 850D 00932 STA CURSOR+1 -C47B C8 00933 INY -C47C B102 00934 LDA (TEMP),Y -C47E 8504 00935 STA TEMP2 -C480 98 00936 TYA -C481 18 00937 CLC -C482 6502 00938 ADC TEMP -C484 8502 00939 STA TEMP -C486 9002 00940 BCC $+4 -C488 E603 00941 INC TEMP+1 -C48A A504 00942 LDA TEMP2 -C48C D016 00943 BNE PRINT_STRING.2 -C48E 00944 -C48E 00945 PRINT_STRING_CURSOR: -C48E 850C 00946 STA CURSOR -C490 840D 00947 STY CURSOR+1 -C492 00948 PRINT_STRING: -C492 68 00949 PLA -C493 8502 00950 STA TEMP -C495 68 00951 PLA -C496 8503 00952 STA TEMP+1 -C498 A001 00953 LDY #1 -C49A B102 00954 LDA (TEMP),Y -C49C 8504 00955 STA TEMP2 -C49E E602 00956 INC TEMP -C4A0 D002 00957 BNE $+4 -C4A2 E603 00958 INC TEMP+1 -C4A4 18 00959 .2: CLC -C4A5 6502 00960 ADC TEMP -C4A7 A8 00961 TAY -C4A8 A900 00962 LDA #0 -C4AA 6503 00963 ADC TEMP+1 -C4AC 48 00964 PHA -C4AD 98 00965 TYA -C4AE 48 00966 PHA -C4AF E602 00967 INC TEMP -C4B1 D002 00968 BNE $+4 -C4B3 E603 00969 INC TEMP+1 -C4B5 A614 00970 LDX PPU_POINTER -C4B7 A50C 00971 LDA CURSOR -C4B9 9D0001 00972 STA PPUBUF,X -C4BC A50D 00973 LDA CURSOR+1 -C4BE 2907 00974 AND #$07 -C4C0 0920 00975 ORA #$20 -C4C2 9D0101 00976 STA PPUBUF+1,X -C4C5 A900 00977 LDA #0 -C4C7 38 00978 SEC -C4C8 E504 00979 SBC TEMP2 -C4CA 9D0201 00980 STA PPUBUF+2,X -C4CD A502 00981 LDA TEMP -C4CF 38 00982 SEC -C4D0 FD0201 00983 SBC PPUBUF+2,X -C4D3 9D0301 00984 STA PPUBUF+3,X -C4D6 A503 00985 LDA TEMP+1 -C4D8 E900 00986 SBC #0 -C4DA 9D0401 00987 STA PPUBUF+4,X -C4DD 8A 00988 TXA -C4DE 18 00989 CLC -C4DF 6905 00990 ADC #5 -C4E1 8514 00991 STA PPU_POINTER -C4E3 A504 00992 LDA TEMP2 -C4E5 18 00993 CLC -C4E6 650C 00994 ADC CURSOR -C4E8 850C 00995 STA CURSOR -C4EA 9002 00996 BCC .1 -C4EC E60D 00997 INC CURSOR+1 -C4EE 00998 .1: -C4EE 60 00999 RTS -C4EF 01000 -C4EF 01001 PRINT_NUMBER: -C4EF A200 01002 LDX #0 -C4F1 8602 01003 STX TEMP -C4F3 78 01004 SEI -C4F4 01005 PRINT_NUMBER5: -C4F4 A210 01006 LDX #10000 -C4F6 8604 01007 STX TEMP2 -C4F8 A227 01008 LDX #10000/256 -C4FA 8605 01009 STX TEMP2+1 -C4FC 202FC5 01010 JSR PRINT_DIGIT -C4FF 01011 PRINT_NUMBER4: -C4FF A2E8 01012 LDX #1000 -C501 8604 01013 STX TEMP2 -C503 A203 01014 LDX #1000/256 -C505 8605 01015 STX TEMP2+1 -C507 202FC5 01016 JSR PRINT_DIGIT -C50A 01017 PRINT_NUMBER3: -C50A A264 01018 LDX #100 -C50C 8604 01019 STX TEMP2 -C50E A200 01020 LDX #0 -C510 8605 01021 STX TEMP2+1 -C512 202FC5 01022 JSR PRINT_DIGIT -C515 01023 PRINT_NUMBER2: -C515 A20A 01024 LDX #10 -C517 8604 01025 STX TEMP2 -C519 A200 01026 LDX #0 -C51B 8605 01027 STX TEMP2+1 -C51D 202FC5 01028 JSR PRINT_DIGIT -C520 01029 PRINT_NUMBER1: -C520 A201 01030 LDX #1 -C522 8604 01031 STX TEMP2 -C524 8602 01032 STX TEMP -C526 A200 01033 LDX #0 -C528 8605 01034 STX TEMP2+1 -C52A 202FC5 01035 JSR PRINT_DIGIT -C52D 58 01036 CLI -C52E 60 01037 RTS -C52F 01038 -C52F 01039 PRINT_DIGIT: -C52F A22F 01040 LDX #$2F -C531 01041 .2: -C531 E8 01042 INX -C532 38 01043 SEC -C533 E504 01044 SBC TEMP2 -C535 48 01045 PHA -C536 98 01046 TYA -C537 E505 01047 SBC TEMP2+1 -C539 A8 01048 TAY -C53A 68 01049 PLA -C53B B0F4 01050 BCS .2 -C53D 18 01051 CLC -C53E 6504 01052 ADC TEMP2 -C540 48 01053 PHA -C541 98 01054 TYA -C542 6505 01055 ADC TEMP2+1 -C544 A8 01056 TAY -C545 68 01057 PLA -C546 E030 01058 CPX #$30 -C548 D00E 01059 BNE .3 -C54A A602 01060 LDX TEMP -C54C D001 01061 BNE .4 -C54E 60 01062 RTS -C54F 01063 -C54F CA 01064 .4: DEX -C550 F004 01065 BEQ .6 -C552 A603 01066 LDX TEMP+1 -C554 D008 01067 BNE PRINT_CHAR -C556 01068 .6: -C556 A230 01069 LDX #$30 -C558 48 01070 .3: PHA -C559 A901 01071 LDA #1 -C55B 8502 01072 STA TEMP -C55D 68 01073 PLA -C55E 01074 -C55E 01075 PRINT_CHAR: -C55E 48 01076 PHA -C55F 98 01077 TYA -C560 48 01078 PHA -C561 A50D 01079 LDA CURSOR+1 -C563 2907 01080 AND #$07 -C565 0920 01081 ORA #$20 -C567 A8 01082 TAY -C568 A50C 01083 LDA CURSOR -C56A 2000C0 01084 JSR WRTVRM -C56D E60C 01085 INC CURSOR -C56F D002 01086 BNE .1 -C571 E60D 01087 INC CURSOR+1 -C573 01088 .1: -C573 68 01089 PLA -C574 A8 01090 TAY -C575 68 01091 PLA -C576 60 01092 RTS -C577 01093 -C577 01094 MODE_0: -C577 20C6C0 01095 JSR CLS -C57A 01096 CLEAR_SPRITES: -C57A A9F0 01097 LDA #$F0 -C57C A200 01098 LDX #0 -C57E 01099 .1: -C57E 9D0002 01100 STA $0200,X -C581 E8 01101 INX -C582 E8 01102 INX -C583 E8 01103 INX -C584 E8 01104 INX -C585 D0F7 01105 BNE .1 -C587 60 01106 RTS -C588 01107 -C588 01108 MUSIC_INIT: -C588 A940 01109 LDA #$40 -C58A 8D1740 01110 STA $4017 -C58D A910 01111 LDA #$10 -C58F 8D0040 01112 STA $4000 ; Channel 1 silent -C592 8D0440 01113 STA $4004 ; Channel 2 silent -C595 8D0C40 01114 STA $400C ; Channel 4 silent -C598 A90B 01115 LDA #$0B -C59A 8D1540 01116 STA $4015 ; Enable channel 1, 2 and 4. -C59D A900 01117 LDA #$00 -C59F 8D1040 01118 STA $4010 -C5A2 01119 IF CVBASIC_MUSIC_PLAYER -C5A2 01120 ELSE -C5A2 01121 RTS -C5A2 01122 ENDIF -C5A2 01123 -C5A2 01124 IF CVBASIC_MUSIC_PLAYER -C5A2 A903 01125 LDA #MUSIC_SILENCE -C5A4 A0C9 01126 LDY #MUSIC_SILENCE>>8 -C5A6 01127 ; -C5A6 01128 ; Play music. -C5A6 01129 ; YA = Pointer to music. -C5A6 01130 ; -C5A6 01131 MUSIC_PLAY: -C5A6 78 01132 SEI -C5A7 8534 01133 STA MUSIC_POINTER -C5A9 8435 01134 STY MUSIC_POINTER+1 -C5AB A000 01135 LDY #0 -C5AD 8436 01136 STY MUSIC_NOTE_COUNTER -C5AF B134 01137 LDA (MUSIC_POINTER),Y -C5B1 8531 01138 STA MUSIC_TIMING -C5B3 C8 01139 INY -C5B4 844F 01140 STY MUSIC_PLAYING -C5B6 E634 01141 INC MUSIC_POINTER -C5B8 D002 01142 BNE $+4 -C5BA E635 01143 INC MUSIC_POINTER+1 -C5BC A534 01144 LDA MUSIC_POINTER -C5BE A435 01145 LDY MUSIC_POINTER+1 -C5C0 8532 01146 STA MUSIC_START -C5C2 8433 01147 STY MUSIC_START+1 -C5C4 01148 IF CVBASIC_BANK_SWITCHING -C5C4 ADFFBF 01149 LDA $BFFF -C5C7 8530 01150 STA MUSIC_BANK -C5C9 01151 ENDIF -C5C9 58 01152 CLI -C5CA 60 01153 RTS -C5CB 01154 -C5CB 01155 ; -C5CB 01156 ; Generates music -C5CB 01157 ; -C5CB 01158 MUSIC_GENERATE: -C5CB A910 01159 LDA #$10 -C5CD 8548 01160 STA AUDIO_VOL1 -C5CF 8549 01161 STA AUDIO_VOL2 -C5D1 854A 01162 STA AUDIO_VOL3 -C5D3 854B 01163 STA AUDIO_VOL4HW -C5D5 A536 01164 LDA MUSIC_NOTE_COUNTER -C5D7 F003 01165 BEQ .1 -C5D9 4C5CC6 01166 JMP .2 -C5DC 01167 .1: -C5DC 01168 IF CVBASIC_BANK_SWITCHING -C5DC A530 01169 LDA MUSIC_BANK -C5DE 051C 01170 ORA CHRRAM_BANK -C5E0 8D00C0 01171 STA BANKSEL -C5E3 01172 ENDIF -C5E3 A000 01173 LDY #0 -C5E5 B134 01174 LDA (MUSIC_POINTER),Y -C5E7 C9FE 01175 CMP #$FE ; End of music? -C5E9 D005 01176 BNE .3 ; No, jump. -C5EB A900 01177 LDA #0 ; Keep at same place. -C5ED 854F 01178 STA MUSIC_PLAYING -C5EF 60 01179 RTS -C5F0 01180 -C5F0 C9FD 01181 .3: CMP #$FD ; Repeat music? -C5F2 D00B 01182 BNE .4 -C5F4 A532 01183 LDA MUSIC_START -C5F6 A433 01184 LDY MUSIC_START+1 -C5F8 8534 01185 STA MUSIC_POINTER -C5FA 8435 01186 STY MUSIC_POINTER+1 -C5FC 4CDCC5 01187 JMP .1 -C5FF 01188 -C5FF A531 01189 .4: LDA MUSIC_TIMING -C601 293F 01190 AND #$3F ; Restart note time. -C603 8536 01191 STA MUSIC_NOTE_COUNTER -C605 01192 -C605 B134 01193 LDA (MUSIC_POINTER),Y -C607 C93F 01194 CMP #$3F ; Sustain? -C609 F00F 01195 BEQ .5 -C60B 29C0 01196 AND #$C0 -C60D 8537 01197 STA MUSIC_INSTRUMENT_1 -C60F B134 01198 LDA (MUSIC_POINTER),Y -C611 293F 01199 AND #$3F -C613 0A 01200 ASL A -C614 8538 01201 STA MUSIC_NOTE_1 -C616 A900 01202 LDA #0 -C618 8539 01203 STA MUSIC_COUNTER_1 -C61A 01204 .5: -C61A C8 01205 INY -C61B B134 01206 LDA (MUSIC_POINTER),Y -C61D C93F 01207 CMP #$3F ; Sustain? -C61F F00F 01208 BEQ .6 -C621 29C0 01209 AND #$C0 -C623 853A 01210 STA MUSIC_INSTRUMENT_2 -C625 B134 01211 LDA (MUSIC_POINTER),Y -C627 293F 01212 AND #$3F -C629 0A 01213 ASL A -C62A 853B 01214 STA MUSIC_NOTE_2 -C62C A900 01215 LDA #0 -C62E 853C 01216 STA MUSIC_COUNTER_2 -C630 01217 .6: -C630 C8 01218 INY -C631 B134 01219 LDA (MUSIC_POINTER),Y -C633 C93F 01220 CMP #$3F ; Sustain? -C635 F00F 01221 BEQ .7 -C637 29C0 01222 AND #$C0 -C639 853D 01223 STA MUSIC_INSTRUMENT_3 -C63B B134 01224 LDA (MUSIC_POINTER),Y -C63D 293F 01225 AND #$3F -C63F 0A 01226 ASL A -C640 853E 01227 STA MUSIC_NOTE_3 -C642 A900 01228 LDA #0 -C644 853F 01229 STA MUSIC_COUNTER_3 -C646 01230 .7: -C646 C8 01231 INY -C647 B134 01232 LDA (MUSIC_POINTER),Y -C649 8540 01233 STA MUSIC_DRUM -C64B A900 01234 LDA #0 -C64D 8541 01235 STA MUSIC_COUNTER_4 -C64F A534 01236 LDA MUSIC_POINTER -C651 18 01237 CLC -C652 6904 01238 ADC #4 -C654 8534 01239 STA MUSIC_POINTER -C656 A535 01240 LDA MUSIC_POINTER+1 -C658 6900 01241 ADC #0 -C65A 8535 01242 STA MUSIC_POINTER+1 -C65C 01243 .2: -C65C A438 01244 LDY MUSIC_NOTE_1 -C65E F00D 01245 BEQ .8 -C660 A537 01246 LDA MUSIC_INSTRUMENT_1 -C662 A639 01247 LDX MUSIC_COUNTER_1 -C664 2037C7 01248 JSR MUSIC_NOTE2FREQ -C667 8542 01249 STA AUDIO_FREQ1 -C669 8443 01250 STY AUDIO_FREQ1+1 -C66B 8648 01251 STX AUDIO_VOL1 -C66D 01252 .8: -C66D A43B 01253 LDY MUSIC_NOTE_2 -C66F F00D 01254 BEQ .9 -C671 A53A 01255 LDA MUSIC_INSTRUMENT_2 -C673 A63C 01256 LDX MUSIC_COUNTER_2 -C675 2037C7 01257 JSR MUSIC_NOTE2FREQ -C678 8544 01258 STA AUDIO_FREQ2 -C67A 8445 01259 STY AUDIO_FREQ2+1 -C67C 8649 01260 STX AUDIO_VOL2 -C67E 01261 .9: -C67E A43E 01262 LDY MUSIC_NOTE_3 -C680 F00D 01263 BEQ .10 -C682 A53D 01264 LDA MUSIC_INSTRUMENT_3 -C684 A63F 01265 LDX MUSIC_COUNTER_3 -C686 2037C7 01266 JSR MUSIC_NOTE2FREQ -C689 8546 01267 STA AUDIO_FREQ3 -C68B 8447 01268 STY AUDIO_FREQ3+1 -C68D 864A 01269 STX AUDIO_VOL3 -C68F 01270 .10: -C68F A540 01271 LDA MUSIC_DRUM -C691 F03A 01272 BEQ .11 -C693 C901 01273 CMP #1 ; 1 - Long drum. -C695 D011 01274 BNE .12 -C697 A541 01275 LDA MUSIC_COUNTER_4 -C699 C903 01276 CMP #3 -C69B B030 01277 BCS .11 -C69D 01278 .15: -C69D A906 01279 LDA #$06 -C69F 854C 01280 STA AUDIO_NOISE -C6A1 A99C 01281 LDA #$9C -C6A3 854B 01282 STA AUDIO_VOL4HW -C6A5 4CCDC6 01283 JMP .11 -C6A8 01284 -C6A8 C902 01285 .12: CMP #2 ; 2 - Short drum. -C6AA D011 01286 BNE .14 -C6AC A541 01287 LDA MUSIC_COUNTER_4 -C6AE C900 01288 CMP #0 -C6B0 D01B 01289 BNE .11 -C6B2 A902 01290 LDA #$02 -C6B4 854C 01291 STA AUDIO_NOISE -C6B6 A99C 01292 LDA #$9C -C6B8 854B 01293 STA AUDIO_VOL4HW -C6BA 4CCDC6 01294 JMP .11 -C6BD 01295 -C6BD 01296 .14: ;CMP #3 ; 3 - Roll. -C6BD 01297 ;BNE -C6BD A541 01298 LDA MUSIC_COUNTER_4 -C6BF C902 01299 CMP #2 -C6C1 90DA 01300 BCC .15 -C6C3 0A 01301 ASL A -C6C4 38 01302 SEC -C6C5 E531 01303 SBC MUSIC_TIMING -C6C7 9004 01304 BCC .11 -C6C9 C904 01305 CMP #4 -C6CB 90D0 01306 BCC .15 -C6CD 01307 .11: -C6CD A639 01308 LDX MUSIC_COUNTER_1 -C6CF E8 01309 INX -C6D0 E018 01310 CPX #$18 -C6D2 D002 01311 BNE $+4 -C6D4 A210 01312 LDX #$10 -C6D6 8639 01313 STX MUSIC_COUNTER_1 -C6D8 01314 -C6D8 A63C 01315 LDX MUSIC_COUNTER_2 -C6DA E8 01316 INX -C6DB E018 01317 CPX #$18 -C6DD D002 01318 BNE $+4 -C6DF A210 01319 LDX #$10 -C6E1 863C 01320 STX MUSIC_COUNTER_2 -C6E3 01321 -C6E3 A63F 01322 LDX MUSIC_COUNTER_3 -C6E5 E8 01323 INX -C6E6 E018 01324 CPX #$18 -C6E8 D002 01325 BNE $+4 -C6EA A210 01326 LDX #$10 -C6EC 863F 01327 STX MUSIC_COUNTER_3 -C6EE 01328 -C6EE E641 01329 INC MUSIC_COUNTER_4 -C6F0 C636 01330 DEC MUSIC_NOTE_COUNTER -C6F2 60 01331 RTS -C6F3 01332 -C6F3 01333 MUSIC_FLUTE: -C6F3 B9DDC7 01334 LDA MUSIC_NOTES_TABLE,Y -C6F6 18 01335 CLC -C6F7 7D1FC7 01336 ADC .2,X -C6FA 48 01337 PHA -C6FB B9DEC7 01338 LDA MUSIC_NOTES_TABLE+1,Y -C6FE 6900 01339 ADC #0 -C700 A8 01340 TAY -C701 BD07C7 01341 LDA .1,X -C704 AA 01342 TAX -C705 68 01343 PLA -C706 60 01344 RTS -C707 01345 -C707 01346 .1: -C707 9A9C9D9D9C9C9C9C 01347 DB $9A,$9C,$9D,$9D,$9C,$9C,$9C,$9C -C70F 9B9B9B9B9A9A9A9A 01348 DB $9B,$9B,$9B,$9B,$9A,$9A,$9A,$9A -C717 9B9B9B9B9A9A9A9A 01349 DB $9B,$9B,$9B,$9B,$9A,$9A,$9A,$9A -C71F 01350 -C71F 01351 .2: -C71F 0000000000010101 01352 DB 0,0,0,0,0,1,1,1 -C727 0001010100010101 01353 DB 0,1,1,1,0,1,1,1 -C72F 0001010100010101 01354 DB 0,1,1,1,0,1,1,1 -C737 01355 -C737 01356 ; -C737 01357 ; Converts note to frequency. -C737 01358 ; Input: -C737 01359 ; A = Instrument. -C737 01360 ; Y = Note (1-62) -C737 01361 ; X = Instrument counter. -C737 01362 ; Output: -C737 01363 ; YA = Frequency. -C737 01364 ; X = Volume. -C737 01365 ; -C737 01366 MUSIC_NOTE2FREQ: -C737 C940 01367 CMP #$40 -C739 902E 01368 BCC MUSIC_PIANO -C73B F052 01369 BEQ MUSIC_CLARINET -C73D C980 01370 CMP #$80 -C73F F0B2 01371 BEQ MUSIC_FLUTE -C741 01372 ; -C741 01373 ; Bass instrument -C741 01374 ; -C741 01375 MUSIC_BASS: -C741 B9DDC7 01376 LDA MUSIC_NOTES_TABLE,Y -C744 0A 01377 ASL A -C745 48 01378 PHA -C746 B9DEC7 01379 LDA MUSIC_NOTES_TABLE+1,Y -C749 2A 01380 ROL A -C74A A8 01381 TAY -C74B BD51C7 01382 LDA .1,X -C74E AA 01383 TAX -C74F 68 01384 PLA -C750 60 01385 RTS -C751 01386 -C751 01387 .1: -C751 9D9D9C9C9B9B9A9A 01388 DB $9D,$9D,$9C,$9C,$9B,$9B,$9A,$9A -C759 9999989897979696 01389 DB $99,$99,$98,$98,$97,$97,$96,$96 -C761 9595949493939292 01390 DB $95,$95,$94,$94,$93,$93,$92,$92 -C769 01391 -C769 01392 MUSIC_PIANO: -C769 B9DDC7 01393 LDA MUSIC_NOTES_TABLE,Y -C76C 48 01394 PHA -C76D B9DEC7 01395 LDA MUSIC_NOTES_TABLE+1,Y -C770 A8 01396 TAY -C771 BD77C7 01397 LDA .1,X -C774 AA 01398 TAX -C775 68 01399 PLA -C776 60 01400 RTS -C777 01401 -C777 01402 .1: -C777 DCDBDBDADAD9D9D8 01403 DB $DC,$DB,$DB,$DA,$DA,$D9,$D9,$D8 -C77F D8D7D7D6D6D5D5D4 01404 DB $D8,$D7,$D7,$D6,$D6,$D5,$D5,$D4 -C787 D4D4D5D5D4D4D3D3 01405 DB $D4,$D4,$D5,$D5,$D4,$D4,$D3,$D3 -C78F 01406 -C78F 01407 MUSIC_CLARINET: -C78F B9DDC7 01408 LDA MUSIC_NOTES_TABLE,Y -C792 18 01409 CLC -C793 7DC5C7 01410 ADC .2,X -C796 48 01411 PHA -C797 BDC5C7 01412 LDA .2,X -C79A 3003 01413 BMI .3 -C79C A900 01414 LDA #$00 -C79E 2C 01415 DB $2C -C79F A9FF 01416 .3: LDA #$FF -C7A1 79DEC7 01417 ADC MUSIC_NOTES_TABLE+1,Y -C7A4 4A 01418 LSR A -C7A5 A8 01419 TAY -C7A6 BDADC7 01420 LDA .1,X -C7A9 AA 01421 TAX -C7AA 68 01422 PLA -C7AB 6A 01423 ROR A -C7AC 60 01424 RTS -C7AD 01425 -C7AD 01426 .1: -C7AD 1D1E1E1D1D1C1C1C 01427 DB $1D,$1E,$1E,$1D,$1D,$1C,$1C,$1C -C7B5 1B1B1B1B1C1C1C1C 01428 DB $1B,$1B,$1B,$1B,$1C,$1C,$1C,$1C -C7BD 1B1B1B1B1C1C1C1C 01429 DB $1B,$1B,$1B,$1B,$1C,$1C,$1C,$1C -C7C5 01430 -C7C5 01431 .2: -C7C5 00000000FFFFFF00 01432 DB 0,0,0,0,-1,-1,-1,0 -C7CD 01010100FFFFFF00 01433 DB 1,1,1,0,-1,-1,-1,0 -C7D5 01010100FFFFFF00 01434 DB 1,1,1,0,-1,-1,-1,0 -C7DD 01435 -C7DD 01436 ; -C7DD 01437 ; Musical notes table. -C7DD 01438 ; -C7DD 01439 MUSIC_NOTES_TABLE: -C7DD 01440 ; Silence - 0 -C7DD 0000 01441 DW 0 -C7DF 01442 ; Values for 1.79 mhz. / 16, offset 0 -C7DF 01443 ; 2nd octave - Index 1 -C7DF AE064E06F4059E05 01444 DW 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 -C7F7 01445 ; 3rd octave - Index 13 -C7F7 57032703FA02CF02 01446 DW 855,807,762,719,679,641,605,571,539,508,480,453 -C80F 01447 ; 4th octave - Index 25 -C80F AC0194017D016801 01448 DW 428,404,381,360,339,320,302,285,269,254,240,226 -C827 01449 ; 5th octave - Index 37 -C827 D600CA00BE00B400 01450 DW 214,202,190,180,170,160,151,143,135,127,120,113 -C83F 01451 ; 6th octave - Index 49 -C83F 6B0065005F005A00 01452 DW 107,101,95,90,85,80,76,71,67,64,60,57 -C857 01453 ; 7th octave - Index 61 -C857 350032003000 01454 DW 53,50,48 -C85D 01455 -C85D 01456 ; -C85D 01457 ; When the frequency upper byte is rewritten, the -C85D 01458 ; output phase is reset, and it creates glitches. -C85D 01459 ; So it doesn't rewrite frequency unless the note -C85D 01460 ; changes. -C85D 01461 ; -C85D 01462 MUSIC_HARDWARE: -C85D A54E 01463 LDA MUSIC_MODE -C85F C904 01464 CMP #4 ; PLAY SIMPLE? -C861 901C 01465 BCC .9 ; Yes, jump. -C863 A549 01466 LDA AUDIO_VOL2 -C865 290F 01467 AND #$0F -C867 D016 01468 BNE .9 -C869 A54A 01469 LDA AUDIO_VOL3 -C86B 290F 01470 AND #$0F -C86D F010 01471 BEQ .9 -C86F A54A 01472 LDA AUDIO_VOL3 -C871 8549 01473 STA AUDIO_VOL2 -C873 A910 01474 LDA #$10 -C875 854A 01475 STA AUDIO_VOL3 -C877 A546 01476 LDA AUDIO_FREQ3 -C879 A447 01477 LDY AUDIO_FREQ3+1 -C87B 8544 01478 STA AUDIO_FREQ2 -C87D 8445 01479 STY AUDIO_FREQ2+1 -C87F 01480 .9: -C87F A542 01481 LDA AUDIO_FREQ1 -C881 8D0240 01482 STA $4002 -C884 A539 01483 LDA MUSIC_COUNTER_1 -C886 C901 01484 CMP #1 -C888 D007 01485 BNE .3 -C88A A543 01486 LDA AUDIO_FREQ1+1 -C88C 0908 01487 ORA #$08 ; Keeps tone enabled -C88E 8D0340 01488 STA $4003 -C891 A548 01489 .3: LDA AUDIO_VOL1 -C893 8D0040 01490 STA $4000 -C896 A900 01491 LDA #0 -C898 8D0140 01492 STA $4001 -C89B 01493 -C89B A544 01494 LDA AUDIO_FREQ2 -C89D 8D0640 01495 STA $4006 -C8A0 A53C 01496 LDA MUSIC_COUNTER_2 -C8A2 C901 01497 CMP #1 -C8A4 D007 01498 BNE .4 -C8A6 A545 01499 LDA AUDIO_FREQ2+1 -C8A8 0908 01500 ORA #$08 ; Keeps tone enabled -C8AA 8D0740 01501 STA $4007 -C8AD A549 01502 .4: LDA AUDIO_VOL2 -C8AF 8D0440 01503 STA $4004 -C8B2 A900 01504 LDA #0 -C8B4 8D0540 01505 STA $4005 -C8B7 01506 -C8B7 A54E 01507 LDA MUSIC_MODE -C8B9 C904 01508 CMP #4 ; PLAY SIMPLE? -C8BB 902B 01509 BCC .6 ; Yes, jump. -C8BD 01510 -C8BD 4647 01511 LSR AUDIO_FREQ3+1 -C8BF 6646 01512 ROR AUDIO_FREQ3 -C8C1 A546 01513 LDA AUDIO_FREQ3 -C8C3 8D0A40 01514 STA $400A -C8C6 A53F 01515 LDA MUSIC_COUNTER_3 -C8C8 C901 01516 CMP #1 -C8CA D007 01517 BNE .5 -C8CC A547 01518 LDA AUDIO_FREQ3+1 -C8CE 0908 01519 ORA #$08 ; Keeps tone enabled -C8D0 8D0B40 01520 STA $400B -C8D3 01521 .5: -C8D3 A920 01522 LDA #$20 -C8D5 8D0840 01523 STA $4008 -C8D8 A54A 01524 LDA AUDIO_VOL3 -C8DA 290F 01525 AND #$0F -C8DC D005 01526 BNE .1 -C8DE A90B 01527 LDA #$0B -C8E0 4CE5C8 01528 JMP .2 -C8E3 01529 -C8E3 A90F 01530 .1: LDA #$0F -C8E5 8D1540 01531 .2: STA $4015 -C8E8 01532 -C8E8 A54E 01533 .6: LDA MUSIC_MODE -C8EA 4A 01534 LSR A ; NO DRUMS? -C8EB 9015 01535 BCC .8 -C8ED A541 01536 LDA MUSIC_COUNTER_4 -C8EF C901 01537 CMP #1 -C8F1 D00A 01538 BNE .7 -C8F3 A54C 01539 LDA AUDIO_NOISE -C8F5 8D0E40 01540 STA $400E -C8F8 0908 01541 ORA #$08 ; Keeps tone enabled -C8FA 8D0F40 01542 STA $400F -C8FD A54B 01543 .7: LDA AUDIO_VOL4HW -C8FF 8D0C40 01544 STA $400C -C902 01545 .8: -C902 60 01546 RTS -C903 01547 -C903 01548 MUSIC_SILENCE: -C903 08 01549 DB 8 -C904 00000000 01550 DB 0,0,0,0 -C908 FE 01551 DB -2 -C909 01552 ENDIF -C909 01553 -C909 01554 -C909 01555 IF CVBASIC_BANK_SWITCHING -C909 01556 COPY_CHRRAM: -C909 A900 01557 LDA #$00 -C90B 8D0620 01558 STA PPUADDR -C90E 8D0620 01559 STA PPUADDR -C911 8502 01560 STA TEMP -C913 8603 01561 STX TEMP+1 -C915 A220 01562 LDX #32 -C917 01563 .1: -C917 201EC9 01564 JSR COPY_PAGE -C91A CA 01565 DEX -C91B D0FA 01566 BNE .1 -C91D 60 01567 RTS -C91E 01568 -C91E 01569 COPY_PAGE: -C91E A000 01570 LDY #0 -C920 01571 .1: -C920 B102 01572 LDA (TEMP),Y -C922 8D0720 01573 STA PPUDATA -C925 C8 01574 INY -C926 D0F8 01575 BNE .1 -C928 E603 01576 INC TEMP+1 -C92A 60 01577 RTS -C92B 01578 ENDIF -C92B 01579 -C92B 01580 START: -C92B 78 01581 SEI -C92C D8 01582 CLD -C92D 01583 -C92D 2C0220 01584 BIT PPUSTATUS -C930 01585 -C930 A940 01586 LDA #$40 -C932 8D1740 01587 STA $4017 -C935 A910 01588 LDA #$10 -C937 8D0040 01589 STA $4000 ; Channel 1 silent -C93A 8D0440 01590 STA $4004 ; Channel 2 silent -C93D 8D0C40 01591 STA $400C ; Channel 4 silent -C940 A90B 01592 LDA #$0B -C942 8D1540 01593 STA $4015 ; Enable channel 1, 2 and 4. -C945 A900 01594 LDA #$00 -C947 8D1040 01595 STA $4010 -C94A 01596 -C94A A900 01597 LDA #0 -C94C 8D0020 01598 STA PPUCTRL -C94F 8D0120 01599 STA PPUMASK -C952 01600 -C952 AA 01601 TAX -C953 9500 01602 .1: STA $00,X -C955 9D0001 01603 STA $0100,X -C958 9D0003 01604 STA $0300,X -C95B 9D0004 01605 STA $0400,X -C95E 9D0005 01606 STA $0500,X -C961 9D0006 01607 STA $0600,X -C964 9D0007 01608 STA $0700,X -C967 E8 01609 INX -C968 D0E9 01610 BNE .1 -C96A 01611 -C96A A2FF 01612 LDX #STACK -C96C 9A 01613 TXS -C96D 01614 -C96D 207AC5 01615 JSR CLEAR_SPRITES -C970 01616 -C970 01617 ; -C970 01618 ; The NES starts with the PPU registers write-protected. -C970 01619 ; Around 29000 cycles must happen before these can be written. -C970 01620 ; -C970 01621 -C970 01622 ; lidnariq code for detecting NTSC/PAL/Dendy system -C970 01623 ; From: https://forums.nesdev.org/viewtopic.php?p=163258#p163258 -C970 A200 01624 LDX #0 -C972 A000 01625 LDY #0 -C974 2C0220 01626 BIT PPUSTATUS -C977 10FB 01627 BPL $-3 -C979 01628 .5: -C979 E8 01629 INX -C97A D001 01630 BNE .6 -C97C C8 01631 INY -C97D 01632 .6: -C97D 01633 ; About 27384 cycles passed at this time. -C97D 2C0220 01634 BIT PPUSTATUS -C980 10F7 01635 BPL .5 -C982 A900 01636 LDA #0 -C984 8D0020 01637 STA PPUCTRL -C987 8D0120 01638 STA PPUMASK -C98A 01639 -C98A 98 01640 TYA -C98B C910 01641 CMP #16 -C98D 9001 01642 BCC .7 -C98F 4A 01643 LSR A -C990 18 01644 .7: CLC -C991 69F7 01645 ADC #$F7 -C993 C903 01646 CMP #3 -C995 9002 01647 BCC .8 -C997 A903 01648 LDA #3 ; Bad -C999 01649 ; 0=NTSC, 1=Pal, 2=Dendy, 3=Bad -C999 01650 .8: -C999 C900 01651 CMP #0 ; Pass NTSC unchanged -C99B F002 01652 BEQ .9 -C99D A901 01653 LDA #1 ; All other PAL -C99F 4901 01654 .9: EOR #1 -C9A1 850F 01655 STA NTSC -C9A3 01656 ; About 57165 cycles passed at this time. -C9A3 01657 -C9A3 01658 IF CVBASIC_BANK_SWITCHING -C9A3 01659 ; Copy CHRROM to CHRRAM -C9A3 A90D 01660 LDA #$00+CVBASIC_BANK_ROM_SIZE/16-3 -C9A5 8D00C0 01661 STA BANKSEL -C9A8 A280 01662 LDX #$80 -C9AA 2009C9 01663 JSR COPY_CHRRAM -C9AD 01664 -C9AD A92D 01665 LDA #$20+CVBASIC_BANK_ROM_SIZE/16-3 -C9AF 8D00C0 01666 STA BANKSEL -C9B2 A2A0 01667 LDX #$A0 -C9B4 2009C9 01668 JSR COPY_CHRRAM -C9B7 01669 -C9B7 A94E 01670 LDA #$40+CVBASIC_BANK_ROM_SIZE/16-2 -C9B9 8D00C0 01671 STA BANKSEL -C9BC A280 01672 LDX #$80 -C9BE 2009C9 01673 JSR COPY_CHRRAM -C9C1 01674 -C9C1 A96E 01675 LDA #$60+CVBASIC_BANK_ROM_SIZE/16-2 -C9C3 8D00C0 01676 STA BANKSEL -C9C6 A2A0 01677 LDX #$A0 -C9C8 2009C9 01678 JSR COPY_CHRRAM -C9CB 01679 -C9CB A900 01680 LDA #$00 ; BANK SELECT 1 -C9CD 8D00C0 01681 STA BANKSEL -C9D0 01682 ENDIF -C9D0 01683 -C9D0 01684 ; Clear 2K of pattern memory -C9D0 A920 01685 LDA #$20 -C9D2 8D0620 01686 STA PPUADDR -C9D5 A900 01687 LDA #$00 -C9D7 8D0620 01688 STA PPUADDR -C9DA A278 01689 LDX #$78 -C9DC A920 01690 LDA #$20 -C9DE 01691 .2: -C9DE 8D0720 01692 STA PPUDATA -C9E1 8D0720 01693 STA PPUDATA -C9E4 8D0720 01694 STA PPUDATA -C9E7 8D0720 01695 STA PPUDATA -C9EA 8D0720 01696 STA PPUDATA -C9ED 8D0720 01697 STA PPUDATA -C9F0 8D0720 01698 STA PPUDATA -C9F3 8D0720 01699 STA PPUDATA -C9F6 CA 01700 DEX -C9F7 D0E5 01701 BNE .2 -C9F9 01702 -C9F9 A240 01703 LDX #$40 -C9FB A900 01704 LDA #$00 -C9FD 8D0720 01705 .3: STA PPUDATA -CA00 CA 01706 DEX -CA01 D0FA 01707 BNE .3 -CA03 01708 -CA03 01709 ; Setup base palette -CA03 A93F 01710 LDA #$3F -CA05 8D0620 01711 STA PPUADDR -CA08 A900 01712 LDA #$00 -CA0A 8D0620 01713 STA PPUADDR -CA0D A208 01714 LDX #8 -CA0F 01715 .4: -CA0F A90F 01716 LDA #$0F ; Black -CA11 8D0720 01717 STA PPUDATA -CA14 A935 01718 LDA #$35 ; Red -CA16 8D0720 01719 STA PPUDATA -CA19 A93A 01720 LDA #$3A ; Green -CA1B 8D0720 01721 STA PPUDATA -CA1E A930 01722 LDA #$30 ; White -CA20 8D0720 01723 STA PPUDATA -CA23 CA 01724 DEX -CA24 D0E9 01725 BNE .4 -CA26 01726 -CA26 2C0220 01727 BIT PPUSTATUS -CA29 10FB 01728 BPL $-3 -CA2B A91E 01729 LDA #$1E ; Color normal, Sprites visible, Background visible, No clipping, Color. -CA2D 8D0120 01730 STA PPUMASK -CA30 8517 01731 STA PPU_MASK -CA32 A9A8 01732 LDA #$A8 ; Enable NMI, 8x16 sprites, BG=$0000, SPR=$1000, NAME=$2000 -CA34 8516 01733 STA PPU_CTRL -CA36 8D0020 01734 STA PPUCTRL -CA39 01735 -CA39 2088C5 01736 JSR MUSIC_INIT -CA3C 01737 -CA3C 2077C5 01738 JSR MODE_0 -CA3F 01739 -CA3F A900 01740 LDA #$00 -CA41 8520 01741 STA JOY1_DATA -CA43 8521 01742 STA JOY2_DATA -CA45 A90F 01743 LDA #$0F -CA47 8522 01744 STA KEY1_DATA -CA49 8523 01745 STA KEY2_DATA -CA4B 01746 -CA4B 01747 RAM_END: -CA4B 01748 ; rem -CA4B 01749 ; rem Bank-switching example for NES/Famicom -CA4B 01750 ; rem by Oscar Toledo G. http://nanochess.org -CA4B 01751 ; rem Aug/26/2025 -CA4B 01752 ; rem -CA4B 01753 ; -CA4B 01754 ; BANK ROM 256 ' Select a 256KB target ROM size. -CA4B 01755 ; ' Now it is in bank 0. -CA4B 01756 ; -CA4B 01757 ; PLAY FULL -CA4B A905 01758 LDA #5 -CA4D 854E 01759 STA MUSIC_MODE -CA4F 01760 ; BANK SELECT 1 ' Select bank 1 to access. -CA4F A900 01761 LDA #0 -CA51 051C 01762 ORA CHRRAM_BANK -CA53 8D00C0 01763 STA BANKSEL -CA56 01764 ; PLAY tune_1 -CA56 A900 01765 LDA #CVB_TUNE_1 -CA58 A080 01766 LDY #CVB_TUNE_1>>8 -CA5A 20A6C5 01767 JSR MUSIC_PLAY -CA5D 01768 ; -CA5D 01769 ; ' Display image. -CA5D 01770 ; PALETTE 0,$0F -CA5D A900 01771 LDA #0 -CA5F A614 01772 LDX PPU_POINTER -CA61 9D0001 01773 STA PPUBUF,X -CA64 A97F 01774 LDA #$7F -CA66 9D0101 01775 STA PPUBUF+1,X -CA69 A90F 01776 LDA #15 -CA6B A614 01777 LDX PPU_POINTER -CA6D 9D0201 01778 STA PPUBUF+2,X -CA70 E8 01779 INX -CA71 E8 01780 INX -CA72 E8 01781 INX -CA73 8614 01782 STX PPU_POINTER -CA75 01783 ; PALETTE 1,$16 -CA75 A901 01784 LDA #1 -CA77 A614 01785 LDX PPU_POINTER -CA79 9D0001 01786 STA PPUBUF,X -CA7C A97F 01787 LDA #$7F -CA7E 9D0101 01788 STA PPUBUF+1,X -CA81 A916 01789 LDA #22 -CA83 A614 01790 LDX PPU_POINTER -CA85 9D0201 01791 STA PPUBUF+2,X -CA88 E8 01792 INX -CA89 E8 01793 INX -CA8A E8 01794 INX -CA8B 8614 01795 STX PPU_POINTER -CA8D 01796 ; PALETTE 2,$27 -CA8D A902 01797 LDA #2 -CA8F A614 01798 LDX PPU_POINTER -CA91 9D0001 01799 STA PPUBUF,X -CA94 A97F 01800 LDA #$7F -CA96 9D0101 01801 STA PPUBUF+1,X -CA99 A927 01802 LDA #39 -CA9B A614 01803 LDX PPU_POINTER -CA9D 9D0201 01804 STA PPUBUF+2,X -CAA0 E8 01805 INX -CAA1 E8 01806 INX -CAA2 E8 01807 INX -CAA3 8614 01808 STX PPU_POINTER -CAA5 01809 ; PALETTE 3,$38 -CAA5 A903 01810 LDA #3 -CAA7 A614 01811 LDX PPU_POINTER -CAA9 9D0001 01812 STA PPUBUF,X -CAAC A97F 01813 LDA #$7F -CAAE 9D0101 01814 STA PPUBUF+1,X -CAB1 A938 01815 LDA #56 -CAB3 A614 01816 LDX PPU_POINTER -CAB5 9D0201 01817 STA PPUBUF+2,X -CAB8 E8 01818 INX -CAB9 E8 01819 INX -CABA E8 01820 INX -CABB 8614 01821 STX PPU_POINTER -CABD 01822 ; SCREEN DISABLE -CABD 2073C0 01823 JSR DISSCR -CAC0 01824 ; WAIT -CAC0 2063C4 01825 JSR WAIT -CAC3 01826 ; -CAC3 01827 ; BANK SELECT 2 ' Select bank 2 to access. -CAC3 A901 01828 LDA #1 -CAC5 051C 01829 ORA CHRRAM_BANK -CAC7 8D00C0 01830 STA BANKSEL -CACA 01831 ; -CACA 01832 ; SCREEN image_pattern,0,132,12,16,12 -CACA A93A 01833 LDA #CVB_IMAGE_PATTERN -CACC A080 01834 LDY #CVB_IMAGE_PATTERN>>8 -CACE 48 01835 PHA -CACF 98 01836 TYA -CAD0 48 01837 PHA -CAD1 A984 01838 LDA #132 -CAD3 A020 01839 LDY #32 -CAD5 8508 01840 STA POINTER -CAD7 8409 01841 STY POINTER+1 -CAD9 A90C 01842 LDA #12 -CADB 48 01843 PHA -CADC A910 01844 LDA #16 -CADE 48 01845 PHA -CADF A90C 01846 LDA #12 -CAE1 A000 01847 LDY #0 -CAE3 AA 01848 TAX -CAE4 68 01849 PLA -CAE5 8505 01850 STA TEMP2+1 -CAE7 68 01851 PLA -CAE8 8504 01852 STA TEMP2 -CAEA 68 01853 PLA -CAEB 8503 01854 STA TEMP+1 -CAED 68 01855 PLA -CAEE 8502 01856 STA TEMP -CAF0 207AC0 01857 JSR CPYBLK -CAF3 01858 ; WAIT -CAF3 2063C4 01859 JSR WAIT -CAF6 01860 ; SCREEN ENABLE -CAF6 206CC0 01861 JSR ENASCR -CAF9 01862 ; -CAF9 01863 ; GOSUB display_some_text -CAF9 200080 01864 JSR CVB_DISPLAY_SOME_TEXT -CAFC 01865 ; -CAFC 01866 ; WHILE 1: WEND -CAFC 01867 CV1: -CAFC 4CFCCA 01868 JMP CV1 -CAFF 01869 CV2: -CAFF 01870 ; -CAFF 01871 ; BANK 1 ' Start of bank 1 data -CAFF 01872 BANK_0_FREE: EQU $FFFA-$ -CAFF FFFFFFFFFFFFFFFF 01873 TIMES $FFFA-$ DB $FF -FFFA 1F 01874 DB $1F - 01875 FORG $00010 -8000 01876 ORG $8000 -8000 01877 ; -8000 01878 ; ' Bach Invention 8 (BWV779) -8000 01879 ; ' Fragment -8000 01880 ; tune_1: DATA BYTE 7 -8000 01881 CVB_TUNE_1: -8000 07 01882 DB $07 -8001 01883 ; MUSIC F4,- -8001 1E000000 01884 DB $1E,$00,$00,$00 -8005 01885 ; MUSIC S,- -8005 3F000000 01886 DB $3F,$00,$00,$00 -8009 01887 ; MUSIC A4,- -8009 22000000 01888 DB $22,$00,$00,$00 -800D 01889 ; MUSIC S,- -800D 3F000000 01890 DB $3F,$00,$00,$00 -8011 01891 ; MUSIC F4,- -8011 1E000000 01892 DB $1E,$00,$00,$00 -8015 01893 ; MUSIC S,- -8015 3F000000 01894 DB $3F,$00,$00,$00 -8019 01895 ; MUSIC C5,- -8019 25000000 01896 DB $25,$00,$00,$00 -801D 01897 ; MUSIC S,- -801D 3F000000 01898 DB $3F,$00,$00,$00 -8021 01899 ; MUSIC F4,- -8021 1E000000 01900 DB $1E,$00,$00,$00 -8025 01901 ; MUSIC S,- -8025 3F000000 01902 DB $3F,$00,$00,$00 -8029 01903 ; -8029 01904 ; MUSIC F5,- -8029 2A000000 01905 DB $2A,$00,$00,$00 -802D 01906 ; MUSIC S,- -802D 3F000000 01907 DB $3F,$00,$00,$00 -8031 01908 ; MUSIC E5,F3 -8031 29120000 01909 DB $29,$12,$00,$00 -8035 01910 ; MUSIC D5,S -8035 273F0000 01911 DB $27,$3F,$00,$00 -8039 01912 ; MUSIC C5,A3 -8039 25160000 01913 DB $25,$16,$00,$00 -803D 01914 ; MUSIC D5,S -803D 273F0000 01915 DB $27,$3F,$00,$00 -8041 01916 ; MUSIC C5,F3 -8041 25120000 01917 DB $25,$12,$00,$00 -8045 01918 ; MUSIC A4#,S -8045 233F0000 01919 DB $23,$3F,$00,$00 -8049 01920 ; MUSIC A4,C4 -8049 22190000 01921 DB $22,$19,$00,$00 -804D 01922 ; MUSIC A4#,S -804D 233F0000 01923 DB $23,$3F,$00,$00 -8051 01924 ; MUSIC A4,F3 -8051 22120000 01925 DB $22,$12,$00,$00 -8055 01926 ; MUSIC G4,S -8055 203F0000 01927 DB $20,$3F,$00,$00 -8059 01928 ; -8059 01929 ; MUSIC F4,F4 -8059 1E1E0000 01930 DB $1E,$1E,$00,$00 -805D 01931 ; MUSIC S,S -805D 3F3F0000 01932 DB $3F,$3F,$00,$00 -8061 01933 ; MUSIC A4,E4 -8061 221D0000 01934 DB $22,$1D,$00,$00 -8065 01935 ; MUSIC S,D4 -8065 3F1B0000 01936 DB $3F,$1B,$00,$00 -8069 01937 ; MUSIC C5,C4 -8069 25190000 01938 DB $25,$19,$00,$00 -806D 01939 ; MUSIC S,D4 -806D 3F1B0000 01940 DB $3F,$1B,$00,$00 -8071 01941 ; MUSIC A4,C4 -8071 22190000 01942 DB $22,$19,$00,$00 -8075 01943 ; MUSIC S,A3# -8075 3F170000 01944 DB $3F,$17,$00,$00 -8079 01945 ; MUSIC F5,A3 -8079 2A160000 01946 DB $2A,$16,$00,$00 -807D 01947 ; MUSIC S,A3# -807D 3F170000 01948 DB $3F,$17,$00,$00 -8081 01949 ; MUSIC C5,A3 -8081 25160000 01950 DB $25,$16,$00,$00 -8085 01951 ; MUSIC S,G3 -8085 3F140000 01952 DB $3F,$14,$00,$00 -8089 01953 ; -8089 01954 ; MUSIC A5,F3 -8089 2E120000 01955 DB $2E,$12,$00,$00 -808D 01956 ; MUSIC C6,S -808D 313F0000 01957 DB $31,$3F,$00,$00 -8091 01958 ; MUSIC A5#,A3 -8091 2F160000 01959 DB $2F,$16,$00,$00 -8095 01960 ; MUSIC C6,S -8095 313F0000 01961 DB $31,$3F,$00,$00 -8099 01962 ; MUSIC A5,C4 -8099 2E190000 01963 DB $2E,$19,$00,$00 -809D 01964 ; MUSIC C6,S -809D 313F0000 01965 DB $31,$3F,$00,$00 -80A1 01966 ; MUSIC A5#,A3 -80A1 2F160000 01967 DB $2F,$16,$00,$00 -80A5 01968 ; MUSIC C6,S -80A5 313F0000 01969 DB $31,$3F,$00,$00 -80A9 01970 ; MUSIC A5,F4 -80A9 2E1E0000 01971 DB $2E,$1E,$00,$00 -80AD 01972 ; MUSIC C6,S -80AD 313F0000 01973 DB $31,$3F,$00,$00 -80B1 01974 ; MUSIC A5#,C4 -80B1 2F190000 01975 DB $2F,$19,$00,$00 -80B5 01976 ; MUSIC C6,S -80B5 313F0000 01977 DB $31,$3F,$00,$00 -80B9 01978 ; -80B9 01979 ; MUSIC F5,A3 -80B9 2A160000 01980 DB $2A,$16,$00,$00 -80BD 01981 ; MUSIC A5,C4 -80BD 2E190000 01982 DB $2E,$19,$00,$00 -80C1 01983 ; MUSIC G5,A3# -80C1 2C170000 01984 DB $2C,$17,$00,$00 -80C5 01985 ; MUSIC A5,C4 -80C5 2E190000 01986 DB $2E,$19,$00,$00 -80C9 01987 ; MUSIC F5,A3 -80C9 2A160000 01988 DB $2A,$16,$00,$00 -80CD 01989 ; MUSIC A5,C4 -80CD 2E190000 01990 DB $2E,$19,$00,$00 -80D1 01991 ; MUSIC G5,A3# -80D1 2C170000 01992 DB $2C,$17,$00,$00 -80D5 01993 ; MUSIC A5,C4 -80D5 2E190000 01994 DB $2E,$19,$00,$00 -80D9 01995 ; MUSIC F5,A3 -80D9 2A160000 01996 DB $2A,$16,$00,$00 -80DD 01997 ; MUSIC A5,C4 -80DD 2E190000 01998 DB $2E,$19,$00,$00 -80E1 01999 ; MUSIC G5,A3# -80E1 2C170000 02000 DB $2C,$17,$00,$00 -80E5 02001 ; MUSIC A5,C4 -80E5 2E190000 02002 DB $2E,$19,$00,$00 -80E9 02003 ; -80E9 02004 ; MUSIC D5,F3 -80E9 27120000 02005 DB $27,$12,$00,$00 -80ED 02006 ; MUSIC F5,A3 -80ED 2A160000 02007 DB $2A,$16,$00,$00 -80F1 02008 ; MUSIC E5,G3 -80F1 29140000 02009 DB $29,$14,$00,$00 -80F5 02010 ; MUSIC F5,A3 -80F5 2A160000 02011 DB $2A,$16,$00,$00 -80F9 02012 ; MUSIC D5,F3 -80F9 27120000 02013 DB $27,$12,$00,$00 -80FD 02014 ; MUSIC F5,A3 -80FD 2A160000 02015 DB $2A,$16,$00,$00 -8101 02016 ; MUSIC E5,G3 -8101 29140000 02017 DB $29,$14,$00,$00 -8105 02018 ; MUSIC F5,A3 -8105 2A160000 02019 DB $2A,$16,$00,$00 -8109 02020 ; MUSIC D5,F3 -8109 27120000 02021 DB $27,$12,$00,$00 -810D 02022 ; MUSIC F5,A3 -810D 2A160000 02023 DB $2A,$16,$00,$00 -8111 02024 ; MUSIC E5,G3 -8111 29140000 02025 DB $29,$14,$00,$00 -8115 02026 ; MUSIC F5,A3 -8115 2A160000 02027 DB $2A,$16,$00,$00 -8119 02028 ; -8119 02029 ; MUSIC B4,D3 -8119 240F0000 02030 DB $24,$0F,$00,$00 -811D 02031 ; MUSIC S,F3 -811D 3F120000 02032 DB $3F,$12,$00,$00 -8121 02033 ; MUSIC G4,E3 -8121 20110000 02034 DB $20,$11,$00,$00 -8125 02035 ; MUSIC S,F3 -8125 3F120000 02036 DB $3F,$12,$00,$00 -8129 02037 ; MUSIC D5,D3 -8129 270F0000 02038 DB $27,$0F,$00,$00 -812D 02039 ; MUSIC S,F3 -812D 3F120000 02040 DB $3F,$12,$00,$00 -8131 02041 ; MUSIC B4,E3 -8131 24110000 02042 DB $24,$11,$00,$00 -8135 02043 ; MUSIC S,F3 -8135 3F120000 02044 DB $3F,$12,$00,$00 -8139 02045 ; MUSIC F5,D3 -8139 2A0F0000 02046 DB $2A,$0F,$00,$00 -813D 02047 ; MUSIC S,F3 -813D 3F120000 02048 DB $3F,$12,$00,$00 -8141 02049 ; MUSIC D5,E3 -8141 27110000 02050 DB $27,$11,$00,$00 -8145 02051 ; MUSIC S,F3 -8145 3F120000 02052 DB $3F,$12,$00,$00 -8149 02053 ; -8149 02054 ; MUSIC G5,B3 -8149 2C180000 02055 DB $2C,$18,$00,$00 -814D 02056 ; MUSIC A5,S -814D 2E3F0000 02057 DB $2E,$3F,$00,$00 -8151 02058 ; MUSIC G5,G3 -8151 2C140000 02059 DB $2C,$14,$00,$00 -8155 02060 ; MUSIC F5,S -8155 2A3F0000 02061 DB $2A,$3F,$00,$00 -8159 02062 ; MUSIC E5,C4 -8159 29190000 02063 DB $29,$19,$00,$00 -815D 02064 ; MUSIC F5,S -815D 2A3F0000 02065 DB $2A,$3F,$00,$00 -8161 02066 ; MUSIC E5,G3 -8161 29140000 02067 DB $29,$14,$00,$00 -8165 02068 ; MUSIC D5,S -8165 273F0000 02069 DB $27,$3F,$00,$00 -8169 02070 ; MUSIC C5,E4 -8169 251D0000 02071 DB $25,$1D,$00,$00 -816D 02072 ; MUSIC D5,S -816D 273F0000 02073 DB $27,$3F,$00,$00 -8171 02074 ; MUSIC C5,C4 -8171 25190000 02075 DB $25,$19,$00,$00 -8175 02076 ; MUSIC A4#,S -8175 233F0000 02077 DB $23,$3F,$00,$00 -8179 02078 ; -8179 02079 ; MUSIC A4,F4 -8179 221E0000 02080 DB $22,$1E,$00,$00 -817D 02081 ; MUSIC S,G4 -817D 3F200000 02082 DB $3F,$20,$00,$00 -8181 02083 ; MUSIC D5,F4 -8181 271E0000 02084 DB $27,$1E,$00,$00 -8185 02085 ; MUSIC C5,E4 -8185 251D0000 02086 DB $25,$1D,$00,$00 -8189 02087 ; MUSIC B4,D4 -8189 241B0000 02088 DB $24,$1B,$00,$00 -818D 02089 ; MUSIC C5,E4 -818D 251D0000 02090 DB $25,$1D,$00,$00 -8191 02091 ; MUSIC B4,D4 -8191 241B0000 02092 DB $24,$1B,$00,$00 -8195 02093 ; MUSIC A4,C4 -8195 22190000 02094 DB $22,$19,$00,$00 -8199 02095 ; MUSIC G4,B3 -8199 20180000 02096 DB $20,$18,$00,$00 -819D 02097 ; MUSIC A4,C4 -819D 22190000 02098 DB $22,$19,$00,$00 -81A1 02099 ; MUSIC G4,B3 -81A1 20180000 02100 DB $20,$18,$00,$00 -81A5 02101 ; MUSIC F4,A3 -81A5 1E160000 02102 DB $1E,$16,$00,$00 -81A9 02103 ; -81A9 02104 ; MUSIC E4,G3 -81A9 1D140000 02105 DB $1D,$14,$00,$00 -81AD 02106 ; MUSIC F4,S -81AD 1E3F0000 02107 DB $1E,$3F,$00,$00 -81B1 02108 ; MUSIC E4,C4 -81B1 1D190000 02109 DB $1D,$19,$00,$00 -81B5 02110 ; MUSIC D4,B3 -81B5 1B180000 02111 DB $1B,$18,$00,$00 -81B9 02112 ; MUSIC C4,A3 -81B9 19160000 02113 DB $19,$16,$00,$00 -81BD 02114 ; MUSIC S,B3 -81BD 3F180000 02115 DB $3F,$18,$00,$00 -81C1 02116 ; MUSIC C5,A3 -81C1 25160000 02117 DB $25,$16,$00,$00 -81C5 02118 ; MUSIC B4,G3 -81C5 24140000 02119 DB $24,$14,$00,$00 -81C9 02120 ; MUSIC C5,F3 -81C9 25120000 02121 DB $25,$12,$00,$00 -81CD 02122 ; MUSIC S,G3 -81CD 3F140000 02123 DB $3F,$14,$00,$00 -81D1 02124 ; MUSIC E4,F3 -81D1 1D120000 02125 DB $1D,$12,$00,$00 -81D5 02126 ; MUSIC S,E3 -81D5 3F110000 02127 DB $3F,$11,$00,$00 -81D9 02128 ; -81D9 02129 ; MUSIC F4,D3 -81D9 1E0F0000 02130 DB $1E,$0F,$00,$00 -81DD 02131 ; MUSIC S,E3 -81DD 3F110000 02132 DB $3F,$11,$00,$00 -81E1 02133 ; MUSIC C5,D3 -81E1 250F0000 02134 DB $25,$0F,$00,$00 -81E5 02135 ; MUSIC S,C3 -81E5 3F0D0000 02136 DB $3F,$0D,$00,$00 -81E9 02137 ; MUSIC E4,G3 -81E9 1D140000 02138 DB $1D,$14,$00,$00 -81ED 02139 ; MUSIC S,F3 -81ED 3F120000 02140 DB $3F,$12,$00,$00 -81F1 02141 ; MUSIC C5,E3 -81F1 25110000 02142 DB $25,$11,$00,$00 -81F5 02143 ; MUSIC S,F3 -81F5 3F120000 02144 DB $3F,$12,$00,$00 -81F9 02145 ; MUSIC D4,G3 -81F9 1B140000 02146 DB $1B,$14,$00,$00 -81FD 02147 ; MUSIC S,S -81FD 3F3F0000 02148 DB $3F,$3F,$00,$00 -8201 02149 ; MUSIC B4,G2 -8201 24080000 02150 DB $24,$08,$00,$00 -8205 02151 ; MUSIC S,S -8205 3F3F0000 02152 DB $3F,$3F,$00,$00 -8209 02153 ; -8209 02154 ; MUSIC C5,C4 -8209 25190000 02155 DB $25,$19,$00,$00 -820D 02156 ; MUSIC S,S -820D 3F3F0000 02157 DB $3F,$3F,$00,$00 -8211 02158 ; MUSIC S,S -8211 3F3F0000 02159 DB $3F,$3F,$00,$00 -8215 02160 ; MUSIC S,S -8215 3F3F0000 02161 DB $3F,$3F,$00,$00 -8219 02162 ; MUSIC STOP -8219 FE000000 02163 DB $FE,$00,$00,$00 -821D 02164 ; -821D 02165 ; BANK 2 -821D 02166 BANK_1_FREE: EQU $BFFF-$ -821D FFFFFFFFFFFFFFFF 02167 TIMES $BFFF-$ DB $FF -BFFF 00 02168 DB $00 - 02169 FORG $04010 -8000 02170 ORG $8000 -8000 02171 ; -8000 02172 ; display_some_text: PROCEDURE -8000 02173 CVB_DISPLAY_SOME_TEXT: -8000 02174 ; -8000 02175 ; PRINT AT $01d1,"Hi!" -8000 206AC4 02176 JSR PRINT_STRING_CURSOR_CONSTANT -8003 D10103 02177 DB $D1,$01,$03 -8006 486921 02178 DB $48,$69,$21 -8009 02179 ; -8009 02180 ; PRINT AT $0211,"This is bank-" -8009 206AC4 02181 JSR PRINT_STRING_CURSOR_CONSTANT -800C 11020D 02182 DB $11,$02,$0D -800F 5468697320697320 02183 DB $54,$68,$69,$73,$20,$69,$73,$20 -8017 62616E6B2D 02184 DB $62,$61,$6E,$6B,$2D -801C 02185 ; -801C 02186 ; PRINT AT $0231,"switching demo." -801C 206AC4 02187 JSR PRINT_STRING_CURSOR_CONSTANT -801F 31020F 02188 DB $31,$02,$0F -8022 737769746368696E 02189 DB $73,$77,$69,$74,$63,$68,$69,$6E -802A 672064656D6F2E 02190 DB $67,$20,$64,$65,$6D,$6F,$2E -8031 02191 ; -8031 02192 ; PRINT AT $0271,":)" -8031 206AC4 02193 JSR PRINT_STRING_CURSOR_CONSTANT -8034 710202 02194 DB $71,$02,$02 -8037 3A29 02195 DB $3A,$29 -8039 02196 ; -8039 02197 ; END -8039 60 02198 RTS -803A 02199 ; -803A 02200 ; ' CHRROM is technically outside of the ROM, but for -803A 02201 ; ' the purposes of UNROM 512 bank-switching it is saved -803A 02202 ; ' in reserved banks and copied to CHRRAM on boot. -803A 02203 ; -803A 02204 ; ' TMSColor 3.2 Aug/26/2025 -803A 02205 ; ' Command: ./tmscolor -nes -p1 -t128 -b yo.png yo.bas -803A 02206 ; ' Created: Tue Aug 26 10:07:21 2025 -803A 02207 ; -803A 02208 ; ' Start tile = 128. Total_tiles = 118 -803A 02209 ; CHRROM 0 PATTERN 128 -803A 02210 ; BITMAP "11112222" -803A 02211 ; BITMAP "11112222" -803A 02212 ; BITMAP "11112222" -803A 02213 ; BITMAP "12222222" -803A 02214 ; BITMAP "22222222" -803A 02215 ; BITMAP "22222222" -803A 02216 ; BITMAP "22222222" -803A 02217 ; BITMAP "22222222" -803A 02218 ; -803A 02219 ; BITMAP "22222222" -803A 02220 ; BITMAP "22222222" -803A 02221 ; BITMAP "22222222" -803A 02222 ; BITMAP "22222222" -803A 02223 ; BITMAP "22222222" -803A 02224 ; BITMAP "22222222" -803A 02225 ; BITMAP "22222222" -803A 02226 ; BITMAP "22222222" -803A 02227 ; -803A 02228 ; BITMAP "22222222" -803A 02229 ; BITMAP "22222222" -803A 02230 ; BITMAP "22222222" -803A 02231 ; BITMAP "22222222" -803A 02232 ; BITMAP "22222222" -803A 02233 ; BITMAP "22222233" -803A 02234 ; BITMAP "22223333" -803A 02235 ; BITMAP "22333333" -803A 02236 ; -803A 02237 ; BITMAP "22222223" -803A 02238 ; BITMAP "22222333" -803A 02239 ; BITMAP "23223333" -803A 02240 ; BITMAP "23333333" -803A 02241 ; BITMAP "33333333" -803A 02242 ; BITMAP "33333333" -803A 02243 ; BITMAP "33333333" -803A 02244 ; BITMAP "33333333" -803A 02245 ; -803A 02246 ; BITMAP "33333333" -803A 02247 ; BITMAP "33333333" -803A 02248 ; BITMAP "33333333" -803A 02249 ; BITMAP "33333333" -803A 02250 ; BITMAP "33333333" -803A 02251 ; BITMAP "33333333" -803A 02252 ; BITMAP "33333333" -803A 02253 ; BITMAP "33333333" -803A 02254 ; -803A 02255 ; BITMAP "22222222" -803A 02256 ; BITMAP "22222222" -803A 02257 ; BITMAP "22222223" -803A 02258 ; BITMAP "22222233" -803A 02259 ; BITMAP "22222333" -803A 02260 ; BITMAP "22223333" -803A 02261 ; BITMAP "22233333" -803A 02262 ; BITMAP "22333333" -803A 02263 ; -803A 02264 ; BITMAP "23333333" -803A 02265 ; BITMAP "33333333" -803A 02266 ; BITMAP "33333333" -803A 02267 ; BITMAP "33333333" -803A 02268 ; BITMAP "33333333" -803A 02269 ; BITMAP "33333333" -803A 02270 ; BITMAP "33333333" -803A 02271 ; BITMAP "33333333" -803A 02272 ; -803A 02273 ; BITMAP "22222222" -803A 02274 ; BITMAP "22222222" -803A 02275 ; BITMAP "22222222" -803A 02276 ; BITMAP "22222222" -803A 02277 ; BITMAP "22222233" -803A 02278 ; BITMAP "22222233" -803A 02279 ; BITMAP "22222333" -803A 02280 ; BITMAP "22223333" -803A 02281 ; -803A 02282 ; BITMAP "22333333" -803A 02283 ; BITMAP "23333333" -803A 02284 ; BITMAP "33333333" -803A 02285 ; BITMAP "33333333" -803A 02286 ; BITMAP "33333333" -803A 02287 ; BITMAP "33333333" -803A 02288 ; BITMAP "33333333" -803A 02289 ; BITMAP "33333333" -803A 02290 ; -803A 02291 ; BITMAP "22223333" -803A 02292 ; BITMAP "22233333" -803A 02293 ; BITMAP "22233333" -803A 02294 ; BITMAP "22333333" -803A 02295 ; BITMAP "23333333" -803A 02296 ; BITMAP "33333333" -803A 02297 ; BITMAP "33333333" -803A 02298 ; BITMAP "33333333" -803A 02299 ; -803A 02300 ; BITMAP "33333333" -803A 02301 ; BITMAP "33333333" -803A 02302 ; BITMAP "33333333" -803A 02303 ; BITMAP "33333333" -803A 02304 ; BITMAP "33333322" -803A 02305 ; BITMAP "33332222" -803A 02306 ; BITMAP "33322211" -803A 02307 ; BITMAP "33222111" -803A 02308 ; -803A 02309 ; BITMAP "33333333" -803A 02310 ; BITMAP "33333333" -803A 02311 ; BITMAP "33333333" -803A 02312 ; BITMAP "33323333" -803A 02313 ; BITMAP "22222222" -803A 02314 ; BITMAP "11111111" -803A 02315 ; BITMAP "11100111" -803A 02316 ; BITMAP "11111111" -803A 02317 ; -803A 02318 ; BITMAP "33333333" -803A 02319 ; BITMAP "33333333" -803A 02320 ; BITMAP "33333333" -803A 02321 ; BITMAP "33333333" -803A 02322 ; BITMAP "33333333" -803A 02323 ; BITMAP "22333333" -803A 02324 ; BITMAP "11112333" -803A 02325 ; BITMAP "11111223" -803A 02326 ; -803A 02327 ; BITMAP "22222222" -803A 02328 ; BITMAP "22222223" -803A 02329 ; BITMAP "22222233" -803A 02330 ; BITMAP "22222233" -803A 02331 ; BITMAP "22222333" -803A 02332 ; BITMAP "22223333" -803A 02333 ; BITMAP "22223333" -803A 02334 ; BITMAP "22233333" -803A 02335 ; -803A 02336 ; BITMAP "33333333" -803A 02337 ; BITMAP "33333333" -803A 02338 ; BITMAP "33333333" -803A 02339 ; BITMAP "33333333" -803A 02340 ; BITMAP "33333332" -803A 02341 ; BITMAP "33333332" -803A 02342 ; BITMAP "33333322" -803A 02343 ; BITMAP "33333322" -803A 02344 ; -803A 02345 ; BITMAP "33221111" -803A 02346 ; BITMAP "32211111" -803A 02347 ; BITMAP "22211111" -803A 02348 ; BITMAP "22111111" -803A 02349 ; BITMAP "21111111" -803A 02350 ; BITMAP "21111112" -803A 02351 ; BITMAP "11112222" -803A 02352 ; BITMAP "11122222" -803A 02353 ; -803A 02354 ; BITMAP "11111111" -803A 02355 ; BITMAP "11111111" -803A 02356 ; BITMAP "11111111" -803A 02357 ; BITMAP "11111111" -803A 02358 ; BITMAP "11111111" -803A 02359 ; BITMAP "22222221" -803A 02360 ; BITMAP "22222222" -803A 02361 ; BITMAP "22222222" -803A 02362 ; -803A 02363 ; BITMAP "11111112" -803A 02364 ; BITMAP "11111111" -803A 02365 ; BITMAP "11111111" -803A 02366 ; BITMAP "11111111" -803A 02367 ; BITMAP "11111111" -803A 02368 ; BITMAP "11111111" -803A 02369 ; BITMAP "22111111" -803A 02370 ; BITMAP "22221111" -803A 02371 ; -803A 02372 ; BITMAP "22333333" -803A 02373 ; BITMAP "11122333" -803A 02374 ; BITMAP "11000233" -803A 02375 ; BITMAP "11100023" -803A 02376 ; BITMAP "11100001" -803A 02377 ; BITMAP "11100000" -803A 02378 ; BITMAP "11100000" -803A 02379 ; BITMAP "11110000" -803A 02380 ; -803A 02381 ; BITMAP "33333333" -803A 02382 ; BITMAP "33333333" -803A 02383 ; BITMAP "33333333" -803A 02384 ; BITMAP "33333333" -803A 02385 ; BITMAP "33333333" -803A 02386 ; BITMAP "13333333" -803A 02387 ; BITMAP "01333333" -803A 02388 ; BITMAP "00233333" -803A 02389 ; -803A 02390 ; BITMAP "22233333" -803A 02391 ; BITMAP "22333333" -803A 02392 ; BITMAP "22333333" -803A 02393 ; BITMAP "22333333" -803A 02394 ; BITMAP "23333333" -803A 02395 ; BITMAP "23333333" -803A 02396 ; BITMAP "33333333" -803A 02397 ; BITMAP "33333333" -803A 02398 ; -803A 02399 ; BITMAP "33333321" -803A 02400 ; BITMAP "33333321" -803A 02401 ; BITMAP "33333321" -803A 02402 ; BITMAP "33333212" -803A 02403 ; BITMAP "33333212" -803A 02404 ; BITMAP "33333222" -803A 02405 ; BITMAP "33333222" -803A 02406 ; BITMAP "33333222" -803A 02407 ; -803A 02408 ; BITMAP "11222222" -803A 02409 ; BITMAP "12222222" -803A 02410 ; BITMAP "22222222" -803A 02411 ; BITMAP "22222222" -803A 02412 ; BITMAP "22222222" -803A 02413 ; BITMAP "22222222" -803A 02414 ; BITMAP "22222222" -803A 02415 ; BITMAP "22222222" -803A 02416 ; -803A 02417 ; BITMAP "22221111" -803A 02418 ; BITMAP "22222111" -803A 02419 ; BITMAP "22222111" -803A 02420 ; BITMAP "22222211" -803A 02421 ; BITMAP "22222221" -803A 02422 ; BITMAP "22222221" -803A 02423 ; BITMAP "22222221" -803A 02424 ; BITMAP "22222221" -803A 02425 ; -803A 02426 ; BITMAP "11110000" -803A 02427 ; BITMAP "11110000" -803A 02428 ; BITMAP "11111000" -803A 02429 ; BITMAP "11111000" -803A 02430 ; BITMAP "11111000" -803A 02431 ; BITMAP "11111000" -803A 02432 ; BITMAP "11111000" -803A 02433 ; BITMAP "11111100" -803A 02434 ; -803A 02435 ; BITMAP "00033333" -803A 02436 ; BITMAP "00023333" -803A 02437 ; BITMAP "00003333" -803A 02438 ; BITMAP "00002333" -803A 02439 ; BITMAP "00002333" -803A 02440 ; BITMAP "00001333" -803A 02441 ; BITMAP "00000333" -803A 02442 ; BITMAP "00000233" -803A 02443 ; -803A 02444 ; BITMAP "22222222" -803A 02445 ; BITMAP "22222223" -803A 02446 ; BITMAP "22222223" -803A 02447 ; BITMAP "22222233" -803A 02448 ; BITMAP "22222233" -803A 02449 ; BITMAP "22222233" -803A 02450 ; BITMAP "22222333" -803A 02451 ; BITMAP "22222333" -803A 02452 ; -803A 02453 ; BITMAP "33332122" -803A 02454 ; BITMAP "33332122" -803A 02455 ; BITMAP "33332122" -803A 02456 ; BITMAP "33332222" -803A 02457 ; BITMAP "33333122" -803A 02458 ; BITMAP "33333122" -803A 02459 ; BITMAP "33332111" -803A 02460 ; BITMAP "33332111" -803A 02461 ; -803A 02462 ; BITMAP "22222222" -803A 02463 ; BITMAP "22222222" -803A 02464 ; BITMAP "22222222" -803A 02465 ; BITMAP "22222232" -803A 02466 ; BITMAP "22232233" -803A 02467 ; BITMAP "22222222" -803A 02468 ; BITMAP "11122222" -803A 02469 ; BITMAP "11112222" -803A 02470 ; -803A 02471 ; BITMAP "22222222" -803A 02472 ; BITMAP "22222222" -803A 02473 ; BITMAP "22222222" -803A 02474 ; BITMAP "22233333" -803A 02475 ; BITMAP "22233222" -803A 02476 ; BITMAP "22222111" -803A 02477 ; BITMAP "22221110" -803A 02478 ; BITMAP "22221112" -803A 02479 ; -803A 02480 ; BITMAP "22222221" -803A 02481 ; BITMAP "22222211" -803A 02482 ; BITMAP "22222211" -803A 02483 ; BITMAP "32222111" -803A 02484 ; BITMAP "22221111" -803A 02485 ; BITMAP "01111111" -803A 02486 ; BITMAP "11222211" -803A 02487 ; BITMAP "33333222" -803A 02488 ; -803A 02489 ; BITMAP "11111100" -803A 02490 ; BITMAP "11111110" -803A 02491 ; BITMAP "11111110" -803A 02492 ; BITMAP "11111110" -803A 02493 ; BITMAP "11111110" -803A 02494 ; BITMAP "11111110" -803A 02495 ; BITMAP "11110000" -803A 02496 ; BITMAP "11110001" -803A 02497 ; -803A 02498 ; BITMAP "00000233" -803A 02499 ; BITMAP "00000232" -803A 02500 ; BITMAP "00000132" -803A 02501 ; BITMAP "00000122" -803A 02502 ; BITMAP "01110122" -803A 02503 ; BITMAP "11000112" -803A 02504 ; BITMAP "00001111" -803A 02505 ; BITMAP "00001122" -803A 02506 ; -803A 02507 ; BITMAP "33333333" -803A 02508 ; BITMAP "22233333" -803A 02509 ; BITMAP "22222233" -803A 02510 ; BITMAP "22222223" -803A 02511 ; BITMAP "22222222" -803A 02512 ; BITMAP "22222222" -803A 02513 ; BITMAP "22222222" -803A 02514 ; BITMAP "22222222" -803A 02515 ; -803A 02516 ; BITMAP "33333333" -803A 02517 ; BITMAP "33333333" -803A 02518 ; BITMAP "33333333" -803A 02519 ; BITMAP "33333333" -803A 02520 ; BITMAP "33333333" -803A 02521 ; BITMAP "33333333" -803A 02522 ; BITMAP "23333333" -803A 02523 ; BITMAP "23333333" -803A 02524 ; -803A 02525 ; BITMAP "22222333" -803A 02526 ; BITMAP "22222333" -803A 02527 ; BITMAP "22222333" -803A 02528 ; BITMAP "22222333" -803A 02529 ; BITMAP "22222333" -803A 02530 ; BITMAP "22222333" -803A 02531 ; BITMAP "22222333" -803A 02532 ; BITMAP "22223333" -803A 02533 ; -803A 02534 ; BITMAP "33332111" -803A 02535 ; BITMAP "33222122" -803A 02536 ; BITMAP "32321222" -803A 02537 ; BITMAP "32101211" -803A 02538 ; BITMAP "10233110" -803A 02539 ; BITMAP "12333111" -803A 02540 ; BITMAP "33333112" -803A 02541 ; BITMAP "33233122" -803A 02542 ; -803A 02543 ; BITMAP "11111122" -803A 02544 ; BITMAP "22222112" -803A 02545 ; BITMAP "22212111" -803A 02546 ; BITMAP "11110111" -803A 02547 ; BITMAP "22000111" -803A 02548 ; BITMAP "22111101" -803A 02549 ; BITMAP "22222211" -803A 02550 ; BITMAP "22222212" -803A 02551 ; -803A 02552 ; BITMAP "22211222" -803A 02553 ; BITMAP "22211221" -803A 02554 ; BITMAP "22111211" -803A 02555 ; BITMAP "22111121" -803A 02556 ; BITMAP "22111122" -803A 02557 ; BITMAP "22111122" -803A 02558 ; BITMAP "22211122" -803A 02559 ; BITMAP "22211122" -803A 02560 ; -803A 02561 ; BITMAP "33332112" -803A 02562 ; BITMAP "12231001" -803A 02563 ; BITMAP "23110110" -803A 02564 ; BITMAP "22211221" -803A 02565 ; BITMAP "21222222" -803A 02566 ; BITMAP "22222222" -803A 02567 ; BITMAP "22222222" -803A 02568 ; BITMAP "22222222" -803A 02569 ; -803A 02570 ; BITMAP "20011111" -803A 02571 ; BITMAP "11111111" -803A 02572 ; BITMAP "11222111" -803A 02573 ; BITMAP "11222111" -803A 02574 ; BITMAP "21222211" -803A 02575 ; BITMAP "21222211" -803A 02576 ; BITMAP "21222211" -803A 02577 ; BITMAP "12222111" -803A 02578 ; -803A 02579 ; BITMAP "10000222" -803A 02580 ; BITMAP "10001221" -803A 02581 ; BITMAP "10000221" -803A 02582 ; BITMAP "10001121" -803A 02583 ; BITMAP "11001121" -803A 02584 ; BITMAP "11111121" -803A 02585 ; BITMAP "11111121" -803A 02586 ; BITMAP "11101111" -803A 02587 ; -803A 02588 ; BITMAP "23333333" -803A 02589 ; BITMAP "23333333" -803A 02590 ; BITMAP "22333333" -803A 02591 ; BITMAP "22333333" -803A 02592 ; BITMAP "22333333" -803A 02593 ; BITMAP "22233333" -803A 02594 ; BITMAP "22233333" -803A 02595 ; BITMAP "22223333" -803A 02596 ; -803A 02597 ; BITMAP "22223333" -803A 02598 ; BITMAP "22223333" -803A 02599 ; BITMAP "22222333" -803A 02600 ; BITMAP "22223333" -803A 02601 ; BITMAP "22223333" -803A 02602 ; BITMAP "22222333" -803A 02603 ; BITMAP "22222333" -803A 02604 ; BITMAP "22223333" -803A 02605 ; -803A 02606 ; BITMAP "33232122" -803A 02607 ; BITMAP "33322122" -803A 02608 ; BITMAP "33332122" -803A 02609 ; BITMAP "33333211" -803A 02610 ; BITMAP "33333222" -803A 02611 ; BITMAP "33333322" -803A 02612 ; BITMAP "33333322" -803A 02613 ; BITMAP "33333322" -803A 02614 ; -803A 02615 ; BITMAP "22222112" -803A 02616 ; BITMAP "22222122" -803A 02617 ; BITMAP "22221122" -803A 02618 ; BITMAP "12122222" -803A 02619 ; BITMAP "22222222" -803A 02620 ; BITMAP "22222222" -803A 02621 ; BITMAP "22222222" -803A 02622 ; BITMAP "22222222" -803A 02623 ; -803A 02624 ; BITMAP "22221112" -803A 02625 ; BITMAP "22211111" -803A 02626 ; BITMAP "22211112" -803A 02627 ; BITMAP "22211111" -803A 02628 ; BITMAP "22211111" -803A 02629 ; BITMAP "22221211" -803A 02630 ; BITMAP "32222221" -803A 02631 ; BITMAP "22111111" -803A 02632 ; -803A 02633 ; BITMAP "22222222" -803A 02634 ; BITMAP "22222222" -803A 02635 ; BITMAP "22222232" -803A 02636 ; BITMAP "22223332" -803A 02637 ; BITMAP "12222332" -803A 02638 ; BITMAP "12222222" -803A 02639 ; BITMAP "12222222" -803A 02640 ; BITMAP "22222222" -803A 02641 ; -803A 02642 ; BITMAP "12222111" -803A 02643 ; BITMAP "22222111" -803A 02644 ; BITMAP "22222111" -803A 02645 ; BITMAP "22222111" -803A 02646 ; BITMAP "22222111" -803A 02647 ; BITMAP "22222111" -803A 02648 ; BITMAP "22221111" -803A 02649 ; BITMAP "22221111" -803A 02650 ; -803A 02651 ; BITMAP "11101211" -803A 02652 ; BITMAP "11112222" -803A 02653 ; BITMAP "11111112" -803A 02654 ; BITMAP "11111222" -803A 02655 ; BITMAP "11112222" -803A 02656 ; BITMAP "11112222" -803A 02657 ; BITMAP "11112222" -803A 02658 ; BITMAP "11112222" -803A 02659 ; -803A 02660 ; BITMAP "22223333" -803A 02661 ; BITMAP "22222333" -803A 02662 ; BITMAP "22222333" -803A 02663 ; BITMAP "22222233" -803A 02664 ; BITMAP "22222233" -803A 02665 ; BITMAP "22222223" -803A 02666 ; BITMAP "22222222" -803A 02667 ; BITMAP "22222222" -803A 02668 ; -803A 02669 ; BITMAP "33333333" -803A 02670 ; BITMAP "33333333" -803A 02671 ; BITMAP "33333333" -803A 02672 ; BITMAP "33333333" -803A 02673 ; BITMAP "33333333" -803A 02674 ; BITMAP "33333333" -803A 02675 ; BITMAP "33333333" -803A 02676 ; BITMAP "22333333" -803A 02677 ; -803A 02678 ; BITMAP "22223333" -803A 02679 ; BITMAP "22222333" -803A 02680 ; BITMAP "22222333" -803A 02681 ; BITMAP "22222333" -803A 02682 ; BITMAP "22222333" -803A 02683 ; BITMAP "22222233" -803A 02684 ; BITMAP "22222333" -803A 02685 ; BITMAP "22222333" -803A 02686 ; -803A 02687 ; BITMAP "33333332" -803A 02688 ; BITMAP "33333333" -803A 02689 ; BITMAP "33333333" -803A 02690 ; BITMAP "33333333" -803A 02691 ; BITMAP "33333333" -803A 02692 ; BITMAP "33333333" -803A 02693 ; BITMAP "33333333" -803A 02694 ; BITMAP "33333333" -803A 02695 ; -803A 02696 ; BITMAP "22222222" -803A 02697 ; BITMAP "22222212" -803A 02698 ; BITMAP "22222222" -803A 02699 ; BITMAP "22222222" -803A 02700 ; BITMAP "32222222" -803A 02701 ; BITMAP "32222111" -803A 02702 ; BITMAP "33222211" -803A 02703 ; BITMAP "33222222" -803A 02704 ; -803A 02705 ; BITMAP "22112222" -803A 02706 ; BITMAP "22222222" -803A 02707 ; BITMAP "22222222" -803A 02708 ; BITMAP "22222222" -803A 02709 ; BITMAP "22222211" -803A 02710 ; BITMAP "11111111" -803A 02711 ; BITMAP "11111111" -803A 02712 ; BITMAP "11222222" -803A 02713 ; -803A 02714 ; BITMAP "22222222" -803A 02715 ; BITMAP "22222222" -803A 02716 ; BITMAP "22222222" -803A 02717 ; BITMAP "22111222" -803A 02718 ; BITMAP "11112222" -803A 02719 ; BITMAP "11222222" -803A 02720 ; BITMAP "22222222" -803A 02721 ; BITMAP "22222222" -803A 02722 ; -803A 02723 ; BITMAP "22221211" -803A 02724 ; BITMAP "22222211" -803A 02725 ; BITMAP "22222211" -803A 02726 ; BITMAP "22222211" -803A 02727 ; BITMAP "22222211" -803A 02728 ; BITMAP "22222211" -803A 02729 ; BITMAP "22222211" -803A 02730 ; BITMAP "22222111" -803A 02731 ; -803A 02732 ; BITMAP "11112222" -803A 02733 ; BITMAP "11112222" -803A 02734 ; BITMAP "11112222" -803A 02735 ; BITMAP "11112222" -803A 02736 ; BITMAP "11112222" -803A 02737 ; BITMAP "11112222" -803A 02738 ; BITMAP "11112222" -803A 02739 ; BITMAP "11101222" -803A 02740 ; -803A 02741 ; BITMAP "22233333" -803A 02742 ; BITMAP "22223333" -803A 02743 ; BITMAP "22222233" -803A 02744 ; BITMAP "22222222" -803A 02745 ; BITMAP "22222222" -803A 02746 ; BITMAP "22222222" -803A 02747 ; BITMAP "22222222" -803A 02748 ; BITMAP "22222222" -803A 02749 ; -803A 02750 ; BITMAP "33333333" -803A 02751 ; BITMAP "33333333" -803A 02752 ; BITMAP "33333333" -803A 02753 ; BITMAP "33333333" -803A 02754 ; BITMAP "22333333" -803A 02755 ; BITMAP "22223333" -803A 02756 ; BITMAP "22222333" -803A 02757 ; BITMAP "22222233" -803A 02758 ; -803A 02759 ; BITMAP "22222333" -803A 02760 ; BITMAP "22222333" -803A 02761 ; BITMAP "22222233" -803A 02762 ; BITMAP "22222333" -803A 02763 ; BITMAP "22222333" -803A 02764 ; BITMAP "22222333" -803A 02765 ; BITMAP "22222333" -803A 02766 ; BITMAP "22222233" -803A 02767 ; -803A 02768 ; BITMAP "33322222" -803A 02769 ; BITMAP "33322222" -803A 02770 ; BITMAP "33332222" -803A 02771 ; BITMAP "33332122" -803A 02772 ; BITMAP "33333222" -803A 02773 ; BITMAP "33333212" -803A 02774 ; BITMAP "33333322" -803A 02775 ; BITMAP "33333332" -803A 02776 ; -803A 02777 ; BITMAP "22222222" -803A 02778 ; BITMAP "22222222" -803A 02779 ; BITMAP "22222222" -803A 02780 ; BITMAP "22222222" -803A 02781 ; BITMAP "22222112" -803A 02782 ; BITMAP "22221112" -803A 02783 ; BITMAP "22211111" -803A 02784 ; BITMAP "22211111" -803A 02785 ; -803A 02786 ; BITMAP "22222111" -803A 02787 ; BITMAP "22221111" -803A 02788 ; BITMAP "22211111" -803A 02789 ; BITMAP "22111111" -803A 02790 ; BITMAP "21111111" -803A 02791 ; BITMAP "11111112" -803A 02792 ; BITMAP "11211132" -803A 02793 ; BITMAP "11112321" -803A 02794 ; -803A 02795 ; BITMAP "11001222" -803A 02796 ; BITMAP "11001222" -803A 02797 ; BITMAP "10101222" -803A 02798 ; BITMAP "11102212" -803A 02799 ; BITMAP "21112112" -803A 02800 ; BITMAP "11022022" -803A 02801 ; BITMAP "01132022" -803A 02802 ; BITMAP "10231132" -803A 02803 ; -803A 02804 ; BITMAP "22222222" -803A 02805 ; BITMAP "22222222" -803A 02806 ; BITMAP "22222222" -803A 02807 ; BITMAP "22222222" -803A 02808 ; BITMAP "22222222" -803A 02809 ; BITMAP "22222222" -803A 02810 ; BITMAP "12222222" -803A 02811 ; BITMAP "00122222" -803A 02812 ; -803A 02813 ; BITMAP "22222333" -803A 02814 ; BITMAP "22222233" -803A 02815 ; BITMAP "22222233" -803A 02816 ; BITMAP "22222333" -803A 02817 ; BITMAP "22222233" -803A 02818 ; BITMAP "22222233" -803A 02819 ; BITMAP "22222233" -803A 02820 ; BITMAP "22222233" -803A 02821 ; -803A 02822 ; BITMAP "33333333" -803A 02823 ; BITMAP "33333333" -803A 02824 ; BITMAP "33333333" -803A 02825 ; BITMAP "33333333" -803A 02826 ; BITMAP "33333333" -803A 02827 ; BITMAP "33333321" -803A 02828 ; BITMAP "33333100" -803A 02829 ; BITMAP "33321010" -803A 02830 ; -803A 02831 ; BITMAP "33333332" -803A 02832 ; BITMAP "33333211" -803A 02833 ; BITMAP "33321002" -803A 02834 ; BITMAP "32100112" -803A 02835 ; BITMAP "20011122" -803A 02836 ; BITMAP "00111123" -803A 02837 ; BITMAP "10110232" -803A 02838 ; BITMAP "01111322" -803A 02839 ; -803A 02840 ; BITMAP "22222222" -803A 02841 ; BITMAP "22222222" -803A 02842 ; BITMAP "22111111" -803A 02843 ; BITMAP "22111111" -803A 02844 ; BITMAP "22122222" -803A 02845 ; BITMAP "22112222" -803A 02846 ; BITMAP "21012222" -803A 02847 ; BITMAP "21012222" -803A 02848 ; -803A 02849 ; BITMAP "22111111" -803A 02850 ; BITMAP "21111111" -803A 02851 ; BITMAP "11111222" -803A 02852 ; BITMAP "12222222" -803A 02853 ; BITMAP "22222222" -803A 02854 ; BITMAP "22222222" -803A 02855 ; BITMAP "22222223" -803A 02856 ; BITMAP "22222233" -803A 02857 ; -803A 02858 ; BITMAP "11223311" -803A 02859 ; BITMAP "22223201" -803A 02860 ; BITMAP "22232110" -803A 02861 ; BITMAP "22331102" -803A 02862 ; BITMAP "23321113" -803A 02863 ; BITMAP "33211023" -803A 02864 ; BITMAP "33110233" -803A 02865 ; BITMAP "32011332" -803A 02866 ; -803A 02867 ; BITMAP "02320231" -803A 02868 ; BITMAP "13311320" -803A 02869 ; BITMAP "23202310" -803A 02870 ; BITMAP "33013201" -803A 02871 ; BITMAP "31033101" -803A 02872 ; BITMAP "20232010" -803A 02873 ; BITMAP "11331010" -803A 02874 ; BITMAP "02320110" -803A 02875 ; -803A 02876 ; BITMAP "00012222" -803A 02877 ; BITMAP "00012222" -803A 02878 ; BITMAP "00000112" -803A 02879 ; BITMAP "00000001" -803A 02880 ; BITMAP "00000000" -803A 02881 ; BITMAP "11000000" -803A 02882 ; BITMAP "00000000" -803A 02883 ; BITMAP "00000000" -803A 02884 ; -803A 02885 ; BITMAP "22222222" -803A 02886 ; BITMAP "22222222" -803A 02887 ; BITMAP "22222222" -803A 02888 ; BITMAP "12222222" -803A 02889 ; BITMAP "01222222" -803A 02890 ; BITMAP "00122222" -803A 02891 ; BITMAP "00012222" -803A 02892 ; BITMAP "00000112" -803A 02893 ; -803A 02894 ; BITMAP "22222223" -803A 02895 ; BITMAP "22222223" -803A 02896 ; BITMAP "22222222" -803A 02897 ; BITMAP "22222222" -803A 02898 ; BITMAP "22222222" -803A 02899 ; BITMAP "22222222" -803A 02900 ; BITMAP "22222222" -803A 02901 ; BITMAP "22222222" -803A 02902 ; -803A 02903 ; BITMAP "33333333" -803A 02904 ; BITMAP "33333333" -803A 02905 ; BITMAP "33333333" -803A 02906 ; BITMAP "33333331" -803A 02907 ; BITMAP "33333210" -803A 02908 ; BITMAP "23333111" -803A 02909 ; BITMAP "22232111" -803A 02910 ; BITMAP "22331110" -803A 02911 ; -803A 02912 ; BITMAP "33200100" -803A 02913 ; BITMAP "32011001" -803A 02914 ; BITMAP "10110011" -803A 02915 ; BITMAP "01110011" -803A 02916 ; BITMAP "11100111" -803A 02917 ; BITMAP "11101110" -803A 02918 ; BITMAP "01011111" -803A 02919 ; BITMAP "11111101" -803A 02920 ; -803A 02921 ; BITMAP "11102322" -803A 02922 ; BITMAP "11112322" -803A 02923 ; BITMAP "01123322" -803A 02924 ; BITMAP "11123222" -803A 02925 ; BITMAP "11132222" -803A 02926 ; BITMAP "21022222" -803A 02927 ; BITMAP "21122222" -803A 02928 ; BITMAP "20022122" -803A 02929 ; -803A 02930 ; BITMAP "21012222" -803A 02931 ; BITMAP "21012222" -803A 02932 ; BITMAP "21011222" -803A 02933 ; BITMAP "21011222" -803A 02934 ; BITMAP "21011222" -803A 02935 ; BITMAP "11011222" -803A 02936 ; BITMAP "22011222" -803A 02937 ; BITMAP "22101232" -803A 02938 ; -803A 02939 ; BITMAP "22222333" -803A 02940 ; BITMAP "22223333" -803A 02941 ; BITMAP "22233332" -803A 02942 ; BITMAP "22333331" -803A 02943 ; BITMAP "23333311" -803A 02944 ; BITMAP "22223211" -803A 02945 ; BITMAP "22222110" -803A 02946 ; BITMAP "22221112" -803A 02947 ; -803A 02948 ; BITMAP "21102320" -803A 02949 ; BITMAP "11023310" -803A 02950 ; BITMAP "01133202" -803A 02951 ; BITMAP "10232013" -803A 02952 ; BITMAP "02331023" -803A 02953 ; BITMAP "13320233" -803A 02954 ; BITMAP "23301331" -803A 02955 ; BITMAP "33102320" -803A 02956 ; -803A 02957 ; BITMAP "13201001" -803A 02958 ; BITMAP "33101000" -803A 02959 ; BITMAP "32011000" -803A 02960 ; BITMAP "31010000" -803A 02961 ; BITMAP "20100010" -803A 02962 ; BITMAP "01100110" -803A 02963 ; BITMAP "01000000" -803A 02964 ; BITMAP "11001100" -803A 02965 ; -803A 02966 ; BITMAP "00000000" -803A 02967 ; BITMAP "00000000" -803A 02968 ; BITMAP "00000000" -803A 02969 ; BITMAP "00000000" -803A 02970 ; BITMAP "00000000" -803A 02971 ; BITMAP "00000000" -803A 02972 ; BITMAP "00000000" -803A 02973 ; BITMAP "00000000" -803A 02974 ; -803A 02975 ; BITMAP "00000001" -803A 02976 ; BITMAP "00000000" -803A 02977 ; BITMAP "00000000" -803A 02978 ; BITMAP "00000000" -803A 02979 ; BITMAP "00000000" -803A 02980 ; BITMAP "00000000" -803A 02981 ; BITMAP "00000000" -803A 02982 ; BITMAP "00000000" -803A 02983 ; -803A 02984 ; BITMAP "22222222" -803A 02985 ; BITMAP "01222222" -803A 02986 ; BITMAP "00122222" -803A 02987 ; BITMAP "00012222" -803A 02988 ; BITMAP "00001222" -803A 02989 ; BITMAP "00000122" -803A 02990 ; BITMAP "00000112" -803A 02991 ; BITMAP "00000000" -803A 02992 ; -803A 02993 ; BITMAP "22222222" -803A 02994 ; BITMAP "22222222" -803A 02995 ; BITMAP "22222222" -803A 02996 ; BITMAP "22222222" -803A 02997 ; BITMAP "22222222" -803A 02998 ; BITMAP "22222222" -803A 02999 ; BITMAP "22222222" -803A 03000 ; BITMAP "11222222" -803A 03001 ; -803A 03002 ; BITMAP "22321110" -803A 03003 ; BITMAP "22321100" -803A 03004 ; BITMAP "22321100" -803A 03005 ; BITMAP "22311100" -803A 03006 ; BITMAP "23311101" -803A 03007 ; BITMAP "23310101" -803A 03008 ; BITMAP "23310111" -803A 03009 ; BITMAP "23320111" -803A 03010 ; -803A 03011 ; BITMAP "10111102" -803A 03012 ; BITMAP "01111112" -803A 03013 ; BITMAP "11111112" -803A 03014 ; BITMAP "11111112" -803A 03015 ; BITMAP "11111022" -803A 03016 ; BITMAP "11111121" -803A 03017 ; BITMAP "11111121" -803A 03018 ; BITMAP "11111111" -803A 03019 ; -803A 03020 ; BITMAP "20023112" -803A 03021 ; BITMAP "10013212" -803A 03022 ; BITMAP "10001222" -803A 03023 ; BITMAP "00001222" -803A 03024 ; BITMAP "00001222" -803A 03025 ; BITMAP "00001222" -803A 03026 ; BITMAP "00012223" -803A 03027 ; BITMAP "00012233" -803A 03028 ; -803A 03029 ; BITMAP "22201322" -803A 03030 ; BITMAP "22201322" -803A 03031 ; BITMAP "22222223" -803A 03032 ; BITMAP "22222333" -803A 03033 ; BITMAP "22222332" -803A 03034 ; BITMAP "32222322" -803A 03035 ; BITMAP "33212221" -803A 03036 ; BITMAP "33202101" -803A 03037 ; -803A 03038 ; BITMAP "22221113" -803A 03039 ; BITMAP "22211023" -803A 03040 ; BITMAP "22111233" -803A 03041 ; BITMAP "21111332" -803A 03042 ; BITMAP "11103331" -803A 03043 ; BITMAP "11023310" -803A 03044 ; BITMAP "10233201" -803A 03045 ; BITMAP "02332013" -803A 03046 ; -803A 03047 ; BITMAP "32013310" -803A 03048 ; BITMAP "31133201" -803A 03049 ; BITMAP "20233011" -803A 03050 ; BITMAP "01331011" -803A 03051 ; BITMAP "03320111" -803A 03052 ; BITMAP "23311110" -803A 03053 ; BITMAP "33211000" -803A 03054 ; BITMAP "32111111" -803A 03055 ; -803A 03056 ; BITMAP "11111000" -803A 03057 ; BITMAP "11111000" -803A 03058 ; BITMAP "11110000" -803A 03059 ; BITMAP "11000000" -803A 03060 ; BITMAP "00000000" -803A 03061 ; BITMAP "00000000" -803A 03062 ; BITMAP "00000001" -803A 03063 ; BITMAP "00000001" -803A 03064 ; -803A 03065 ; BITMAP "00000000" -803A 03066 ; BITMAP "00000000" -803A 03067 ; BITMAP "00000000" -803A 03068 ; BITMAP "00000000" -803A 03069 ; BITMAP "11000000" -803A 03070 ; BITMAP "11000000" -803A 03071 ; BITMAP "11100000" -803A 03072 ; BITMAP "11100000" -803A 03073 ; -803A 03074 ; BITMAP "00012222" -803A 03075 ; BITMAP "00000122" -803A 03076 ; BITMAP "00000002" -803A 03077 ; BITMAP "00000000" -803A 03078 ; BITMAP "00000000" -803A 03079 ; BITMAP "00000000" -803A 03080 ; BITMAP "00000000" -803A 03081 ; BITMAP "00000000" -803A 03082 ; -803A 03083 ; BITMAP "23310111" -803A 03084 ; BITMAP "23301111" -803A 03085 ; BITMAP "23201111" -803A 03086 ; BITMAP "23111111" -803A 03087 ; BITMAP "22111111" -803A 03088 ; BITMAP "22011111" -803A 03089 ; BITMAP "21111111" -803A 03090 ; BITMAP "21111111" -803A 03091 ; -803A 03092 ; BITMAP "11111111" -803A 03093 ; BITMAP "11111110" -803A 03094 ; BITMAP "11111110" -803A 03095 ; BITMAP "11101110" -803A 03096 ; BITMAP "11101110" -803A 03097 ; BITMAP "11011100" -803A 03098 ; BITMAP "11011100" -803A 03099 ; BITMAP "10011100" -803A 03100 ; -803A 03101 ; BITMAP "00012333" -803A 03102 ; BITMAP "00123333" -803A 03103 ; BITMAP "00123333" -803A 03104 ; BITMAP "01223333" -803A 03105 ; BITMAP "01223333" -803A 03106 ; BITMAP "01233333" -803A 03107 ; BITMAP "12233333" -803A 03108 ; BITMAP "12333332" -803A 03109 ; -803A 03110 ; BITMAP "33201110" -803A 03111 ; BITMAP "33201102" -803A 03112 ; BITMAP "33111123" -803A 03113 ; BITMAP "32111122" -803A 03114 ; BITMAP "21111100" -803A 03115 ; BITMAP "21111011" -803A 03116 ; BITMAP "11123201" -803A 03117 ; BITMAP "11133311" -803A 03118 ; -803A 03119 ; BITMAP "23331122" -803A 03120 ; BITMAP "33201110" -803A 03121 ; BITMAP "32111111" -803A 03122 ; BITMAP "11111111" -803A 03123 ; BITMAP "11111111" -803A 03124 ; BITMAP "11111111" -803A 03125 ; BITMAP "11111111" -803A 03126 ; BITMAP "11111111" -803A 03127 ; -803A 03128 ; BITMAP "10111111" -803A 03129 ; BITMAP "11111111" -803A 03130 ; BITMAP "11101111" -803A 03131 ; BITMAP "11111111" -803A 03132 ; BITMAP "11111111" -803A 03133 ; BITMAP "11111111" -803A 03134 ; BITMAP "11111111" -803A 03135 ; BITMAP "11111111" -803A 03136 ; -803A 03137 ; BITMAP "10000001" -803A 03138 ; BITMAP "11100001" -803A 03139 ; BITMAP "11111001" -803A 03140 ; BITMAP "11111001" -803A 03141 ; BITMAP "11111001" -803A 03142 ; BITMAP "11111011" -803A 03143 ; BITMAP "11110011" -803A 03144 ; BITMAP "11100011" -803A 03145 ; -803A 03146 ; BITMAP "11110000" -803A 03147 ; BITMAP "11110000" -803A 03148 ; BITMAP "11110000" -803A 03149 ; BITMAP "11111000" -803A 03150 ; BITMAP "11111000" -803A 03151 ; BITMAP "11111000" -803A 03152 ; BITMAP "11111100" -803A 03153 ; BITMAP "11111100" -803A 03154 ; -803A 03155 ; BITMAP "00000000" -803A 03156 ; BITMAP "00000001" -803A 03157 ; BITMAP "00000012" -803A 03158 ; BITMAP "00000222" -803A 03159 ; BITMAP "00002322" -803A 03160 ; BITMAP "00013332" -803A 03161 ; BITMAP "00023333" -803A 03162 ; BITMAP "00133333" -803A 03163 ; -803A 03164 ; BITMAP "22222222" -803A 03165 ; BITMAP "22222222" -803A 03166 ; BITMAP "22222222" -803A 03167 ; BITMAP "22222222" -803A 03168 ; BITMAP "22222221" -803A 03169 ; BITMAP "22222221" -803A 03170 ; BITMAP "22222210" -803A 03171 ; BITMAP "22222211" -803A 03172 ; -803A 03173 ; BITMAP "21111111" -803A 03174 ; BITMAP "11111111" -803A 03175 ; BITMAP "11111111" -803A 03176 ; BITMAP "11111111" -803A 03177 ; BITMAP "11111111" -803A 03178 ; BITMAP "11111111" -803A 03179 ; BITMAP "11111110" -803A 03180 ; BITMAP "11111110" -803A 03181 ; -803A 03182 ; BITMAP "10111001" -803A 03183 ; BITMAP "11111001" -803A 03184 ; BITMAP "11111012" -803A 03185 ; BITMAP "11110012" -803A 03186 ; BITMAP "11110122" -803A 03187 ; BITMAP "11110122" -803A 03188 ; BITMAP "11101222" -803A 03189 ; BITMAP "11001123" -803A 03190 ; -803A 03191 ; BITMAP "23333222" -803A 03192 ; BITMAP "23332232" -803A 03193 ; BITMAP "23223331" -803A 03194 ; BITMAP "32233321" -803A 03195 ; BITMAP "22333321" -803A 03196 ; BITMAP "23333321" -803A 03197 ; BITMAP "33332211" -803A 03198 ; BITMAP "33332211" -803A 03199 ; -803A 03200 ; BITMAP "11133311" -803A 03201 ; BITMAP "11112101" -803A 03202 ; BITMAP "11110111" -803A 03203 ; BITMAP "11111111" -803A 03204 ; BITMAP "11111111" -803A 03205 ; BITMAP "11111111" -803A 03206 ; BITMAP "11111111" -803A 03207 ; BITMAP "11111111" -803A 03208 ; -803A 03209 ; BITMAP "11111111" -803A 03210 ; BITMAP "11111111" -803A 03211 ; BITMAP "11111111" -803A 03212 ; BITMAP "11110111" -803A 03213 ; BITMAP "11100111" -803A 03214 ; BITMAP "11101111" -803A 03215 ; BITMAP "11001111" -803A 03216 ; BITMAP "10011111" -803A 03217 ; -803A 03218 ; BITMAP "11111111" -803A 03219 ; BITMAP "11111111" -803A 03220 ; BITMAP "11111111" -803A 03221 ; BITMAP "11111111" -803A 03222 ; BITMAP "11111111" -803A 03223 ; BITMAP "11111111" -803A 03224 ; BITMAP "11111111" -803A 03225 ; BITMAP "11111111" -803A 03226 ; -803A 03227 ; BITMAP "11100011" -803A 03228 ; BITMAP "11000111" -803A 03229 ; BITMAP "11000111" -803A 03230 ; BITMAP "11000111" -803A 03231 ; BITMAP "11000111" -803A 03232 ; BITMAP "11001111" -803A 03233 ; BITMAP "10001111" -803A 03234 ; BITMAP "10001111" -803A 03235 ; -803A 03236 ; BITMAP "11111110" -803A 03237 ; BITMAP "11111110" -803A 03238 ; BITMAP "11111111" -803A 03239 ; BITMAP "11111111" -803A 03240 ; BITMAP "11111111" -803A 03241 ; BITMAP "11111111" -803A 03242 ; BITMAP "11111111" -803A 03243 ; BITMAP "11111111" -803A 03244 ; -803A 03245 ; BITMAP "00000000" -803A 03246 ; BITMAP "00000000" -803A 03247 ; BITMAP "00000000" -803A 03248 ; BITMAP "00000000" -803A 03249 ; BITMAP "10000000" -803A 03250 ; BITMAP "10000000" -803A 03251 ; BITMAP "10000000" -803A 03252 ; BITMAP "11000000" -803A 03253 ; -803A 03254 ; BITMAP "00000000" -803A 03255 ; BITMAP "00000000" -803A 03256 ; BITMAP "00000000" -803A 03257 ; BITMAP "00000000" -803A 03258 ; BITMAP "00000000" -803A 03259 ; BITMAP "00100000" -803A 03260 ; BITMAP "00100001" -803A 03261 ; BITMAP "00101102" -803A 03262 ; -803A 03263 ; BITMAP "00233333" -803A 03264 ; BITMAP "01333323" -803A 03265 ; BITMAP "02333323" -803A 03266 ; BITMAP "13333223" -803A 03267 ; BITMAP "23333223" -803A 03268 ; BITMAP "23333223" -803A 03269 ; BITMAP "33332233" -803A 03270 ; BITMAP "33332233" -803A 03271 ; -803A 03272 ; -803A 03273 ; ' Width = 12, height = 16 -803A 03274 ; image_pattern: -803A 03275 CVB_IMAGE_PATTERN: -803A 03276 ; DATA BYTE $80,$81,$81,$81,$82,$83,$84,$84,$84,$84,$84,$84 -803A 8081818182838484 03277 DB $80,$81,$81,$81,$82,$83,$84,$84 -8042 84848484 03278 DB $84,$84,$84,$84 -8046 03279 ; DATA BYTE $81,$81,$81,$85,$86,$84,$84,$84,$84,$84,$84,$84 -8046 8181818586848484 03280 DB $81,$81,$81,$85,$86,$84,$84,$84 -804E 84848484 03281 DB $84,$84,$84,$84 -8052 03282 ; DATA BYTE $81,$81,$87,$88,$84,$84,$84,$84,$84,$84,$84,$84 -8052 8181878884848484 03283 DB $81,$81,$87,$88,$84,$84,$84,$84 -805A 84848484 03284 DB $84,$84,$84,$84 -805E 03285 ; DATA BYTE $81,$81,$89,$8a,$8b,$8c,$84,$84,$84,$84,$84,$84 -805E 8181898A8B8C8484 03286 DB $81,$81,$89,$8A,$8B,$8C,$84,$84 -8066 84848484 03287 DB $84,$84,$84,$84 -806A 03288 ; DATA BYTE $81,$8d,$8e,$8f,$90,$91,$92,$93,$84,$84,$84,$84 -806A 818D8E8F90919293 03289 DB $81,$8D,$8E,$8F,$90,$91,$92,$93 -8072 84848484 03290 DB $84,$84,$84,$84 -8076 03291 ; DATA BYTE $81,$94,$95,$96,$81,$97,$98,$99,$84,$84,$84,$84 -8076 8194959681979899 03292 DB $81,$94,$95,$96,$81,$97,$98,$99 -807E 84848484 03293 DB $84,$84,$84,$84 -8082 03294 ; DATA BYTE $9a,$84,$9b,$9c,$9d,$9e,$9f,$a0,$a1,$a2,$84,$84 -8082 9A849B9C9D9E9FA0 03295 DB $9A,$84,$9B,$9C,$9D,$9E,$9F,$A0 -808A A1A28484 03296 DB $A1,$A2,$84,$84 -808E 03297 ; DATA BYTE $a3,$84,$a4,$a5,$a6,$a7,$a8,$a9,$81,$aa,$84,$84 -808E A384A4A5A6A7A8A9 03298 DB $A3,$84,$A4,$A5,$A6,$A7,$A8,$A9 -8096 81AA8484 03299 DB $81,$AA,$84,$84 -809A 03300 ; DATA BYTE $ab,$84,$ac,$ad,$ae,$af,$b0,$b1,$81,$b2,$b3,$84 -809A AB84ACADAEAFB0B1 03301 DB $AB,$84,$AC,$AD,$AE,$AF,$B0,$B1 -80A2 81B2B384 03302 DB $81,$B2,$B3,$84 -80A6 03303 ; DATA BYTE $b4,$84,$b5,$b6,$b7,$b8,$b9,$ba,$81,$81,$bb,$bc -80A6 B484B5B6B7B8B9BA 03304 DB $B4,$84,$B5,$B6,$B7,$B8,$B9,$BA -80AE 8181BBBC 03305 DB $81,$81,$BB,$BC -80B2 03306 ; DATA BYTE $bd,$84,$84,$be,$81,$bf,$c0,$c1,$c2,$81,$81,$81 -80B2 BD8484BE81BFC0C1 03307 DB $BD,$84,$84,$BE,$81,$BF,$C0,$C1 -80BA C2818181 03308 DB $C2,$81,$81,$81 -80BE 03309 ; DATA BYTE $c3,$84,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$81,$81 -80BE C384C4C5C6C7C8C9 03310 DB $C3,$84,$C4,$C5,$C6,$C7,$C8,$C9 -80C6 CACB8181 03311 DB $CA,$CB,$81,$81 -80CA 03312 ; DATA BYTE $cc,$cd,$ce,$cf,$d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7 -80CA CCCDCECFD0D1D2D3 03313 DB $CC,$CD,$CE,$CF,$D0,$D1,$D2,$D3 -80D2 D4D5D6D7 03314 DB $D4,$D5,$D6,$D7 -80D6 03315 ; DATA BYTE $81,$d8,$d9,$da,$db,$dc,$dd,$de,$df,$d4,$d4,$e0 -80D6 81D8D9DADBDCDDDE 03316 DB $81,$D8,$D9,$DA,$DB,$DC,$DD,$DE -80DE DFD4D4E0 03317 DB $DF,$D4,$D4,$E0 -80E2 03318 ; DATA BYTE $81,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$d4,$d4,$e9 -80E2 81E1E2E3E4E5E6E7 03319 DB $81,$E1,$E2,$E3,$E4,$E5,$E6,$E7 -80EA E8D4D4E9 03320 DB $E8,$D4,$D4,$E9 -80EE 03321 ; DATA BYTE $ea,$eb,$ec,$ed,$ee,$ef,$f0,$f1,$f2,$f3,$f4,$f5 -80EE EAEBECEDEEEFF0F1 03322 DB $EA,$EB,$EC,$ED,$EE,$EF,$F0,$F1 -80F6 F2F3F4F5 03323 DB $F2,$F3,$F4,$F5 -80FA 03324 BANK_2_FREE: EQU $BFFF-$ -80FA FFFFFFFFFFFFFFFF 03325 TIMES $BFFF-$ DB $FF -BFFF 01 03326 DB $01 -C000 03327 ROM_END: -C000 03328 IF CVBASIC_BANK_SWITCHING - 03329 FORG CVBASIC_BANK_ROM_SIZE*1024+16-6 ; Go to final of ROM minus vectors - 03330 ELSE - 03331 TIMES $FFFA-$ DB $FF - 03332 ENDIF - 03333 -0000 E3C2 03334 DW NMI_HANDLER -0002 2BC9 03335 DW START -0004 E2C2 03336 DW IRQ_HANDLER -0006 03337 - 03338 FORG $34010 - 03339 -8000 03340 ORG $8000 -8000 03341 -8000 03342 ; CHR data -8000 0000000000000000 03343 DB $00,$00,$00,$00,$00,$00,$00,$00 -8008 0000000000000000 03344 DB $00,$00,$00,$00,$00,$00,$00,$00 -8010 0000000000000000 03345 DB $00,$00,$00,$00,$00,$00,$00,$00 -8018 0000000000000000 03346 DB $00,$00,$00,$00,$00,$00,$00,$00 -8020 0000000000000000 03347 DB $00,$00,$00,$00,$00,$00,$00,$00 -8028 0000000000000000 03348 DB $00,$00,$00,$00,$00,$00,$00,$00 -8030 0000000000000000 03349 DB $00,$00,$00,$00,$00,$00,$00,$00 -8038 0000000000000000 03350 DB $00,$00,$00,$00,$00,$00,$00,$00 -8040 0000000000000000 03351 DB $00,$00,$00,$00,$00,$00,$00,$00 -8048 0000000000000000 03352 DB $00,$00,$00,$00,$00,$00,$00,$00 -8050 0000000000000000 03353 DB $00,$00,$00,$00,$00,$00,$00,$00 -8058 0000000000000000 03354 DB $00,$00,$00,$00,$00,$00,$00,$00 -8060 0000000000000000 03355 DB $00,$00,$00,$00,$00,$00,$00,$00 -8068 0000000000000000 03356 DB $00,$00,$00,$00,$00,$00,$00,$00 -8070 0000000000000000 03357 DB $00,$00,$00,$00,$00,$00,$00,$00 -8078 0000000000000000 03358 DB $00,$00,$00,$00,$00,$00,$00,$00 -8080 0000000000000000 03359 DB $00,$00,$00,$00,$00,$00,$00,$00 -8088 0000000000000000 03360 DB $00,$00,$00,$00,$00,$00,$00,$00 -8090 0000000000000000 03361 DB $00,$00,$00,$00,$00,$00,$00,$00 -8098 0000000000000000 03362 DB $00,$00,$00,$00,$00,$00,$00,$00 -80A0 0000000000000000 03363 DB $00,$00,$00,$00,$00,$00,$00,$00 -80A8 0000000000000000 03364 DB $00,$00,$00,$00,$00,$00,$00,$00 -80B0 0000000000000000 03365 DB $00,$00,$00,$00,$00,$00,$00,$00 -80B8 0000000000000000 03366 DB $00,$00,$00,$00,$00,$00,$00,$00 -80C0 0000000000000000 03367 DB $00,$00,$00,$00,$00,$00,$00,$00 -80C8 0000000000000000 03368 DB $00,$00,$00,$00,$00,$00,$00,$00 -80D0 0000000000000000 03369 DB $00,$00,$00,$00,$00,$00,$00,$00 -80D8 0000000000000000 03370 DB $00,$00,$00,$00,$00,$00,$00,$00 -80E0 0000000000000000 03371 DB $00,$00,$00,$00,$00,$00,$00,$00 -80E8 0000000000000000 03372 DB $00,$00,$00,$00,$00,$00,$00,$00 -80F0 0000000000000000 03373 DB $00,$00,$00,$00,$00,$00,$00,$00 -80F8 0000000000000000 03374 DB $00,$00,$00,$00,$00,$00,$00,$00 -8100 0000000000000000 03375 DB $00,$00,$00,$00,$00,$00,$00,$00 -8108 0000000000000000 03376 DB $00,$00,$00,$00,$00,$00,$00,$00 -8110 0000000000000000 03377 DB $00,$00,$00,$00,$00,$00,$00,$00 -8118 0000000000000000 03378 DB $00,$00,$00,$00,$00,$00,$00,$00 -8120 0000000000000000 03379 DB $00,$00,$00,$00,$00,$00,$00,$00 -8128 0000000000000000 03380 DB $00,$00,$00,$00,$00,$00,$00,$00 -8130 0000000000000000 03381 DB $00,$00,$00,$00,$00,$00,$00,$00 -8138 0000000000000000 03382 DB $00,$00,$00,$00,$00,$00,$00,$00 -8140 0000000000000000 03383 DB $00,$00,$00,$00,$00,$00,$00,$00 -8148 0000000000000000 03384 DB $00,$00,$00,$00,$00,$00,$00,$00 -8150 0000000000000000 03385 DB $00,$00,$00,$00,$00,$00,$00,$00 -8158 0000000000000000 03386 DB $00,$00,$00,$00,$00,$00,$00,$00 -8160 0000000000000000 03387 DB $00,$00,$00,$00,$00,$00,$00,$00 -8168 0000000000000000 03388 DB $00,$00,$00,$00,$00,$00,$00,$00 -8170 0000000000000000 03389 DB $00,$00,$00,$00,$00,$00,$00,$00 -8178 0000000000000000 03390 DB $00,$00,$00,$00,$00,$00,$00,$00 -8180 0000000000000000 03391 DB $00,$00,$00,$00,$00,$00,$00,$00 -8188 0000000000000000 03392 DB $00,$00,$00,$00,$00,$00,$00,$00 -8190 0000000000000000 03393 DB $00,$00,$00,$00,$00,$00,$00,$00 -8198 0000000000000000 03394 DB $00,$00,$00,$00,$00,$00,$00,$00 -81A0 0000000000000000 03395 DB $00,$00,$00,$00,$00,$00,$00,$00 -81A8 0000000000000000 03396 DB $00,$00,$00,$00,$00,$00,$00,$00 -81B0 0000000000000000 03397 DB $00,$00,$00,$00,$00,$00,$00,$00 -81B8 0000000000000000 03398 DB $00,$00,$00,$00,$00,$00,$00,$00 -81C0 0000000000000000 03399 DB $00,$00,$00,$00,$00,$00,$00,$00 -81C8 0000000000000000 03400 DB $00,$00,$00,$00,$00,$00,$00,$00 -81D0 0000000000000000 03401 DB $00,$00,$00,$00,$00,$00,$00,$00 -81D8 0000000000000000 03402 DB $00,$00,$00,$00,$00,$00,$00,$00 -81E0 0000000000000000 03403 DB $00,$00,$00,$00,$00,$00,$00,$00 -81E8 0000000000000000 03404 DB $00,$00,$00,$00,$00,$00,$00,$00 -81F0 0000000000000000 03405 DB $00,$00,$00,$00,$00,$00,$00,$00 -81F8 0000000000000000 03406 DB $00,$00,$00,$00,$00,$00,$00,$00 -8200 0000000000000000 03407 DB $00,$00,$00,$00,$00,$00,$00,$00 -8208 0000000000000000 03408 DB $00,$00,$00,$00,$00,$00,$00,$00 -8210 2020202020002000 03409 DB $20,$20,$20,$20,$20,$00,$20,$00 -8218 2020202020002000 03410 DB $20,$20,$20,$20,$20,$00,$20,$00 -8220 5050500000000000 03411 DB $50,$50,$50,$00,$00,$00,$00,$00 -8228 5050500000000000 03412 DB $50,$50,$50,$00,$00,$00,$00,$00 -8230 5050F850F8505000 03413 DB $50,$50,$F8,$50,$F8,$50,$50,$00 -8238 5050F850F8505000 03414 DB $50,$50,$F8,$50,$F8,$50,$50,$00 -8240 2078A07028F02000 03415 DB $20,$78,$A0,$70,$28,$F0,$20,$00 -8248 2078A07028F02000 03416 DB $20,$78,$A0,$70,$28,$F0,$20,$00 -8250 C0C8102040981800 03417 DB $C0,$C8,$10,$20,$40,$98,$18,$00 -8258 C0C8102040981800 03418 DB $C0,$C8,$10,$20,$40,$98,$18,$00 -8260 40A040A0A8906800 03419 DB $40,$A0,$40,$A0,$A8,$90,$68,$00 -8268 40A040A0A8906800 03420 DB $40,$A0,$40,$A0,$A8,$90,$68,$00 -8270 6020400000000000 03421 DB $60,$20,$40,$00,$00,$00,$00,$00 -8278 6020400000000000 03422 DB $60,$20,$40,$00,$00,$00,$00,$00 -8280 1020404040201000 03423 DB $10,$20,$40,$40,$40,$20,$10,$00 -8288 1020404040201000 03424 DB $10,$20,$40,$40,$40,$20,$10,$00 -8290 4020101010204000 03425 DB $40,$20,$10,$10,$10,$20,$40,$00 -8298 4020101010204000 03426 DB $40,$20,$10,$10,$10,$20,$40,$00 -82A0 00A8702070A80000 03427 DB $00,$A8,$70,$20,$70,$A8,$00,$00 -82A8 00A8702070A80000 03428 DB $00,$A8,$70,$20,$70,$A8,$00,$00 -82B0 002020F820200000 03429 DB $00,$20,$20,$F8,$20,$20,$00,$00 -82B8 002020F820200000 03430 DB $00,$20,$20,$F8,$20,$20,$00,$00 -82C0 0000000000602040 03431 DB $00,$00,$00,$00,$00,$60,$20,$40 -82C8 0000000000602040 03432 DB $00,$00,$00,$00,$00,$60,$20,$40 -82D0 000000FC00000000 03433 DB $00,$00,$00,$FC,$00,$00,$00,$00 -82D8 000000FC00000000 03434 DB $00,$00,$00,$FC,$00,$00,$00,$00 -82E0 0000000000006000 03435 DB $00,$00,$00,$00,$00,$00,$60,$00 -82E8 0000000000006000 03436 DB $00,$00,$00,$00,$00,$00,$60,$00 -82F0 0008102040800000 03437 DB $00,$08,$10,$20,$40,$80,$00,$00 -82F8 0008102040800000 03438 DB $00,$08,$10,$20,$40,$80,$00,$00 -8300 708898A8C8887000 03439 DB $70,$88,$98,$A8,$C8,$88,$70,$00 -8308 708898A8C8887000 03440 DB $70,$88,$98,$A8,$C8,$88,$70,$00 -8310 206020202020F800 03441 DB $20,$60,$20,$20,$20,$20,$F8,$00 -8318 206020202020F800 03442 DB $20,$60,$20,$20,$20,$20,$F8,$00 -8320 708808106080F800 03443 DB $70,$88,$08,$10,$60,$80,$F8,$00 -8328 708808106080F800 03444 DB $70,$88,$08,$10,$60,$80,$F8,$00 -8330 7088083008887000 03445 DB $70,$88,$08,$30,$08,$88,$70,$00 -8338 7088083008887000 03446 DB $70,$88,$08,$30,$08,$88,$70,$00 -8340 30509090F8101000 03447 DB $30,$50,$90,$90,$F8,$10,$10,$00 -8348 30509090F8101000 03448 DB $30,$50,$90,$90,$F8,$10,$10,$00 -8350 F880F0080808F000 03449 DB $F8,$80,$F0,$08,$08,$08,$F0,$00 -8358 F880F0080808F000 03450 DB $F8,$80,$F0,$08,$08,$08,$F0,$00 -8360 304080F088887000 03451 DB $30,$40,$80,$F0,$88,$88,$70,$00 -8368 304080F088887000 03452 DB $30,$40,$80,$F0,$88,$88,$70,$00 -8370 F808102020202000 03453 DB $F8,$08,$10,$20,$20,$20,$20,$00 -8378 F808102020202000 03454 DB $F8,$08,$10,$20,$20,$20,$20,$00 -8380 7088887088887000 03455 DB $70,$88,$88,$70,$88,$88,$70,$00 -8388 7088887088887000 03456 DB $70,$88,$88,$70,$88,$88,$70,$00 -8390 7088887808106000 03457 DB $70,$88,$88,$78,$08,$10,$60,$00 -8398 7088887808106000 03458 DB $70,$88,$88,$78,$08,$10,$60,$00 -83A0 0000006000600000 03459 DB $00,$00,$00,$60,$00,$60,$00,$00 -83A8 0000006000600000 03460 DB $00,$00,$00,$60,$00,$60,$00,$00 -83B0 0000006000602040 03461 DB $00,$00,$00,$60,$00,$60,$20,$40 -83B8 0000006000602040 03462 DB $00,$00,$00,$60,$00,$60,$20,$40 -83C0 1020408040201000 03463 DB $10,$20,$40,$80,$40,$20,$10,$00 -83C8 1020408040201000 03464 DB $10,$20,$40,$80,$40,$20,$10,$00 -83D0 0000F800F8000000 03465 DB $00,$00,$F8,$00,$F8,$00,$00,$00 -83D8 0000F800F8000000 03466 DB $00,$00,$F8,$00,$F8,$00,$00,$00 -83E0 0804020102040800 03467 DB $08,$04,$02,$01,$02,$04,$08,$00 -83E8 0804020102040800 03468 DB $08,$04,$02,$01,$02,$04,$08,$00 -83F0 7088081020002000 03469 DB $70,$88,$08,$10,$20,$00,$20,$00 -83F8 7088081020002000 03470 DB $70,$88,$08,$10,$20,$00,$20,$00 -8400 708898A898807000 03471 DB $70,$88,$98,$A8,$98,$80,$70,$00 -8408 708898A898807000 03472 DB $70,$88,$98,$A8,$98,$80,$70,$00 -8410 20508888F8888800 03473 DB $20,$50,$88,$88,$F8,$88,$88,$00 -8418 20508888F8888800 03474 DB $20,$50,$88,$88,$F8,$88,$88,$00 -8420 F08888F08888F000 03475 DB $F0,$88,$88,$F0,$88,$88,$F0,$00 -8428 F08888F08888F000 03476 DB $F0,$88,$88,$F0,$88,$88,$F0,$00 -8430 7088808080887000 03477 DB $70,$88,$80,$80,$80,$88,$70,$00 -8438 7088808080887000 03478 DB $70,$88,$80,$80,$80,$88,$70,$00 -8440 F08888888888F000 03479 DB $F0,$88,$88,$88,$88,$88,$F0,$00 -8448 F08888888888F000 03480 DB $F0,$88,$88,$88,$88,$88,$F0,$00 -8450 F88080F08080F800 03481 DB $F8,$80,$80,$F0,$80,$80,$F8,$00 -8458 F88080F08080F800 03482 DB $F8,$80,$80,$F0,$80,$80,$F8,$00 -8460 F88080F080808000 03483 DB $F8,$80,$80,$F0,$80,$80,$80,$00 -8468 F88080F080808000 03484 DB $F8,$80,$80,$F0,$80,$80,$80,$00 -8470 708880B888887000 03485 DB $70,$88,$80,$B8,$88,$88,$70,$00 -8478 708880B888887000 03486 DB $70,$88,$80,$B8,$88,$88,$70,$00 -8480 888888F888888800 03487 DB $88,$88,$88,$F8,$88,$88,$88,$00 -8488 888888F888888800 03488 DB $88,$88,$88,$F8,$88,$88,$88,$00 -8490 7020202020207000 03489 DB $70,$20,$20,$20,$20,$20,$70,$00 -8498 7020202020207000 03490 DB $70,$20,$20,$20,$20,$20,$70,$00 -84A0 0808080888887000 03491 DB $08,$08,$08,$08,$88,$88,$70,$00 -84A8 0808080888887000 03492 DB $08,$08,$08,$08,$88,$88,$70,$00 -84B0 8890A0C0A0908800 03493 DB $88,$90,$A0,$C0,$A0,$90,$88,$00 -84B8 8890A0C0A0908800 03494 DB $88,$90,$A0,$C0,$A0,$90,$88,$00 -84C0 808080808080F800 03495 DB $80,$80,$80,$80,$80,$80,$F8,$00 -84C8 808080808080F800 03496 DB $80,$80,$80,$80,$80,$80,$F8,$00 -84D0 88D8A8A888888800 03497 DB $88,$D8,$A8,$A8,$88,$88,$88,$00 -84D8 88D8A8A888888800 03498 DB $88,$D8,$A8,$A8,$88,$88,$88,$00 -84E0 88C8C8A898988800 03499 DB $88,$C8,$C8,$A8,$98,$98,$88,$00 -84E8 88C8C8A898988800 03500 DB $88,$C8,$C8,$A8,$98,$98,$88,$00 -84F0 7088888888887000 03501 DB $70,$88,$88,$88,$88,$88,$70,$00 -84F8 7088888888887000 03502 DB $70,$88,$88,$88,$88,$88,$70,$00 -8500 F08888F080808000 03503 DB $F0,$88,$88,$F0,$80,$80,$80,$00 -8508 F08888F080808000 03504 DB $F0,$88,$88,$F0,$80,$80,$80,$00 -8510 7088888888A89068 03505 DB $70,$88,$88,$88,$88,$A8,$90,$68 -8518 7088888888A89068 03506 DB $70,$88,$88,$88,$88,$A8,$90,$68 -8520 F08888F0A0908800 03507 DB $F0,$88,$88,$F0,$A0,$90,$88,$00 -8528 F08888F0A0908800 03508 DB $F0,$88,$88,$F0,$A0,$90,$88,$00 -8530 7088807008887000 03509 DB $70,$88,$80,$70,$08,$88,$70,$00 -8538 7088807008887000 03510 DB $70,$88,$80,$70,$08,$88,$70,$00 -8540 F820202020202000 03511 DB $F8,$20,$20,$20,$20,$20,$20,$00 -8548 F820202020202000 03512 DB $F8,$20,$20,$20,$20,$20,$20,$00 -8550 8888888888887000 03513 DB $88,$88,$88,$88,$88,$88,$70,$00 -8558 8888888888887000 03514 DB $88,$88,$88,$88,$88,$88,$70,$00 -8560 8888888850502000 03515 DB $88,$88,$88,$88,$50,$50,$20,$00 -8568 8888888850502000 03516 DB $88,$88,$88,$88,$50,$50,$20,$00 -8570 888888A8A8D88800 03517 DB $88,$88,$88,$A8,$A8,$D8,$88,$00 -8578 888888A8A8D88800 03518 DB $88,$88,$88,$A8,$A8,$D8,$88,$00 -8580 8888502050888800 03519 DB $88,$88,$50,$20,$50,$88,$88,$00 -8588 8888502050888800 03520 DB $88,$88,$50,$20,$50,$88,$88,$00 -8590 8888887020202000 03521 DB $88,$88,$88,$70,$20,$20,$20,$00 -8598 8888887020202000 03522 DB $88,$88,$88,$70,$20,$20,$20,$00 -85A0 F80810204080F800 03523 DB $F8,$08,$10,$20,$40,$80,$F8,$00 -85A8 F80810204080F800 03524 DB $F8,$08,$10,$20,$40,$80,$F8,$00 -85B0 7860606060607800 03525 DB $78,$60,$60,$60,$60,$60,$78,$00 -85B8 7860606060607800 03526 DB $78,$60,$60,$60,$60,$60,$78,$00 -85C0 0080402010080000 03527 DB $00,$80,$40,$20,$10,$08,$00,$00 -85C8 0080402010080000 03528 DB $00,$80,$40,$20,$10,$08,$00,$00 -85D0 F03030303030F000 03529 DB $F0,$30,$30,$30,$30,$30,$F0,$00 -85D8 F03030303030F000 03530 DB $F0,$30,$30,$30,$30,$30,$F0,$00 -85E0 2050880000000000 03531 DB $20,$50,$88,$00,$00,$00,$00,$00 -85E8 2050880000000000 03532 DB $20,$50,$88,$00,$00,$00,$00,$00 -85F0 000000000000F800 03533 DB $00,$00,$00,$00,$00,$00,$F8,$00 -85F8 000000000000F800 03534 DB $00,$00,$00,$00,$00,$00,$F8,$00 -8600 4020100000000000 03535 DB $40,$20,$10,$00,$00,$00,$00,$00 -8608 4020100000000000 03536 DB $40,$20,$10,$00,$00,$00,$00,$00 -8610 0000689888986800 03537 DB $00,$00,$68,$98,$88,$98,$68,$00 -8618 0000689888986800 03538 DB $00,$00,$68,$98,$88,$98,$68,$00 -8620 8080F0888888F000 03539 DB $80,$80,$F0,$88,$88,$88,$F0,$00 -8628 8080F0888888F000 03540 DB $80,$80,$F0,$88,$88,$88,$F0,$00 -8630 0000788080807800 03541 DB $00,$00,$78,$80,$80,$80,$78,$00 -8638 0000788080807800 03542 DB $00,$00,$78,$80,$80,$80,$78,$00 -8640 0808689888986800 03543 DB $08,$08,$68,$98,$88,$98,$68,$00 -8648 0808689888986800 03544 DB $08,$08,$68,$98,$88,$98,$68,$00 -8650 00007088F8807000 03545 DB $00,$00,$70,$88,$F8,$80,$70,$00 -8658 00007088F8807000 03546 DB $00,$00,$70,$88,$F8,$80,$70,$00 -8660 304840E040404000 03547 DB $30,$48,$40,$E0,$40,$40,$40,$00 -8668 304840E040404000 03548 DB $30,$48,$40,$E0,$40,$40,$40,$00 -8670 0000788888780870 03549 DB $00,$00,$78,$88,$88,$78,$08,$70 -8678 0000788888780870 03550 DB $00,$00,$78,$88,$88,$78,$08,$70 -8680 8080F08888888800 03551 DB $80,$80,$F0,$88,$88,$88,$88,$00 -8688 8080F08888888800 03552 DB $80,$80,$F0,$88,$88,$88,$88,$00 -8690 2000602020207000 03553 DB $20,$00,$60,$20,$20,$20,$70,$00 -8698 2000602020207000 03554 DB $20,$00,$60,$20,$20,$20,$70,$00 -86A0 0800180888887000 03555 DB $08,$00,$18,$08,$88,$88,$70,$00 -86A8 0800180888887000 03556 DB $08,$00,$18,$08,$88,$88,$70,$00 -86B0 80808890E0908800 03557 DB $80,$80,$88,$90,$E0,$90,$88,$00 -86B8 80808890E0908800 03558 DB $80,$80,$88,$90,$E0,$90,$88,$00 -86C0 6020202020207000 03559 DB $60,$20,$20,$20,$20,$20,$70,$00 -86C8 6020202020207000 03560 DB $60,$20,$20,$20,$20,$20,$70,$00 -86D0 0000D0A8A8A8A800 03561 DB $00,$00,$D0,$A8,$A8,$A8,$A8,$00 -86D8 0000D0A8A8A8A800 03562 DB $00,$00,$D0,$A8,$A8,$A8,$A8,$00 -86E0 0000B0C888888800 03563 DB $00,$00,$B0,$C8,$88,$88,$88,$00 -86E8 0000B0C888888800 03564 DB $00,$00,$B0,$C8,$88,$88,$88,$00 -86F0 0000708888887000 03565 DB $00,$00,$70,$88,$88,$88,$70,$00 -86F8 0000708888887000 03566 DB $00,$00,$70,$88,$88,$88,$70,$00 -8700 0000F0888888F080 03567 DB $00,$00,$F0,$88,$88,$88,$F0,$80 -8708 0000F0888888F080 03568 DB $00,$00,$F0,$88,$88,$88,$F0,$80 -8710 0000788888887808 03569 DB $00,$00,$78,$88,$88,$88,$78,$08 -8718 0000788888887808 03570 DB $00,$00,$78,$88,$88,$88,$78,$08 -8720 0000B8C080808000 03571 DB $00,$00,$B8,$C0,$80,$80,$80,$00 -8728 0000B8C080808000 03572 DB $00,$00,$B8,$C0,$80,$80,$80,$00 -8730 000078807008F000 03573 DB $00,$00,$78,$80,$70,$08,$F0,$00 -8738 000078807008F000 03574 DB $00,$00,$78,$80,$70,$08,$F0,$00 -8740 2020F82020202000 03575 DB $20,$20,$F8,$20,$20,$20,$20,$00 -8748 2020F82020202000 03576 DB $20,$20,$F8,$20,$20,$20,$20,$00 -8750 0000888888986800 03577 DB $00,$00,$88,$88,$88,$98,$68,$00 -8758 0000888888986800 03578 DB $00,$00,$88,$88,$88,$98,$68,$00 -8760 0000888888502000 03579 DB $00,$00,$88,$88,$88,$50,$20,$00 -8768 0000888888502000 03580 DB $00,$00,$88,$88,$88,$50,$20,$00 -8770 000088A8A8A85000 03581 DB $00,$00,$88,$A8,$A8,$A8,$50,$00 -8778 000088A8A8A85000 03582 DB $00,$00,$88,$A8,$A8,$A8,$50,$00 -8780 0000885020508800 03583 DB $00,$00,$88,$50,$20,$50,$88,$00 -8788 0000885020508800 03584 DB $00,$00,$88,$50,$20,$50,$88,$00 -8790 0000888898680870 03585 DB $00,$00,$88,$88,$98,$68,$08,$70 -8798 0000888898680870 03586 DB $00,$00,$88,$88,$98,$68,$08,$70 -87A0 0000F8102040F800 03587 DB $00,$00,$F8,$10,$20,$40,$F8,$00 -87A8 0000F8102040F800 03588 DB $00,$00,$F8,$10,$20,$40,$F8,$00 -87B0 1820204020201800 03589 DB $18,$20,$20,$40,$20,$20,$18,$00 -87B8 1820204020201800 03590 DB $18,$20,$20,$40,$20,$20,$18,$00 -87C0 2020202020202000 03591 DB $20,$20,$20,$20,$20,$20,$20,$00 -87C8 2020202020202000 03592 DB $20,$20,$20,$20,$20,$20,$20,$00 -87D0 C02020102020C000 03593 DB $C0,$20,$20,$10,$20,$20,$C0,$00 -87D8 C02020102020C000 03594 DB $C0,$20,$20,$10,$20,$20,$C0,$00 -87E0 000040A810000000 03595 DB $00,$00,$40,$A8,$10,$00,$00,$00 -87E8 000040A810000000 03596 DB $00,$00,$40,$A8,$10,$00,$00,$00 -87F0 707020F820705000 03597 DB $70,$70,$20,$F8,$20,$70,$50,$00 -87F8 707020F820705000 03598 DB $70,$70,$20,$F8,$20,$70,$50,$00 -8800 F0F0F08000000000 03599 DB $F0,$F0,$F0,$80,$00,$00,$00,$00 -8808 0F0F0F7FFFFFFFFF 03600 DB $0F,$0F,$0F,$7F,$FF,$FF,$FF,$FF -8810 0000000000000000 03601 DB $00,$00,$00,$00,$00,$00,$00,$00 -8818 FFFFFFFFFFFFFFFF 03602 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8820 0000000000030F3F 03603 DB $00,$00,$00,$00,$00,$03,$0F,$3F -8828 FFFFFFFFFFFFFFFF 03604 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8830 01074F7FFFFFFFFF 03605 DB $01,$07,$4F,$7F,$FF,$FF,$FF,$FF -8838 FFFFFFFFFFFFFFFF 03606 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8840 FFFFFFFFFFFFFFFF 03607 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8848 FFFFFFFFFFFFFFFF 03608 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8850 00000103070F1F3F 03609 DB $00,$00,$01,$03,$07,$0F,$1F,$3F -8858 FFFFFFFFFFFFFFFF 03610 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8860 7FFFFFFFFFFFFFFF 03611 DB $7F,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8868 FFFFFFFFFFFFFFFF 03612 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8870 000000000303070F 03613 DB $00,$00,$00,$00,$03,$03,$07,$0F -8878 FFFFFFFFFFFFFFFF 03614 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8880 3F7FFFFFFFFFFFFF 03615 DB $3F,$7F,$FF,$FF,$FF,$FF,$FF,$FF -8888 FFFFFFFFFFFFFFFF 03616 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8890 0F1F1F3F7FFFFFFF 03617 DB $0F,$1F,$1F,$3F,$7F,$FF,$FF,$FF -8898 FFFFFFFFFFFFFFFF 03618 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -88A0 FFFFFFFFFCF0E3C7 03619 DB $FF,$FF,$FF,$FF,$FC,$F0,$E3,$C7 -88A8 FFFFFFFFFFFFFCF8 03620 DB $FF,$FF,$FF,$FF,$FF,$FF,$FC,$F8 -88B0 FFFFFFEF00FFE7FF 03621 DB $FF,$FF,$FF,$EF,$00,$FF,$E7,$FF -88B8 FFFFFFFFFF000000 03622 DB $FF,$FF,$FF,$FF,$FF,$00,$00,$00 -88C0 FFFFFFFFFF3FF7F9 03623 DB $FF,$FF,$FF,$FF,$FF,$3F,$F7,$F9 -88C8 FFFFFFFFFFFF0F07 03624 DB $FF,$FF,$FF,$FF,$FF,$FF,$0F,$07 -88D0 00010303070F0F1F 03625 DB $00,$01,$03,$03,$07,$0F,$0F,$1F -88D8 FFFFFFFFFFFFFFFF 03626 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -88E0 FFFFFFFFFEFEFCFC 03627 DB $FF,$FF,$FF,$FF,$FE,$FE,$FC,$FC -88E8 FFFFFFFFFFFFFFFF 03628 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -88F0 CF9F1F3F7F7EF0E0 03629 DB $CF,$9F,$1F,$3F,$7F,$7E,$F0,$E0 -88F8 F0E0E0C080810F1F 03630 DB $F0,$E0,$E0,$C0,$80,$81,$0F,$1F -8900 FFFFFFFFFF010000 03631 DB $FF,$FF,$FF,$FF,$FF,$01,$00,$00 -8908 0000000000FEFFFF 03632 DB $00,$00,$00,$00,$00,$FE,$FF,$FF -8910 FEFFFFFFFFFF3F0F 03633 DB $FE,$FF,$FF,$FF,$FF,$FF,$3F,$0F -8918 010000000000C0F0 03634 DB $01,$00,$00,$00,$00,$00,$C0,$F0 -8920 3FE7C3E1E1E0E0F0 03635 DB $3F,$E7,$C3,$E1,$E1,$E0,$E0,$F0 -8928 FF1F070300000000 03636 DB $FF,$1F,$07,$03,$00,$00,$00,$00 -8930 FFFFFFFFFFFF7F1F 03637 DB $FF,$FF,$FF,$FF,$FF,$FF,$7F,$1F -8938 FFFFFFFFFF7F3F3F 03638 DB $FF,$FF,$FF,$FF,$FF,$7F,$3F,$3F -8940 1F3F3F3F7F7FFFFF 03639 DB $1F,$3F,$3F,$3F,$7F,$7F,$FF,$FF -8948 FFFFFFFFFFFFFFFF 03640 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8950 FDFDFDFAFAF8F8F8 03641 DB $FD,$FD,$FD,$FA,$FA,$F8,$F8,$F8 -8958 FEFEFEFDFDFFFFFF 03642 DB $FE,$FE,$FE,$FD,$FD,$FF,$FF,$FF -8960 C080000000000000 03643 DB $C0,$80,$00,$00,$00,$00,$00,$00 -8968 3F7FFFFFFFFFFFFF 03644 DB $3F,$7F,$FF,$FF,$FF,$FF,$FF,$FF -8970 0F07070301010101 03645 DB $0F,$07,$07,$03,$01,$01,$01,$01 -8978 F0F8F8FCFEFEFEFE 03646 DB $F0,$F8,$F8,$FC,$FE,$FE,$FE,$FE -8980 F0F0F8F8F8F8F8FC 03647 DB $F0,$F0,$F8,$F8,$F8,$F8,$F8,$FC -8988 0000000000000000 03648 DB $00,$00,$00,$00,$00,$00,$00,$00 -8990 1F0F0F07070F0703 03649 DB $1F,$0F,$0F,$07,$07,$0F,$07,$03 -8998 1F1F0F0F0F070707 03650 DB $1F,$1F,$0F,$0F,$0F,$07,$07,$07 -89A0 0001010303030707 03651 DB $00,$01,$01,$03,$03,$03,$07,$07 -89A8 FFFFFFFFFFFFFFFF 03652 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -89B0 F4F4F4F0FCFCF7F7 03653 DB $F4,$F4,$F4,$F0,$FC,$FC,$F7,$F7 -89B8 FBFBFBFFFBFBF8F8 03654 DB $FB,$FB,$FB,$FF,$FB,$FB,$F8,$F8 -89C0 000000021300E0F0 03655 DB $00,$00,$00,$02,$13,$00,$E0,$F0 -89C8 FFFFFFFFFFFF1F0F 03656 DB $FF,$FF,$FF,$FF,$FF,$FF,$1F,$0F -89D0 0000001F18070E0E 03657 DB $00,$00,$00,$1F,$18,$07,$0E,$0E -89D8 FFFFFFFFFFF8F0F1 03658 DB $FF,$FF,$FF,$FF,$FF,$F8,$F0,$F1 -89E0 010303870F7FC3F8 03659 DB $01,$03,$03,$87,$0F,$7F,$C3,$F8 -89E8 FEFCFCF8F0003CFF 03660 DB $FE,$FC,$FC,$F8,$F0,$00,$3C,$FF -89F0 FCFEFEFEFEFEF0F1 03661 DB $FC,$FE,$FE,$FE,$FE,$FE,$F0,$F1 -89F8 0000000000000000 03662 DB $00,$00,$00,$00,$00,$00,$00,$00 -8A00 0302060474C60F0C 03663 DB $03,$02,$06,$04,$74,$C6,$0F,$0C -8A08 0707030303010003 03664 DB $07,$07,$03,$03,$03,$01,$00,$03 -8A10 FF1F030100000000 03665 DB $FF,$1F,$03,$01,$00,$00,$00,$00 -8A18 FFFFFFFFFFFFFFFF 03666 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8A20 FFFFFFFFFFFF7F7F 03667 DB $FF,$FF,$FF,$FF,$FF,$FF,$7F,$7F -8A28 FFFFFFFFFFFFFFFF 03668 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8A30 070707070707070F 03669 DB $07,$07,$07,$07,$07,$07,$07,$0F -8A38 FFFFFFFFFFFFFFFF 03670 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8A40 F7C4A8AB9EBFFEDC 03671 DB $F7,$C4,$A8,$AB,$9E,$BF,$FE,$DC -8A48 F8FBF7C43878F9FB 03672 DB $F8,$FB,$F7,$C4,$38,$78,$F9,$FB -8A50 FC0617F7073D0302 03673 DB $FC,$06,$17,$F7,$07,$3D,$03,$02 -8A58 03F9E800C0C0FCFD 03674 DB $03,$F9,$E8,$00,$C0,$C0,$FC,$FD -8A60 18193B3D3C3C1C1C 03675 DB $18,$19,$3B,$3D,$3C,$3C,$1C,$1C -8A68 E7E6C4C2C3C3E3E3 03676 DB $E7,$E6,$C4,$C2,$C3,$C3,$E3,$E3 -8A70 F699761940000000 03677 DB $F6,$99,$76,$19,$40,$00,$00,$00 -8A78 F970C0E6BFFFFFFF 03678 DB $F9,$70,$C0,$E6,$BF,$FF,$FF,$FF -8A80 1FFFC7C743434387 03679 DB $1F,$FF,$C7,$C7,$43,$43,$43,$87 -8A88 80003838BCBCBC78 03680 DB $80,$00,$38,$38,$BC,$BC,$BC,$78 -8A90 8089818DCDFDFDEF 03681 DB $80,$89,$81,$8D,$CD,$FD,$FD,$EF -8A98 0706060202020200 03682 DB $07,$06,$06,$02,$02,$02,$02,$00 -8AA0 7F7F3F3F3F1F1F0F 03683 DB $7F,$7F,$3F,$3F,$3F,$1F,$1F,$0F -8AA8 FFFFFFFFFFFFFFFF 03684 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8AB0 0F0F070F0F07070F 03685 DB $0F,$0F,$07,$0F,$0F,$07,$07,$0F -8AB8 FFFFFFFFFFFFFFFF 03686 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8AC0 D4E4F4FBF8FCFCFC 03687 DB $D4,$E4,$F4,$FB,$F8,$FC,$FC,$FC -8AC8 FBFBFBFCFFFFFFFF 03688 DB $FB,$FB,$FB,$FC,$FF,$FF,$FF,$FF -8AD0 06040CA000000000 03689 DB $06,$04,$0C,$A0,$00,$00,$00,$00 -8AD8 F9FBF35FFFFFFFFF 03690 DB $F9,$FB,$F3,$5F,$FF,$FF,$FF,$FF -8AE0 0E1F1E1F1F0B813F 03691 DB $0E,$1F,$1E,$1F,$1F,$0B,$81,$3F -8AE8 F1E0E1E0E0F4FEC0 03692 DB $F1,$E0,$E1,$E0,$E0,$F4,$FE,$C0 -8AF0 0000020E86808000 03693 DB $00,$00,$02,$0E,$86,$80,$80,$00 -8AF8 FFFFFFFF7F7F7FFF 03694 DB $FF,$FF,$FF,$FF,$7F,$7F,$7F,$FF -8B00 8707070707070F0F 03695 DB $87,$07,$07,$07,$07,$07,$0F,$0F -8B08 78F8F8F8F8F8F0F0 03696 DB $78,$F8,$F8,$F8,$F8,$F8,$F0,$F0 -8B10 EBF0FEF8F0F0F0F0 03697 DB $EB,$F0,$FE,$F8,$F0,$F0,$F0,$F0 -8B18 040F01070F0F0F0F 03698 DB $04,$0F,$01,$07,$0F,$0F,$0F,$0F -8B20 0F07070303010000 03699 DB $0F,$07,$07,$03,$03,$01,$00,$00 -8B28 FFFFFFFFFFFFFFFF 03700 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8B30 FFFFFFFFFFFFFF3F 03701 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$3F -8B38 FFFFFFFFFFFFFFFF 03702 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8B40 0F07070707030707 03703 DB $0F,$07,$07,$07,$07,$03,$07,$07 -8B48 FFFFFFFFFFFFFFFF 03704 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8B50 FEFFFFFFFFFFFFFF 03705 DB $FE,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8B58 FFFFFFFFFFFFFFFF 03706 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8B60 000200008087C3C0 03707 DB $00,$02,$00,$00,$80,$87,$C3,$C0 -8B68 FFFDFFFFFFF8FCFF 03708 DB $FF,$FD,$FF,$FF,$FF,$F8,$FC,$FF -8B70 3000000003FFFFC0 03709 DB $30,$00,$00,$00,$03,$FF,$FF,$C0 -8B78 CFFFFFFFFC00003F 03710 DB $CF,$FF,$FF,$FF,$FC,$00,$00,$3F -8B80 00000038F0C00000 03711 DB $00,$00,$00,$38,$F0,$C0,$00,$00 -8B88 FFFFFFC70F3FFFFF 03712 DB $FF,$FF,$FF,$C7,$0F,$3F,$FF,$FF -8B90 0B03030303030307 03713 DB $0B,$03,$03,$03,$03,$03,$03,$07 -8B98 F4FCFCFCFCFCFCF8 03714 DB $F4,$FC,$FC,$FC,$FC,$FC,$FC,$F8 -8BA0 F0F0F0F0F0F0F0E8 03715 DB $F0,$F0,$F0,$F0,$F0,$F0,$F0,$E8 -8BA8 0F0F0F0F0F0F0F07 03716 DB $0F,$0F,$0F,$0F,$0F,$0F,$0F,$07 -8BB0 1F0F030000000000 03717 DB $1F,$0F,$03,$00,$00,$00,$00,$00 -8BB8 FFFFFFFFFFFFFFFF 03718 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8BC0 FFFFFFFF3F0F0703 03719 DB $FF,$FF,$FF,$FF,$3F,$0F,$07,$03 -8BC8 FFFFFFFFFFFFFFFF 03720 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8BD0 0707030707070703 03721 DB $07,$07,$03,$07,$07,$07,$07,$03 -8BD8 FFFFFFFFFFFFFFFF 03722 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8BE0 E0E0F0F4F8FAFCFE 03723 DB $E0,$E0,$F0,$F4,$F8,$FA,$FC,$FE -8BE8 FFFFFFFBFFFDFFFF 03724 DB $FF,$FF,$FF,$FB,$FF,$FD,$FF,$FF -8BF0 00000000060E1F1F 03725 DB $00,$00,$00,$00,$06,$0E,$1F,$1F -8BF8 FFFFFFFFF9F1E0E0 03726 DB $FF,$FF,$FF,$FF,$F9,$F1,$E0,$E0 -8C00 070F1F3F7FFEDEF5 03727 DB $07,$0F,$1F,$3F,$7F,$FE,$DE,$F5 -8C08 F8F0E0C08001230E 03728 DB $F8,$F0,$E0,$C0,$80,$01,$23,$0E -8C10 C8C8A8E276C0709E 03729 DB $C8,$C8,$A8,$E2,$76,$C0,$70,$9E -8C18 0707070D891B1B33 03730 DB $07,$07,$07,$0D,$89,$1B,$1B,$33 -8C20 0000000000008020 03731 DB $00,$00,$00,$00,$00,$00,$80,$20 -8C28 FFFFFFFFFFFF7F1F 03732 DB $FF,$FF,$FF,$FF,$FF,$FF,$7F,$1F -8C30 0703030703030303 03733 DB $07,$03,$03,$07,$03,$03,$03,$03 -8C38 FFFFFFFFFFFFFFFF 03734 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8C40 FFFFFFFFFFFDFCEA 03735 DB $FF,$FF,$FF,$FF,$FF,$FD,$FC,$EA -8C48 FFFFFFFFFFFEF8F0 03736 DB $FF,$FF,$FF,$FF,$FF,$FE,$F8,$F0 -8C50 FEFBE8A61C3DB27C 03737 DB $FE,$FB,$E8,$A6,$1C,$3D,$B2,$7C -8C58 FFFCF1C183030707 03738 DB $FF,$FC,$F1,$C1,$83,$03,$07,$07 -8C60 00003F3F20305050 03739 DB $00,$00,$3F,$3F,$20,$30,$50,$50 -8C68 FFFFC0C0DFCF8F8F 03740 DB $FF,$FF,$C0,$C0,$DF,$CF,$8F,$8F -8C70 3F7FF88000000103 03741 DB $3F,$7F,$F8,$80,$00,$00,$01,$03 -8C78 C080077FFFFFFFFF 03742 DB $C0,$80,$07,$7F,$FF,$FF,$FF,$FF -8C80 CF09163C6FD9F39E 03743 DB $CF,$09,$16,$3C,$6F,$D9,$F3,$9E -8C88 3CFCF8F1F1E3C7C7 03744 DB $3C,$FC,$F8,$F1,$F1,$E3,$C7,$C7 -8C90 23FC46D9DD12FA26 03745 DB $23,$FC,$46,$D9,$DD,$12,$FA,$26 -8C98 7666ECCC98B83070 03746 DB $76,$66,$EC,$CC,$98,$B8,$30,$70 -8CA0 1010060100C00000 03747 DB $10,$10,$06,$01,$00,$C0,$00,$00 -8CA8 0F0F010000000000 03748 DB $0F,$0F,$01,$00,$00,$00,$00,$00 -8CB0 0000008040201006 03749 DB $00,$00,$00,$80,$40,$20,$10,$06 -8CB8 FFFFFF7F3F1F0F01 03750 DB $FF,$FF,$FF,$7F,$3F,$1F,$0F,$01 -8CC0 0101000000000000 03751 DB $01,$01,$00,$00,$00,$00,$00,$00 -8CC8 FFFFFFFFFFFFFFFF 03752 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8CD0 FFFFFFFFFA7F173E 03753 DB $FF,$FF,$FF,$FF,$FA,$7F,$17,$3E -8CD8 FFFFFFFEFCF8F8F0 03754 DB $FF,$FF,$FF,$FE,$FC,$F8,$F8,$F0 -8CE0 C499B373E7EE5FFD 03755 DB $C4,$99,$B3,$73,$E7,$EE,$5F,$FD -8CE8 E0C0000000000000 03756 DB $E0,$C0,$00,$00,$00,$00,$00,$00 -8CF0 E4F46CE8F0406004 03757 DB $E4,$F4,$6C,$E8,$F0,$40,$60,$04 -8CF8 0F0F1F1F1F9F9F9B 03758 DB $0F,$0F,$1F,$1F,$1F,$9F,$9F,$9B -8D00 5050585858D8182A 03759 DB $50,$50,$58,$58,$58,$D8,$18,$2A -8D08 8F8F87878707C7C7 03760 DB $8F,$8F,$87,$87,$87,$07,$C7,$C7 -8D10 070F1E3F7F0B060E 03761 DB $07,$0F,$1E,$3F,$7F,$0B,$06,$0E -8D18 FFFFFFFEFCFCF8F1 03762 DB $FF,$FF,$FF,$FE,$FC,$FC,$F8,$F1 -8D20 64CE789339E36FE4 03763 DB $64,$CE,$78,$93,$39,$E3,$6F,$E4 -8D28 8E1C1D397377E6CE 03764 DB $8E,$1C,$1D,$39,$73,$77,$E6,$CE -8D30 C9E898D0226640CC 03765 DB $C9,$E8,$98,$D0,$22,$66,$40,$CC -8D38 60C0C08080000000 03766 DB $60,$C0,$C0,$80,$80,$00,$00,$00 -8D40 0000000000000000 03767 DB $00,$00,$00,$00,$00,$00,$00,$00 -8D48 0000000000000000 03768 DB $00,$00,$00,$00,$00,$00,$00,$00 -8D50 0100000000000000 03769 DB $01,$00,$00,$00,$00,$00,$00,$00 -8D58 0000000000000000 03770 DB $00,$00,$00,$00,$00,$00,$00,$00 -8D60 0040201008040600 03771 DB $00,$40,$20,$10,$08,$04,$06,$00 -8D68 FF3F1F0F07030100 03772 DB $FF,$3F,$1F,$0F,$07,$03,$01,$00 -8D70 00000000000000C0 03773 DB $00,$00,$00,$00,$00,$00,$00,$C0 -8D78 FFFFFFFFFFFFFF3F 03774 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$3F -8D80 2E2C2C3C7D757767 03775 DB $2E,$2C,$2C,$3C,$7D,$75,$77,$67 -8D88 F0F0F0E0E0E0E0F0 03776 DB $F0,$F0,$F0,$E0,$E0,$E0,$E0,$F0 -8D90 BC7EFEFEF8FDFDFF 03777 DB $BC,$7E,$FE,$FE,$F8,$FD,$FD,$FF -8D98 0101010103020200 03778 DB $01,$01,$01,$01,$03,$02,$02,$00 -8DA0 0E9A880808081113 03779 DB $0E,$9A,$88,$08,$08,$08,$11,$13 -8DA8 990D070707070F0F 03780 DB $99,$0D,$07,$07,$07,$07,$0F,$0F -8DB0 0C0C01070684D1C5 03781 DB $0C,$0C,$01,$07,$06,$84,$D1,$C5 -8DB8 E7E7FFFFFFFFEEE8 03782 DB $E7,$E7,$FF,$FF,$FF,$FF,$EE,$E8 -8DC0 0F193B7EEFCE9933 03783 DB $0F,$19,$3B,$7E,$EF,$CE,$99,$33 -8DC8 F1E3C7870E1C3C79 03784 DB $F1,$E3,$C7,$87,$0E,$1C,$3C,$79 -8DD0 9EF91B7B677ED8BF 03785 DB $9E,$F9,$1B,$7B,$67,$7E,$D8,$BF -8DD8 CC9CB83070E0E0C0 03786 DB $CC,$9C,$B8,$30,$70,$E0,$E0,$C0 -8DE0 F8F8F0C000000101 03787 DB $F8,$F8,$F0,$C0,$00,$00,$01,$01 -8DE8 0000000000000000 03788 DB $00,$00,$00,$00,$00,$00,$00,$00 -8DF0 00000000C0C0E0E0 03789 DB $00,$00,$00,$00,$C0,$C0,$E0,$E0 -8DF8 0000000000000000 03790 DB $00,$00,$00,$00,$00,$00,$00,$00 -8E00 1004000000000000 03791 DB $10,$04,$00,$00,$00,$00,$00,$00 -8E08 0F03010000000000 03792 DB $0F,$03,$01,$00,$00,$00,$00,$00 -8E10 776F4F7F3F1F7F7F 03793 DB $77,$6F,$4F,$7F,$3F,$1F,$7F,$7F -8E18 E0E0E0C0C0C08080 03794 DB $E0,$E0,$E0,$C0,$C0,$C0,$80,$80 -8E20 FFFEFEEEEEDCDC9C 03795 DB $FF,$FE,$FE,$EE,$EE,$DC,$DC,$9C -8E28 0000000000000000 03796 DB $00,$00,$00,$00,$00,$00,$00,$00 -8E30 172F2F4F4F5F9FBE 03797 DB $17,$2F,$2F,$4F,$4F,$5F,$9F,$BE -8E38 0F1F1F3F3F3F7F7F 03798 DB $0F,$1F,$1F,$3F,$3F,$3F,$7F,$7F -8E40 CECCFDBC7C7BE9FF 03799 DB $CE,$CC,$FD,$BC,$7C,$7B,$E9,$FF -8E48 E0E1C3C380801C1C 03800 DB $E0,$E1,$C3,$C3,$80,$80,$1C,$1C -8E50 7CCEBFFFFFFFFFFF 03801 DB $7C,$CE,$BF,$FF,$FF,$FF,$FF,$FF -8E58 F3E0C00000000000 03802 DB $F3,$E0,$C0,$00,$00,$00,$00,$00 -8E60 BFFFEFFFFFFFFFFF 03803 DB $BF,$FF,$EF,$FF,$FF,$FF,$FF,$FF -8E68 0000000000000000 03804 DB $00,$00,$00,$00,$00,$00,$00,$00 -8E70 81E1F9F9F9FBF3E3 03805 DB $81,$E1,$F9,$F9,$F9,$FB,$F3,$E3 -8E78 0000000000000000 03806 DB $00,$00,$00,$00,$00,$00,$00,$00 -8E80 F0F0F0F8F8F8FCFC 03807 DB $F0,$F0,$F0,$F8,$F8,$F8,$FC,$FC -8E88 0000000000000000 03808 DB $00,$00,$00,$00,$00,$00,$00,$00 -8E90 00010200041E0F3F 03809 DB $00,$01,$02,$00,$04,$1E,$0F,$3F -8E98 000001070F0F1F1F 03810 DB $00,$00,$01,$07,$0F,$0F,$1F,$1F -8EA0 0000000001010203 03811 DB $00,$00,$00,$00,$01,$01,$02,$03 -8EA8 FFFFFFFFFEFEFCFC 03812 DB $FF,$FF,$FF,$FF,$FE,$FE,$FC,$FC -8EB0 7FFFFFFFFFFFFEFE 03813 DB $7F,$FF,$FF,$FF,$FF,$FF,$FE,$FE -8EB8 8000000000000000 03814 DB $80,$00,$00,$00,$00,$00,$00,$00 -8EC0 B9F9FAF2F4F4E8CD 03815 DB $B9,$F9,$FA,$F2,$F4,$F4,$E8,$CD -8EC8 0000010103030703 03816 DB $00,$00,$01,$01,$03,$03,$07,$03 -8ED0 78724F9D3D7DF3F3 03817 DB $78,$72,$4F,$9D,$3D,$7D,$F3,$F3 -8ED8 FFFFFEFEFEFEFCFC 03818 DB $FF,$FF,$FE,$FE,$FE,$FE,$FC,$FC -8EE0 FFF5F7FFFFFFFFFF 03819 DB $FF,$F5,$F7,$FF,$FF,$FF,$FF,$FF -8EE8 1C08000000000000 03820 DB $1C,$08,$00,$00,$00,$00,$00,$00 -8EF0 FFFFFFF7E7EFCF9F 03821 DB $FF,$FF,$FF,$F7,$E7,$EF,$CF,$9F -8EF8 0000000000000000 03822 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F00 FFFFFFFFFFFFFFFF 03823 DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF -8F08 0000000000000000 03824 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F10 E3C7C7C7C7CF8F8F 03825 DB $E3,$C7,$C7,$C7,$C7,$CF,$8F,$8F -8F18 0000000000000000 03826 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F20 FEFEFFFFFFFFFFFF 03827 DB $FE,$FE,$FF,$FF,$FF,$FF,$FF,$FF -8F28 0000000000000000 03828 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F30 00000000808080C0 03829 DB $00,$00,$00,$00,$80,$80,$80,$C0 -8F38 0000000000000000 03830 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F40 000000000020212C 03831 DB $00,$00,$00,$00,$00,$20,$21,$2C -8F48 0000000000000001 03832 DB $00,$00,$00,$00,$00,$00,$00,$01 -8F50 1F7D3DF97979F3F3 03833 DB $1F,$7D,$3D,$F9,$79,$79,$F3,$F3 -8F58 3F3F7F7FFFFFFFFF 03834 DB $3F,$3F,$7F,$7F,$FF,$FF,$FF,$FF -8F60 0000000000000000 03835 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F68 0000000000000000 03836 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F70 0000000000000000 03837 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F78 0000000000000000 03838 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F80 0000000000000000 03839 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F88 0000000000000000 03840 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F90 0000000000000000 03841 DB $00,$00,$00,$00,$00,$00,$00,$00 -8F98 0000000000000000 03842 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FA0 0000000000000000 03843 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FA8 0000000000000000 03844 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FB0 0000000000000000 03845 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FB8 0000000000000000 03846 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FC0 0000000000000000 03847 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FC8 0000000000000000 03848 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FD0 0000000000000000 03849 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FD8 0000000000000000 03850 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FE0 0000000000000000 03851 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FE8 0000000000000000 03852 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FF0 0000000000000000 03853 DB $00,$00,$00,$00,$00,$00,$00,$00 -8FF8 0000000000000000 03854 DB $00,$00,$00,$00,$00,$00,$00,$00 -9000 0000000000000000 03855 DB $00,$00,$00,$00,$00,$00,$00,$00 -9008 0000000000000000 03856 DB $00,$00,$00,$00,$00,$00,$00,$00 -9010 0000000000000000 03857 DB $00,$00,$00,$00,$00,$00,$00,$00 -9018 0000000000000000 03858 DB $00,$00,$00,$00,$00,$00,$00,$00 -9020 0000000000000000 03859 DB $00,$00,$00,$00,$00,$00,$00,$00 -9028 0000000000000000 03860 DB $00,$00,$00,$00,$00,$00,$00,$00 -9030 0000000000000000 03861 DB $00,$00,$00,$00,$00,$00,$00,$00 -9038 0000000000000000 03862 DB $00,$00,$00,$00,$00,$00,$00,$00 -9040 0000000000000000 03863 DB $00,$00,$00,$00,$00,$00,$00,$00 -9048 0000000000000000 03864 DB $00,$00,$00,$00,$00,$00,$00,$00 -9050 0000000000000000 03865 DB $00,$00,$00,$00,$00,$00,$00,$00 -9058 0000000000000000 03866 DB $00,$00,$00,$00,$00,$00,$00,$00 -9060 0000000000000000 03867 DB $00,$00,$00,$00,$00,$00,$00,$00 -9068 0000000000000000 03868 DB $00,$00,$00,$00,$00,$00,$00,$00 -9070 0000000000000000 03869 DB $00,$00,$00,$00,$00,$00,$00,$00 -9078 0000000000000000 03870 DB $00,$00,$00,$00,$00,$00,$00,$00 -9080 0000000000000000 03871 DB $00,$00,$00,$00,$00,$00,$00,$00 -9088 0000000000000000 03872 DB $00,$00,$00,$00,$00,$00,$00,$00 -9090 0000000000000000 03873 DB $00,$00,$00,$00,$00,$00,$00,$00 -9098 0000000000000000 03874 DB $00,$00,$00,$00,$00,$00,$00,$00 -90A0 0000000000000000 03875 DB $00,$00,$00,$00,$00,$00,$00,$00 -90A8 0000000000000000 03876 DB $00,$00,$00,$00,$00,$00,$00,$00 -90B0 0000000000000000 03877 DB $00,$00,$00,$00,$00,$00,$00,$00 -90B8 0000000000000000 03878 DB $00,$00,$00,$00,$00,$00,$00,$00 -90C0 0000000000000000 03879 DB $00,$00,$00,$00,$00,$00,$00,$00 -90C8 0000000000000000 03880 DB $00,$00,$00,$00,$00,$00,$00,$00 -90D0 0000000000000000 03881 DB $00,$00,$00,$00,$00,$00,$00,$00 -90D8 0000000000000000 03882 DB $00,$00,$00,$00,$00,$00,$00,$00 -90E0 0000000000000000 03883 DB $00,$00,$00,$00,$00,$00,$00,$00 -90E8 0000000000000000 03884 DB $00,$00,$00,$00,$00,$00,$00,$00 -90F0 0000000000000000 03885 DB $00,$00,$00,$00,$00,$00,$00,$00 -90F8 0000000000000000 03886 DB $00,$00,$00,$00,$00,$00,$00,$00 -9100 0000000000000000 03887 DB $00,$00,$00,$00,$00,$00,$00,$00 -9108 0000000000000000 03888 DB $00,$00,$00,$00,$00,$00,$00,$00 -9110 0000000000000000 03889 DB $00,$00,$00,$00,$00,$00,$00,$00 -9118 0000000000000000 03890 DB $00,$00,$00,$00,$00,$00,$00,$00 -9120 0000000000000000 03891 DB $00,$00,$00,$00,$00,$00,$00,$00 -9128 0000000000000000 03892 DB $00,$00,$00,$00,$00,$00,$00,$00 -9130 0000000000000000 03893 DB $00,$00,$00,$00,$00,$00,$00,$00 -9138 0000000000000000 03894 DB $00,$00,$00,$00,$00,$00,$00,$00 -9140 0000000000000000 03895 DB $00,$00,$00,$00,$00,$00,$00,$00 -9148 0000000000000000 03896 DB $00,$00,$00,$00,$00,$00,$00,$00 -9150 0000000000000000 03897 DB $00,$00,$00,$00,$00,$00,$00,$00 -9158 0000000000000000 03898 DB $00,$00,$00,$00,$00,$00,$00,$00 -9160 0000000000000000 03899 DB $00,$00,$00,$00,$00,$00,$00,$00 -9168 0000000000000000 03900 DB $00,$00,$00,$00,$00,$00,$00,$00 -9170 0000000000000000 03901 DB $00,$00,$00,$00,$00,$00,$00,$00 -9178 0000000000000000 03902 DB $00,$00,$00,$00,$00,$00,$00,$00 -9180 0000000000000000 03903 DB $00,$00,$00,$00,$00,$00,$00,$00 -9188 0000000000000000 03904 DB $00,$00,$00,$00,$00,$00,$00,$00 -9190 0000000000000000 03905 DB $00,$00,$00,$00,$00,$00,$00,$00 -9198 0000000000000000 03906 DB $00,$00,$00,$00,$00,$00,$00,$00 -91A0 0000000000000000 03907 DB $00,$00,$00,$00,$00,$00,$00,$00 -91A8 0000000000000000 03908 DB $00,$00,$00,$00,$00,$00,$00,$00 -91B0 0000000000000000 03909 DB $00,$00,$00,$00,$00,$00,$00,$00 -91B8 0000000000000000 03910 DB $00,$00,$00,$00,$00,$00,$00,$00 -91C0 0000000000000000 03911 DB $00,$00,$00,$00,$00,$00,$00,$00 -91C8 0000000000000000 03912 DB $00,$00,$00,$00,$00,$00,$00,$00 -91D0 0000000000000000 03913 DB $00,$00,$00,$00,$00,$00,$00,$00 -91D8 0000000000000000 03914 DB $00,$00,$00,$00,$00,$00,$00,$00 -91E0 0000000000000000 03915 DB $00,$00,$00,$00,$00,$00,$00,$00 -91E8 0000000000000000 03916 DB $00,$00,$00,$00,$00,$00,$00,$00 -91F0 0000000000000000 03917 DB $00,$00,$00,$00,$00,$00,$00,$00 -91F8 0000000000000000 03918 DB $00,$00,$00,$00,$00,$00,$00,$00 -9200 0000000000000000 03919 DB $00,$00,$00,$00,$00,$00,$00,$00 -9208 0000000000000000 03920 DB $00,$00,$00,$00,$00,$00,$00,$00 -9210 0000000000000000 03921 DB $00,$00,$00,$00,$00,$00,$00,$00 -9218 0000000000000000 03922 DB $00,$00,$00,$00,$00,$00,$00,$00 -9220 0000000000000000 03923 DB $00,$00,$00,$00,$00,$00,$00,$00 -9228 0000000000000000 03924 DB $00,$00,$00,$00,$00,$00,$00,$00 -9230 0000000000000000 03925 DB $00,$00,$00,$00,$00,$00,$00,$00 -9238 0000000000000000 03926 DB $00,$00,$00,$00,$00,$00,$00,$00 -9240 0000000000000000 03927 DB $00,$00,$00,$00,$00,$00,$00,$00 -9248 0000000000000000 03928 DB $00,$00,$00,$00,$00,$00,$00,$00 -9250 0000000000000000 03929 DB $00,$00,$00,$00,$00,$00,$00,$00 -9258 0000000000000000 03930 DB $00,$00,$00,$00,$00,$00,$00,$00 -9260 0000000000000000 03931 DB $00,$00,$00,$00,$00,$00,$00,$00 -9268 0000000000000000 03932 DB $00,$00,$00,$00,$00,$00,$00,$00 -9270 0000000000000000 03933 DB $00,$00,$00,$00,$00,$00,$00,$00 -9278 0000000000000000 03934 DB $00,$00,$00,$00,$00,$00,$00,$00 -9280 0000000000000000 03935 DB $00,$00,$00,$00,$00,$00,$00,$00 -9288 0000000000000000 03936 DB $00,$00,$00,$00,$00,$00,$00,$00 -9290 0000000000000000 03937 DB $00,$00,$00,$00,$00,$00,$00,$00 -9298 0000000000000000 03938 DB $00,$00,$00,$00,$00,$00,$00,$00 -92A0 0000000000000000 03939 DB $00,$00,$00,$00,$00,$00,$00,$00 -92A8 0000000000000000 03940 DB $00,$00,$00,$00,$00,$00,$00,$00 -92B0 0000000000000000 03941 DB $00,$00,$00,$00,$00,$00,$00,$00 -92B8 0000000000000000 03942 DB $00,$00,$00,$00,$00,$00,$00,$00 -92C0 0000000000000000 03943 DB $00,$00,$00,$00,$00,$00,$00,$00 -92C8 0000000000000000 03944 DB $00,$00,$00,$00,$00,$00,$00,$00 -92D0 0000000000000000 03945 DB $00,$00,$00,$00,$00,$00,$00,$00 -92D8 0000000000000000 03946 DB $00,$00,$00,$00,$00,$00,$00,$00 -92E0 0000000000000000 03947 DB $00,$00,$00,$00,$00,$00,$00,$00 -92E8 0000000000000000 03948 DB $00,$00,$00,$00,$00,$00,$00,$00 -92F0 0000000000000000 03949 DB $00,$00,$00,$00,$00,$00,$00,$00 -92F8 0000000000000000 03950 DB $00,$00,$00,$00,$00,$00,$00,$00 -9300 0000000000000000 03951 DB $00,$00,$00,$00,$00,$00,$00,$00 -9308 0000000000000000 03952 DB $00,$00,$00,$00,$00,$00,$00,$00 -9310 0000000000000000 03953 DB $00,$00,$00,$00,$00,$00,$00,$00 -9318 0000000000000000 03954 DB $00,$00,$00,$00,$00,$00,$00,$00 -9320 0000000000000000 03955 DB $00,$00,$00,$00,$00,$00,$00,$00 -9328 0000000000000000 03956 DB $00,$00,$00,$00,$00,$00,$00,$00 -9330 0000000000000000 03957 DB $00,$00,$00,$00,$00,$00,$00,$00 -9338 0000000000000000 03958 DB $00,$00,$00,$00,$00,$00,$00,$00 -9340 0000000000000000 03959 DB $00,$00,$00,$00,$00,$00,$00,$00 -9348 0000000000000000 03960 DB $00,$00,$00,$00,$00,$00,$00,$00 -9350 0000000000000000 03961 DB $00,$00,$00,$00,$00,$00,$00,$00 -9358 0000000000000000 03962 DB $00,$00,$00,$00,$00,$00,$00,$00 -9360 0000000000000000 03963 DB $00,$00,$00,$00,$00,$00,$00,$00 -9368 0000000000000000 03964 DB $00,$00,$00,$00,$00,$00,$00,$00 -9370 0000000000000000 03965 DB $00,$00,$00,$00,$00,$00,$00,$00 -9378 0000000000000000 03966 DB $00,$00,$00,$00,$00,$00,$00,$00 -9380 0000000000000000 03967 DB $00,$00,$00,$00,$00,$00,$00,$00 -9388 0000000000000000 03968 DB $00,$00,$00,$00,$00,$00,$00,$00 -9390 0000000000000000 03969 DB $00,$00,$00,$00,$00,$00,$00,$00 -9398 0000000000000000 03970 DB $00,$00,$00,$00,$00,$00,$00,$00 -93A0 0000000000000000 03971 DB $00,$00,$00,$00,$00,$00,$00,$00 -93A8 0000000000000000 03972 DB $00,$00,$00,$00,$00,$00,$00,$00 -93B0 0000000000000000 03973 DB $00,$00,$00,$00,$00,$00,$00,$00 -93B8 0000000000000000 03974 DB $00,$00,$00,$00,$00,$00,$00,$00 -93C0 0000000000000000 03975 DB $00,$00,$00,$00,$00,$00,$00,$00 -93C8 0000000000000000 03976 DB $00,$00,$00,$00,$00,$00,$00,$00 -93D0 0000000000000000 03977 DB $00,$00,$00,$00,$00,$00,$00,$00 -93D8 0000000000000000 03978 DB $00,$00,$00,$00,$00,$00,$00,$00 -93E0 0000000000000000 03979 DB $00,$00,$00,$00,$00,$00,$00,$00 -93E8 0000000000000000 03980 DB $00,$00,$00,$00,$00,$00,$00,$00 -93F0 0000000000000000 03981 DB $00,$00,$00,$00,$00,$00,$00,$00 -93F8 0000000000000000 03982 DB $00,$00,$00,$00,$00,$00,$00,$00 -9400 0000000000000000 03983 DB $00,$00,$00,$00,$00,$00,$00,$00 -9408 0000000000000000 03984 DB $00,$00,$00,$00,$00,$00,$00,$00 -9410 0000000000000000 03985 DB $00,$00,$00,$00,$00,$00,$00,$00 -9418 0000000000000000 03986 DB $00,$00,$00,$00,$00,$00,$00,$00 -9420 0000000000000000 03987 DB $00,$00,$00,$00,$00,$00,$00,$00 -9428 0000000000000000 03988 DB $00,$00,$00,$00,$00,$00,$00,$00 -9430 0000000000000000 03989 DB $00,$00,$00,$00,$00,$00,$00,$00 -9438 0000000000000000 03990 DB $00,$00,$00,$00,$00,$00,$00,$00 -9440 0000000000000000 03991 DB $00,$00,$00,$00,$00,$00,$00,$00 -9448 0000000000000000 03992 DB $00,$00,$00,$00,$00,$00,$00,$00 -9450 0000000000000000 03993 DB $00,$00,$00,$00,$00,$00,$00,$00 -9458 0000000000000000 03994 DB $00,$00,$00,$00,$00,$00,$00,$00 -9460 0000000000000000 03995 DB $00,$00,$00,$00,$00,$00,$00,$00 -9468 0000000000000000 03996 DB $00,$00,$00,$00,$00,$00,$00,$00 -9470 0000000000000000 03997 DB $00,$00,$00,$00,$00,$00,$00,$00 -9478 0000000000000000 03998 DB $00,$00,$00,$00,$00,$00,$00,$00 -9480 0000000000000000 03999 DB $00,$00,$00,$00,$00,$00,$00,$00 -9488 0000000000000000 04000 DB $00,$00,$00,$00,$00,$00,$00,$00 -9490 0000000000000000 04001 DB $00,$00,$00,$00,$00,$00,$00,$00 -9498 0000000000000000 04002 DB $00,$00,$00,$00,$00,$00,$00,$00 -94A0 0000000000000000 04003 DB $00,$00,$00,$00,$00,$00,$00,$00 -94A8 0000000000000000 04004 DB $00,$00,$00,$00,$00,$00,$00,$00 -94B0 0000000000000000 04005 DB $00,$00,$00,$00,$00,$00,$00,$00 -94B8 0000000000000000 04006 DB $00,$00,$00,$00,$00,$00,$00,$00 -94C0 0000000000000000 04007 DB $00,$00,$00,$00,$00,$00,$00,$00 -94C8 0000000000000000 04008 DB $00,$00,$00,$00,$00,$00,$00,$00 -94D0 0000000000000000 04009 DB $00,$00,$00,$00,$00,$00,$00,$00 -94D8 0000000000000000 04010 DB $00,$00,$00,$00,$00,$00,$00,$00 -94E0 0000000000000000 04011 DB $00,$00,$00,$00,$00,$00,$00,$00 -94E8 0000000000000000 04012 DB $00,$00,$00,$00,$00,$00,$00,$00 -94F0 0000000000000000 04013 DB $00,$00,$00,$00,$00,$00,$00,$00 -94F8 0000000000000000 04014 DB $00,$00,$00,$00,$00,$00,$00,$00 -9500 0000000000000000 04015 DB $00,$00,$00,$00,$00,$00,$00,$00 -9508 0000000000000000 04016 DB $00,$00,$00,$00,$00,$00,$00,$00 -9510 0000000000000000 04017 DB $00,$00,$00,$00,$00,$00,$00,$00 -9518 0000000000000000 04018 DB $00,$00,$00,$00,$00,$00,$00,$00 -9520 0000000000000000 04019 DB $00,$00,$00,$00,$00,$00,$00,$00 -9528 0000000000000000 04020 DB $00,$00,$00,$00,$00,$00,$00,$00 -9530 0000000000000000 04021 DB $00,$00,$00,$00,$00,$00,$00,$00 -9538 0000000000000000 04022 DB $00,$00,$00,$00,$00,$00,$00,$00 -9540 0000000000000000 04023 DB $00,$00,$00,$00,$00,$00,$00,$00 -9548 0000000000000000 04024 DB $00,$00,$00,$00,$00,$00,$00,$00 -9550 0000000000000000 04025 DB $00,$00,$00,$00,$00,$00,$00,$00 -9558 0000000000000000 04026 DB $00,$00,$00,$00,$00,$00,$00,$00 -9560 0000000000000000 04027 DB $00,$00,$00,$00,$00,$00,$00,$00 -9568 0000000000000000 04028 DB $00,$00,$00,$00,$00,$00,$00,$00 -9570 0000000000000000 04029 DB $00,$00,$00,$00,$00,$00,$00,$00 -9578 0000000000000000 04030 DB $00,$00,$00,$00,$00,$00,$00,$00 -9580 0000000000000000 04031 DB $00,$00,$00,$00,$00,$00,$00,$00 -9588 0000000000000000 04032 DB $00,$00,$00,$00,$00,$00,$00,$00 -9590 0000000000000000 04033 DB $00,$00,$00,$00,$00,$00,$00,$00 -9598 0000000000000000 04034 DB $00,$00,$00,$00,$00,$00,$00,$00 -95A0 0000000000000000 04035 DB $00,$00,$00,$00,$00,$00,$00,$00 -95A8 0000000000000000 04036 DB $00,$00,$00,$00,$00,$00,$00,$00 -95B0 0000000000000000 04037 DB $00,$00,$00,$00,$00,$00,$00,$00 -95B8 0000000000000000 04038 DB $00,$00,$00,$00,$00,$00,$00,$00 -95C0 0000000000000000 04039 DB $00,$00,$00,$00,$00,$00,$00,$00 -95C8 0000000000000000 04040 DB $00,$00,$00,$00,$00,$00,$00,$00 -95D0 0000000000000000 04041 DB $00,$00,$00,$00,$00,$00,$00,$00 -95D8 0000000000000000 04042 DB $00,$00,$00,$00,$00,$00,$00,$00 -95E0 0000000000000000 04043 DB $00,$00,$00,$00,$00,$00,$00,$00 -95E8 0000000000000000 04044 DB $00,$00,$00,$00,$00,$00,$00,$00 -95F0 0000000000000000 04045 DB $00,$00,$00,$00,$00,$00,$00,$00 -95F8 0000000000000000 04046 DB $00,$00,$00,$00,$00,$00,$00,$00 -9600 0000000000000000 04047 DB $00,$00,$00,$00,$00,$00,$00,$00 -9608 0000000000000000 04048 DB $00,$00,$00,$00,$00,$00,$00,$00 -9610 0000000000000000 04049 DB $00,$00,$00,$00,$00,$00,$00,$00 -9618 0000000000000000 04050 DB $00,$00,$00,$00,$00,$00,$00,$00 -9620 0000000000000000 04051 DB $00,$00,$00,$00,$00,$00,$00,$00 -9628 0000000000000000 04052 DB $00,$00,$00,$00,$00,$00,$00,$00 -9630 0000000000000000 04053 DB $00,$00,$00,$00,$00,$00,$00,$00 -9638 0000000000000000 04054 DB $00,$00,$00,$00,$00,$00,$00,$00 -9640 0000000000000000 04055 DB $00,$00,$00,$00,$00,$00,$00,$00 -9648 0000000000000000 04056 DB $00,$00,$00,$00,$00,$00,$00,$00 -9650 0000000000000000 04057 DB $00,$00,$00,$00,$00,$00,$00,$00 -9658 0000000000000000 04058 DB $00,$00,$00,$00,$00,$00,$00,$00 -9660 0000000000000000 04059 DB $00,$00,$00,$00,$00,$00,$00,$00 -9668 0000000000000000 04060 DB $00,$00,$00,$00,$00,$00,$00,$00 -9670 0000000000000000 04061 DB $00,$00,$00,$00,$00,$00,$00,$00 -9678 0000000000000000 04062 DB $00,$00,$00,$00,$00,$00,$00,$00 -9680 0000000000000000 04063 DB $00,$00,$00,$00,$00,$00,$00,$00 -9688 0000000000000000 04064 DB $00,$00,$00,$00,$00,$00,$00,$00 -9690 0000000000000000 04065 DB $00,$00,$00,$00,$00,$00,$00,$00 -9698 0000000000000000 04066 DB $00,$00,$00,$00,$00,$00,$00,$00 -96A0 0000000000000000 04067 DB $00,$00,$00,$00,$00,$00,$00,$00 -96A8 0000000000000000 04068 DB $00,$00,$00,$00,$00,$00,$00,$00 -96B0 0000000000000000 04069 DB $00,$00,$00,$00,$00,$00,$00,$00 -96B8 0000000000000000 04070 DB $00,$00,$00,$00,$00,$00,$00,$00 -96C0 0000000000000000 04071 DB $00,$00,$00,$00,$00,$00,$00,$00 -96C8 0000000000000000 04072 DB $00,$00,$00,$00,$00,$00,$00,$00 -96D0 0000000000000000 04073 DB $00,$00,$00,$00,$00,$00,$00,$00 -96D8 0000000000000000 04074 DB $00,$00,$00,$00,$00,$00,$00,$00 -96E0 0000000000000000 04075 DB $00,$00,$00,$00,$00,$00,$00,$00 -96E8 0000000000000000 04076 DB $00,$00,$00,$00,$00,$00,$00,$00 -96F0 0000000000000000 04077 DB $00,$00,$00,$00,$00,$00,$00,$00 -96F8 0000000000000000 04078 DB $00,$00,$00,$00,$00,$00,$00,$00 -9700 0000000000000000 04079 DB $00,$00,$00,$00,$00,$00,$00,$00 -9708 0000000000000000 04080 DB $00,$00,$00,$00,$00,$00,$00,$00 -9710 0000000000000000 04081 DB $00,$00,$00,$00,$00,$00,$00,$00 -9718 0000000000000000 04082 DB $00,$00,$00,$00,$00,$00,$00,$00 -9720 0000000000000000 04083 DB $00,$00,$00,$00,$00,$00,$00,$00 -9728 0000000000000000 04084 DB $00,$00,$00,$00,$00,$00,$00,$00 -9730 0000000000000000 04085 DB $00,$00,$00,$00,$00,$00,$00,$00 -9738 0000000000000000 04086 DB $00,$00,$00,$00,$00,$00,$00,$00 -9740 0000000000000000 04087 DB $00,$00,$00,$00,$00,$00,$00,$00 -9748 0000000000000000 04088 DB $00,$00,$00,$00,$00,$00,$00,$00 -9750 0000000000000000 04089 DB $00,$00,$00,$00,$00,$00,$00,$00 -9758 0000000000000000 04090 DB $00,$00,$00,$00,$00,$00,$00,$00 -9760 0000000000000000 04091 DB $00,$00,$00,$00,$00,$00,$00,$00 -9768 0000000000000000 04092 DB $00,$00,$00,$00,$00,$00,$00,$00 -9770 0000000000000000 04093 DB $00,$00,$00,$00,$00,$00,$00,$00 -9778 0000000000000000 04094 DB $00,$00,$00,$00,$00,$00,$00,$00 -9780 0000000000000000 04095 DB $00,$00,$00,$00,$00,$00,$00,$00 -9788 0000000000000000 04096 DB $00,$00,$00,$00,$00,$00,$00,$00 -9790 0000000000000000 04097 DB $00,$00,$00,$00,$00,$00,$00,$00 -9798 0000000000000000 04098 DB $00,$00,$00,$00,$00,$00,$00,$00 -97A0 0000000000000000 04099 DB $00,$00,$00,$00,$00,$00,$00,$00 -97A8 0000000000000000 04100 DB $00,$00,$00,$00,$00,$00,$00,$00 -97B0 0000000000000000 04101 DB $00,$00,$00,$00,$00,$00,$00,$00 -97B8 0000000000000000 04102 DB $00,$00,$00,$00,$00,$00,$00,$00 -97C0 0000000000000000 04103 DB $00,$00,$00,$00,$00,$00,$00,$00 -97C8 0000000000000000 04104 DB $00,$00,$00,$00,$00,$00,$00,$00 -97D0 0000000000000000 04105 DB $00,$00,$00,$00,$00,$00,$00,$00 -97D8 0000000000000000 04106 DB $00,$00,$00,$00,$00,$00,$00,$00 -97E0 0000000000000000 04107 DB $00,$00,$00,$00,$00,$00,$00,$00 -97E8 0000000000000000 04108 DB $00,$00,$00,$00,$00,$00,$00,$00 -97F0 0000000000000000 04109 DB $00,$00,$00,$00,$00,$00,$00,$00 -97F8 0000000000000000 04110 DB $00,$00,$00,$00,$00,$00,$00,$00 -9800 0000000000000000 04111 DB $00,$00,$00,$00,$00,$00,$00,$00 -9808 0000000000000000 04112 DB $00,$00,$00,$00,$00,$00,$00,$00 -9810 0000000000000000 04113 DB $00,$00,$00,$00,$00,$00,$00,$00 -9818 0000000000000000 04114 DB $00,$00,$00,$00,$00,$00,$00,$00 -9820 0000000000000000 04115 DB $00,$00,$00,$00,$00,$00,$00,$00 -9828 0000000000000000 04116 DB $00,$00,$00,$00,$00,$00,$00,$00 -9830 0000000000000000 04117 DB $00,$00,$00,$00,$00,$00,$00,$00 -9838 0000000000000000 04118 DB $00,$00,$00,$00,$00,$00,$00,$00 -9840 0000000000000000 04119 DB $00,$00,$00,$00,$00,$00,$00,$00 -9848 0000000000000000 04120 DB $00,$00,$00,$00,$00,$00,$00,$00 -9850 0000000000000000 04121 DB $00,$00,$00,$00,$00,$00,$00,$00 -9858 0000000000000000 04122 DB $00,$00,$00,$00,$00,$00,$00,$00 -9860 0000000000000000 04123 DB $00,$00,$00,$00,$00,$00,$00,$00 -9868 0000000000000000 04124 DB $00,$00,$00,$00,$00,$00,$00,$00 -9870 0000000000000000 04125 DB $00,$00,$00,$00,$00,$00,$00,$00 -9878 0000000000000000 04126 DB $00,$00,$00,$00,$00,$00,$00,$00 -9880 0000000000000000 04127 DB $00,$00,$00,$00,$00,$00,$00,$00 -9888 0000000000000000 04128 DB $00,$00,$00,$00,$00,$00,$00,$00 -9890 0000000000000000 04129 DB $00,$00,$00,$00,$00,$00,$00,$00 -9898 0000000000000000 04130 DB $00,$00,$00,$00,$00,$00,$00,$00 -98A0 0000000000000000 04131 DB $00,$00,$00,$00,$00,$00,$00,$00 -98A8 0000000000000000 04132 DB $00,$00,$00,$00,$00,$00,$00,$00 -98B0 0000000000000000 04133 DB $00,$00,$00,$00,$00,$00,$00,$00 -98B8 0000000000000000 04134 DB $00,$00,$00,$00,$00,$00,$00,$00 -98C0 0000000000000000 04135 DB $00,$00,$00,$00,$00,$00,$00,$00 -98C8 0000000000000000 04136 DB $00,$00,$00,$00,$00,$00,$00,$00 -98D0 0000000000000000 04137 DB $00,$00,$00,$00,$00,$00,$00,$00 -98D8 0000000000000000 04138 DB $00,$00,$00,$00,$00,$00,$00,$00 -98E0 0000000000000000 04139 DB $00,$00,$00,$00,$00,$00,$00,$00 -98E8 0000000000000000 04140 DB $00,$00,$00,$00,$00,$00,$00,$00 -98F0 0000000000000000 04141 DB $00,$00,$00,$00,$00,$00,$00,$00 -98F8 0000000000000000 04142 DB $00,$00,$00,$00,$00,$00,$00,$00 -9900 0000000000000000 04143 DB $00,$00,$00,$00,$00,$00,$00,$00 -9908 0000000000000000 04144 DB $00,$00,$00,$00,$00,$00,$00,$00 -9910 0000000000000000 04145 DB $00,$00,$00,$00,$00,$00,$00,$00 -9918 0000000000000000 04146 DB $00,$00,$00,$00,$00,$00,$00,$00 -9920 0000000000000000 04147 DB $00,$00,$00,$00,$00,$00,$00,$00 -9928 0000000000000000 04148 DB $00,$00,$00,$00,$00,$00,$00,$00 -9930 0000000000000000 04149 DB $00,$00,$00,$00,$00,$00,$00,$00 -9938 0000000000000000 04150 DB $00,$00,$00,$00,$00,$00,$00,$00 -9940 0000000000000000 04151 DB $00,$00,$00,$00,$00,$00,$00,$00 -9948 0000000000000000 04152 DB $00,$00,$00,$00,$00,$00,$00,$00 -9950 0000000000000000 04153 DB $00,$00,$00,$00,$00,$00,$00,$00 -9958 0000000000000000 04154 DB $00,$00,$00,$00,$00,$00,$00,$00 -9960 0000000000000000 04155 DB $00,$00,$00,$00,$00,$00,$00,$00 -9968 0000000000000000 04156 DB $00,$00,$00,$00,$00,$00,$00,$00 -9970 0000000000000000 04157 DB $00,$00,$00,$00,$00,$00,$00,$00 -9978 0000000000000000 04158 DB $00,$00,$00,$00,$00,$00,$00,$00 -9980 0000000000000000 04159 DB $00,$00,$00,$00,$00,$00,$00,$00 -9988 0000000000000000 04160 DB $00,$00,$00,$00,$00,$00,$00,$00 -9990 0000000000000000 04161 DB $00,$00,$00,$00,$00,$00,$00,$00 -9998 0000000000000000 04162 DB $00,$00,$00,$00,$00,$00,$00,$00 -99A0 0000000000000000 04163 DB $00,$00,$00,$00,$00,$00,$00,$00 -99A8 0000000000000000 04164 DB $00,$00,$00,$00,$00,$00,$00,$00 -99B0 0000000000000000 04165 DB $00,$00,$00,$00,$00,$00,$00,$00 -99B8 0000000000000000 04166 DB $00,$00,$00,$00,$00,$00,$00,$00 -99C0 0000000000000000 04167 DB $00,$00,$00,$00,$00,$00,$00,$00 -99C8 0000000000000000 04168 DB $00,$00,$00,$00,$00,$00,$00,$00 -99D0 0000000000000000 04169 DB $00,$00,$00,$00,$00,$00,$00,$00 -99D8 0000000000000000 04170 DB $00,$00,$00,$00,$00,$00,$00,$00 -99E0 0000000000000000 04171 DB $00,$00,$00,$00,$00,$00,$00,$00 -99E8 0000000000000000 04172 DB $00,$00,$00,$00,$00,$00,$00,$00 -99F0 0000000000000000 04173 DB $00,$00,$00,$00,$00,$00,$00,$00 -99F8 0000000000000000 04174 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A00 0000000000000000 04175 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A08 0000000000000000 04176 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A10 0000000000000000 04177 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A18 0000000000000000 04178 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A20 0000000000000000 04179 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A28 0000000000000000 04180 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A30 0000000000000000 04181 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A38 0000000000000000 04182 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A40 0000000000000000 04183 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A48 0000000000000000 04184 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A50 0000000000000000 04185 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A58 0000000000000000 04186 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A60 0000000000000000 04187 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A68 0000000000000000 04188 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A70 0000000000000000 04189 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A78 0000000000000000 04190 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A80 0000000000000000 04191 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A88 0000000000000000 04192 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A90 0000000000000000 04193 DB $00,$00,$00,$00,$00,$00,$00,$00 -9A98 0000000000000000 04194 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AA0 0000000000000000 04195 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AA8 0000000000000000 04196 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AB0 0000000000000000 04197 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AB8 0000000000000000 04198 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AC0 0000000000000000 04199 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AC8 0000000000000000 04200 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AD0 0000000000000000 04201 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AD8 0000000000000000 04202 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AE0 0000000000000000 04203 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AE8 0000000000000000 04204 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AF0 0000000000000000 04205 DB $00,$00,$00,$00,$00,$00,$00,$00 -9AF8 0000000000000000 04206 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B00 0000000000000000 04207 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B08 0000000000000000 04208 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B10 0000000000000000 04209 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B18 0000000000000000 04210 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B20 0000000000000000 04211 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B28 0000000000000000 04212 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B30 0000000000000000 04213 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B38 0000000000000000 04214 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B40 0000000000000000 04215 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B48 0000000000000000 04216 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B50 0000000000000000 04217 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B58 0000000000000000 04218 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B60 0000000000000000 04219 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B68 0000000000000000 04220 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B70 0000000000000000 04221 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B78 0000000000000000 04222 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B80 0000000000000000 04223 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B88 0000000000000000 04224 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B90 0000000000000000 04225 DB $00,$00,$00,$00,$00,$00,$00,$00 -9B98 0000000000000000 04226 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BA0 0000000000000000 04227 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BA8 0000000000000000 04228 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BB0 0000000000000000 04229 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BB8 0000000000000000 04230 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BC0 0000000000000000 04231 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BC8 0000000000000000 04232 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BD0 0000000000000000 04233 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BD8 0000000000000000 04234 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BE0 0000000000000000 04235 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BE8 0000000000000000 04236 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BF0 0000000000000000 04237 DB $00,$00,$00,$00,$00,$00,$00,$00 -9BF8 0000000000000000 04238 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C00 0000000000000000 04239 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C08 0000000000000000 04240 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C10 0000000000000000 04241 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C18 0000000000000000 04242 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C20 0000000000000000 04243 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C28 0000000000000000 04244 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C30 0000000000000000 04245 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C38 0000000000000000 04246 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C40 0000000000000000 04247 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C48 0000000000000000 04248 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C50 0000000000000000 04249 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C58 0000000000000000 04250 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C60 0000000000000000 04251 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C68 0000000000000000 04252 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C70 0000000000000000 04253 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C78 0000000000000000 04254 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C80 0000000000000000 04255 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C88 0000000000000000 04256 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C90 0000000000000000 04257 DB $00,$00,$00,$00,$00,$00,$00,$00 -9C98 0000000000000000 04258 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CA0 0000000000000000 04259 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CA8 0000000000000000 04260 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CB0 0000000000000000 04261 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CB8 0000000000000000 04262 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CC0 0000000000000000 04263 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CC8 0000000000000000 04264 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CD0 0000000000000000 04265 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CD8 0000000000000000 04266 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CE0 0000000000000000 04267 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CE8 0000000000000000 04268 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CF0 0000000000000000 04269 DB $00,$00,$00,$00,$00,$00,$00,$00 -9CF8 0000000000000000 04270 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D00 0000000000000000 04271 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D08 0000000000000000 04272 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D10 0000000000000000 04273 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D18 0000000000000000 04274 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D20 0000000000000000 04275 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D28 0000000000000000 04276 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D30 0000000000000000 04277 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D38 0000000000000000 04278 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D40 0000000000000000 04279 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D48 0000000000000000 04280 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D50 0000000000000000 04281 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D58 0000000000000000 04282 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D60 0000000000000000 04283 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D68 0000000000000000 04284 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D70 0000000000000000 04285 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D78 0000000000000000 04286 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D80 0000000000000000 04287 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D88 0000000000000000 04288 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D90 0000000000000000 04289 DB $00,$00,$00,$00,$00,$00,$00,$00 -9D98 0000000000000000 04290 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DA0 0000000000000000 04291 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DA8 0000000000000000 04292 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DB0 0000000000000000 04293 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DB8 0000000000000000 04294 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DC0 0000000000000000 04295 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DC8 0000000000000000 04296 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DD0 0000000000000000 04297 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DD8 0000000000000000 04298 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DE0 0000000000000000 04299 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DE8 0000000000000000 04300 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DF0 0000000000000000 04301 DB $00,$00,$00,$00,$00,$00,$00,$00 -9DF8 0000000000000000 04302 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E00 0000000000000000 04303 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E08 0000000000000000 04304 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E10 0000000000000000 04305 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E18 0000000000000000 04306 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E20 0000000000000000 04307 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E28 0000000000000000 04308 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E30 0000000000000000 04309 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E38 0000000000000000 04310 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E40 0000000000000000 04311 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E48 0000000000000000 04312 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E50 0000000000000000 04313 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E58 0000000000000000 04314 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E60 0000000000000000 04315 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E68 0000000000000000 04316 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E70 0000000000000000 04317 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E78 0000000000000000 04318 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E80 0000000000000000 04319 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E88 0000000000000000 04320 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E90 0000000000000000 04321 DB $00,$00,$00,$00,$00,$00,$00,$00 -9E98 0000000000000000 04322 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EA0 0000000000000000 04323 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EA8 0000000000000000 04324 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EB0 0000000000000000 04325 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EB8 0000000000000000 04326 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EC0 0000000000000000 04327 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EC8 0000000000000000 04328 DB $00,$00,$00,$00,$00,$00,$00,$00 -9ED0 0000000000000000 04329 DB $00,$00,$00,$00,$00,$00,$00,$00 -9ED8 0000000000000000 04330 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EE0 0000000000000000 04331 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EE8 0000000000000000 04332 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EF0 0000000000000000 04333 DB $00,$00,$00,$00,$00,$00,$00,$00 -9EF8 0000000000000000 04334 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F00 0000000000000000 04335 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F08 0000000000000000 04336 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F10 0000000000000000 04337 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F18 0000000000000000 04338 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F20 0000000000000000 04339 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F28 0000000000000000 04340 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F30 0000000000000000 04341 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F38 0000000000000000 04342 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F40 0000000000000000 04343 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F48 0000000000000000 04344 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F50 0000000000000000 04345 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F58 0000000000000000 04346 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F60 0000000000000000 04347 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F68 0000000000000000 04348 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F70 0000000000000000 04349 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F78 0000000000000000 04350 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F80 0000000000000000 04351 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F88 0000000000000000 04352 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F90 0000000000000000 04353 DB $00,$00,$00,$00,$00,$00,$00,$00 -9F98 0000000000000000 04354 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FA0 0000000000000000 04355 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FA8 0000000000000000 04356 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FB0 0000000000000000 04357 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FB8 0000000000000000 04358 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FC0 0000000000000000 04359 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FC8 0000000000000000 04360 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FD0 0000000000000000 04361 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FD8 0000000000000000 04362 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FE0 0000000000000000 04363 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FE8 0000000000000000 04364 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FF0 0000000000000000 04365 DB $00,$00,$00,$00,$00,$00,$00,$00 -9FF8 0000000000000000 04366 DB $00,$00,$00,$00,$00,$00,$00,$00 - -00000 ERRORS FOUND -00000 WARNINGS FOUND - -114722 PROGRAM BYTES - -LABEL VALUE/ADDRESS - -AUDIO_FREQ1 0042 -AUDIO_FREQ2 0044 -AUDIO_FREQ3 0046 -AUDIO_NOISE 004c -AUDIO_VOL1 0048 -AUDIO_VOL2 0049 -AUDIO_VOL3 004a -AUDIO_VOL4HW 004b -BANKSEL c000 -BANK_0_FREE 34fb -BANK_1_FREE 3de2 -BANK_2_FREE 3f05 -BASE_RAM 0050 -CHRRAM_BANK 001c -CLEAR_SPRITES c57a -CLEAR_SPRITES.1 c57e -CLS c0c6 -CLS.1 c0c8 -CLS.2 c0d3 -CLS.3 c0d5 -COLECO 0000 -CONT1 4016 -CONT2 4017 -CONT_BITS 001d -CONVERT_JOYSTICK c42e -COPY_CHRRAM c909 -COPY_CHRRAM.1 c917 -COPY_PAGE c91e -COPY_PAGE.1 c920 -CPM 0000 -CPYBLK c07a -CPYBLK.1 c07a -CURSOR 000c -CV1 cafc -CV2 caff -CVBASIC_BANK_ROM_SIZE 0100 -CVBASIC_BANK_SWITCHING 0001 -CVBASIC_COMPRESSION 0000 -CVBASIC_MUSIC_PLAYER 0001 -CVB_DISPLAY_SOME_TEXT 8000 -CVB_IMAGE_PATTERN 803a -CVB_TUNE_1 8000 -DISSCR c073 -EINSTEIN 0000 -ENASCR c06c -FLICKER 0011 -FRAME 0012 -IRQ_HANDLER c2e2 -JOY1_DATA 0020 -JOY2_DATA 0021 -KEY1_DATA 0022 -KEY2_DATA 0023 -LDIRVM c03a -LDIRVM.1 c069 -LDIRVM2 c02b -LDIRVM2.1 c039 -LDIRVM4 c01e -LFSR 001e -MEMOTECH 0000 -MODE 000e -MODE_0 c577 -MSX 0000 -MUSIC_BANK 0030 -MUSIC_BASS c741 -MUSIC_BASS.1 c751 -MUSIC_CLARINET c78f -MUSIC_CLARINET.1 c7ad -MUSIC_CLARINET.2 c7c5 -MUSIC_CLARINET.3 c79f -MUSIC_COUNTER_1 0039 -MUSIC_COUNTER_2 003c -MUSIC_COUNTER_3 003f -MUSIC_COUNTER_4 0041 -MUSIC_DRUM 0040 -MUSIC_FLUTE c6f3 -MUSIC_FLUTE.1 c707 -MUSIC_FLUTE.2 c71f -MUSIC_GENERATE c5cb -MUSIC_GENERATE.1 c5dc -MUSIC_GENERATE.10 c68f -MUSIC_GENERATE.11 c6cd -MUSIC_GENERATE.12 c6a8 -MUSIC_GENERATE.14 c6bd -MUSIC_GENERATE.15 c69d -MUSIC_GENERATE.2 c65c -MUSIC_GENERATE.3 c5f0 -MUSIC_GENERATE.4 c5ff -MUSIC_GENERATE.5 c61a -MUSIC_GENERATE.6 c630 -MUSIC_GENERATE.7 c646 -MUSIC_GENERATE.8 c66d -MUSIC_GENERATE.9 c67e -MUSIC_HARDWARE c85d -MUSIC_HARDWARE.1 c8e3 -MUSIC_HARDWARE.2 c8e5 -MUSIC_HARDWARE.3 c891 -MUSIC_HARDWARE.4 c8ad -MUSIC_HARDWARE.5 c8d3 -MUSIC_HARDWARE.6 c8e8 -MUSIC_HARDWARE.7 c8fd -MUSIC_HARDWARE.8 c902 -MUSIC_HARDWARE.9 c87f -MUSIC_INIT c588 -MUSIC_INSTRUMENT_1 0037 -MUSIC_INSTRUMENT_2 003a -MUSIC_INSTRUMENT_3 003d -MUSIC_MODE 004e -MUSIC_NOTE2FREQ c737 -MUSIC_NOTES_TABLE c7dd -MUSIC_NOTE_1 0038 -MUSIC_NOTE_2 003b -MUSIC_NOTE_3 003e -MUSIC_NOTE_COUNTER 0036 -MUSIC_PIANO c769 -MUSIC_PIANO.1 c777 -MUSIC_PLAY c5a6 -MUSIC_PLAYING 004f -MUSIC_POINTER 0034 -MUSIC_SILENCE c903 -MUSIC_START 0032 -MUSIC_TICK 004d -MUSIC_TIMING 0031 -NABU 0000 -NES_CHR_BANKS 0001 -NES_NAMETABLE 0000 -NES_PRG_BANKS 0010 -NMI_HANDLER c2e3 -NMI_HANDLER.0 c30c -NMI_HANDLER.1 c362 -NMI_HANDLER.10 c3ce -NMI_HANDLER.11 c35e -NMI_HANDLER.12 c3eb -NMI_HANDLER.14 c3e7 -NMI_HANDLER.2 c34c -NMI_HANDLER.3 c354 -NMI_HANDLER.4 c32f -NMI_HANDLER.5 c2fc -NMI_HANDLER.6 c2fe -NMI_HANDLER.7 c33e -NMI_HANDLER.8 c3d4 -NMI_HANDLER.9 c3f2 -NTSC 000f -OAMADDR 2003 -PENCIL 0000 -POINTER 0008 -PPUADDR 2006 -PPUBUF 0100 -PPUCTRL 2000 -PPUDATA 2007 -PPUMASK 2001 -PPUSCROLL 2005 -PPUSTATUS 2002 -PPU_CTRL 0016 -PPU_MASK 0017 -PPU_POINTER 0014 -PPU_SOURCE 0000 -PPU_TEMP 0015 -PRINT_CHAR c55e -PRINT_CHAR.1 c573 -PRINT_DIGIT c52f -PRINT_DIGIT.2 c531 -PRINT_DIGIT.3 c558 -PRINT_DIGIT.4 c54f -PRINT_DIGIT.6 c556 -PRINT_NUMBER c4ef -PRINT_NUMBER1 c520 -PRINT_NUMBER2 c515 -PRINT_NUMBER3 c50a -PRINT_NUMBER4 c4ff -PRINT_NUMBER5 c4f4 -PRINT_STRING c492 -PRINT_STRING.1 c4ee -PRINT_STRING.2 c4a4 -PRINT_STRING_CURSOR c48e -PRINT_STRING_CURSOR_CONSTANT c46a -PSG 0000 -PV2000 0000 -RAM_END ca4b -RAM_SIZE 0800 -RANDOM c2b3 -RANDOM.0 c2c1 -READ_POINTER 000a -RESULT 0006 -ROM_END c000 -SCROLL_X 0018 -SCROLL_Y 001a -SG1000 0000 -SGM 0000 -SMS 0000 -SORD 0000 -SPRITE_DATA 0024 -SPRITE_PAGE 0002 -SPRRAM 4014 -STACK 01ff -START c92b -START.1 c953 -START.2 c9de -START.3 c9fd -START.4 ca0f -START.5 c979 -START.6 c97d -START.7 c990 -START.8 c999 -START.9 c99f -SVI 0000 -TEMP 0002 -TEMP2 0004 -TI99 0000 -UPDATE_SPRITE c107 -VDP 0000 -VDPR 0000 -VDP_STATUS 0010 -WAIT c463 -WAIT.1 c465 -WRTVRM c000 -WRTVRM.1 c01b -_ABS16 c125 -_DIV16 c223 -_DIV16.1 c235 -_DIV16.2 c23d -_DIV16.3 c261 -_DIV16S c1e8 -_DIV16S.1 c20c -_DIV16S.2 c219 -_DIV16S.3 c222 -_MOD16 c26d -_MOD16.1 c27f -_MOD16.2 c287 -_MOD16.3 c2ab -_MOD16S c1b1 -_MOD16S.1 c1d1 -_MOD16S.2 c1de -_MOD16S.3 c1e7 -_MUL16 c178 -_MUL16.1 c192 -_MUL16.2 c1a5 -_NEG16 c12a -_NEG16.1 c136 -_PEEK16 c169 -_PEEK8 c160 -_READ16 c14b -_READ8 c155 -_READ8.1 c15f -_SGN16 c138 -_SGN16.1 c149 -_SGN16.2 c147 diff --git a/examples/bank_nes.bas b/examples/bank_nes.bas index 3f2ca58..a9a5bc4 100644 --- a/examples/bank_nes.bas +++ b/examples/bank_nes.bas @@ -187,7 +187,7 @@ display_some_text: PROCEDURE PRINT AT $01d1,"Hi!" - PRINT AT $0211,"This is bank-" + PRINT AT $0211,"This is a bank-" PRINT AT $0231,"switching demo." From f1ddcca31082e6815c469aaf08017d1ad1b42371 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 15:10:33 -0600 Subject: [PATCH 081/155] Code cleanup --- cpu9900.c | 7 ------- cvbasic.c | 12 +++++++----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/cpu9900.c b/cpu9900.c index 00699e3..ac24028 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -579,7 +579,6 @@ void cpu9900_2op(char *mnemonic, char *operand1, char *operand2) void cpu9900_node_label(struct node *node) { struct node *explore; - int c; switch (node->type) { case N_USR: /* Assembly language function with result */ @@ -745,8 +744,6 @@ void cpu9900_node_label(struct node *node) } if (node->type == N_EQUAL16 || node->type == N_NOTEQUAL16) { if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { - int c; - if (node->left->type == N_NUM16) explore = node->left; else @@ -763,8 +760,6 @@ void cpu9900_node_label(struct node *node) } if (node->type == N_LESS16 || node->type == N_GREATER16) { if (node->right->type == N_NUM16) { - int c; - cpu9900_node_label(node->left); node->regs = node->left->regs; break; @@ -776,8 +771,6 @@ void cpu9900_node_label(struct node *node) else explore = NULL; if (explore != NULL) { - int c = explore->value; - cpu9900_node_label(node->left); node->regs = node->left->regs; break; diff --git a/cvbasic.c b/cvbasic.c index 41ca485..bff0424 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -240,11 +240,13 @@ static int bitmap_byte; */ #define CHRROM_PAGE 8192 -int current_chrrom; -int chrrom_pointer; -int chrrom_size; -unsigned char *chrrom_data; -int nes_nametable; +static int current_chrrom; +static int chrrom_pointer; +static int chrrom_size; +static unsigned char *chrrom_data; +static int nes_nametable; + +void reset_chrrom(unsigned char *); void reset_chrrom(unsigned char *page) { From be95f6a5ebbe576cb8c2158dc4b99be73e2dd225 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 15:37:59 -0600 Subject: [PATCH 082/155] NES added compatibility with Famicom controllers --- README.md | 19 +++++++++++++++---- cvbasic.c | 2 +- cvbasic_nes_prologue.asm | 16 ++++++++++------ examples/controller_nes.bas | 35 +++++++++++++++++++++++++++-------- 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 81ca7a0..115d081 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,11 @@ Later it was extended to support the following platforms: * Hanimex/Soundic Pencil II. * NABU PC. * Sega Master System (supporting bank switching with Sega mapper) -* NES/Famicom (preliminary, supporting bank switching using UNROM 512) +* NES/Famicom (supporting bank switching using mapper 30 - UNROM 512) One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. -The only difference currently is the Sega Master System, although the compiler shares the core, the sprites are 8x16 and each pixel can have a different color, so the games aren't directly portable, but very easily translated. The examples include SMS versions for every game so you can see what's required to change. +Currently, Sega Master System and NES/Famicom are different in video terms, although the compiler shares the core, the sprites are 8x16 and each pixel can have a different color, so the games aren't directly portable, but very easily translated. The examples include SMS and NES/Famicom versions for every game so you can see the required changes. The following files compose the compiler: @@ -48,31 +48,41 @@ The following files compose the compiler: cvbasic_6502_epilogue.asm Epilogue file needed for 6502 compiled programs. cvbasic_9900_prologue.asm Prologue file needed for TMS9900 compiled programs. cvbasic_9900_epilogue.asm Epilogue file needed for TMS9900 compiled programs. + cvbasic_nes_prologue.asm Prologue file needed for NES/Famicom compiled programs. + cvbasic_nes_epilogue.asm Epilogue file needed for NES/Famicom compiled programs. manual.txt English manual for CVBasic README.md This file examples/bank.bas Bank-switching example. + examples/bank_nes.bas Bank-switching example (NES/Famicom) + examples/bank_sms.bas Bank-switching example (Sega Master System) examples/brinquitos.bas Jumping game. + examples/brinquitos_nes.bas Jumping game (NES/Famicom) examples/brinquitos_sms.bas Jumping game (Sega Master System) examples/controller.bas Controller test. + examples/controller_nes.bas Controller test (NES) examples/cats_sms.bas Cats example (Sega Master System) examples/demo.bas Demo of graphics. + examples/demo_nes.bas Demo of graphics (NES/Famicom) examples/demo_sms.bas Demo of graphics (Sega Master System) examples/face_joystick.bas Moving face with joystick. + examples/face_joystick_nes.bas Moving face with joystick (NES/Famicom) examples/face_joystick_sms.bas Moving face with joystick (Sega Master System) examples/happy_face.bas Bouncing face. - examples/happy_face_sms.bas Bouncing face (Sega Master System). examples/happy_face_nes.bas Bouncing face (NES/Famicom). + examples/happy_face_sms.bas Bouncing face (Sega Master System). examples/music.bas Music example. examples/oscar_compressed.bas High-resolution graphics example compressed with Pletter. examples/oscar_compressed_sms.bas High-resolution graphics example compressed with Pletter (Sega Master System) examples/oscar.bas High-resolution graphics example. + examples/oscar_nes.bas High-resolution graphics example (NES/Famicom) examples/oscar_sms.bas High-resolution graphics example (Sega Master System) examples/portrait.bas Data used by demo.bas examples/portrait_sms.bas Data used by demo_sms.bas examples/space_attack.bas Game example. + examples/space_attack_nes.bas Game example (NES/Famicom) examples/space_attack_sms.bas Game example (Sega Master System) examples/test1.bas Moving stars. examples/test2.bas Arithmetic test. @@ -83,6 +93,7 @@ The following files compose the compiler: examples/vgm.bas VGM audio player for SN76489. examples/vgm_ay.bas VGM audio player for AY-3-8910. examples/viboritas.bas Game example. + examples/viboritas_nes.bas Game example (NES/Famicom) examples/viboritas_sms.bas Game example (Sega Master System) examples/vramcopy.bas VRAM copy example. examples/vramcopy_sms.bas VRAM copy example (Sega Master System) @@ -234,7 +245,7 @@ The TI-99/4A can only generate non-banked binaries up to 24 kb. When banking, th The NABU PC can only use binaries up to 32 kb, joysticks can be used for both controllers, keyboard arrows are handled as controller 1 (<||| is the primary button and |||> is the secondary button), and it can also emulate the Colecovision keypad (CONT1.KEY only) using the keys 0-9, Del and Enter. -The NES support is highly experimental. Five demos have been ported and are functional: face_joystick, happy_face, music, Space Attack, and Viboritas. Missing image converter. +The NES/Famicom translates Select to CONT.KEY = 10, and Start to CONT.KEY = 11. Many people is developing games using CVBasic, feel free to check some of these examples at the [AtariAge Colecovision Programming forum](https://forums.atariage.com/forum/55-colecovision-programming/) diff --git a/cvbasic.c b/cvbasic.c index bff0424..056776d 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.0 Aug/25/2025" +#define VERSION "v0.9.0 Aug/26/2025" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index fc625fd..297a139 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -747,10 +747,12 @@ nmi_handler: LSR A STA CONT1 - LDA CONT1 - LSR A +.15: LDA CONT1 +; LSR A + AND #3 ; So it works with Famicom + CMP #1 ROL cont_bits - BCC $-6 + BCC .15 JSR convert_joystick STA joy1_data @@ -762,10 +764,12 @@ nmi_handler: LSR A STA CONT1 - LDA CONT2 - LSR A +.16: LDA CONT2 +; LSR A + AND #3 ; So it works with Famicom + CMP #1 ROL cont_bits - BCC $-6 + BCC .16 JSR convert_joystick STA joy2_data diff --git a/examples/controller_nes.bas b/examples/controller_nes.bas index f4a2601..5b804b8 100644 --- a/examples/controller_nes.bas +++ b/examples/controller_nes.bas @@ -12,14 +12,33 @@ game_loop: WAIT c = CONT1 - SPRITE 16, 24, 8, (c AND $80) / 128 * 2, 0 - SPRITE 17, 24, 16, (c AND $40) / 64 * 2, 0 - SPRITE 18, 24, 24, (c AND $20) / 32 * 2, 0 - SPRITE 19, 24, 32, (c AND $10) / 16 * 2, 0 - SPRITE 20, 24, 40, (c AND $08) / 8 * 2, 0 - SPRITE 21, 24, 48, (c AND $04) / 4 * 2, 0 - SPRITE 22, 24, 56, (c AND $02) / 2 * 2, 0 - SPRITE 23, 24, 64, (c AND $01) / 1 * 2, 0 + SPRITE 16, 64, 96, (c AND $80) / 128 * 2, 0 + SPRITE 17, 64, 104, (c AND $40) / 64 * 2, 0 + SPRITE 18, 64, 112, (c AND $20) / 32 * 2, 0 + SPRITE 19, 64, 120, (c AND $10) / 16 * 2, 0 + SPRITE 20, 64, 128, (c AND $08) / 8 * 2, 0 + SPRITE 21, 64, 136, (c AND $04) / 4 * 2, 0 + SPRITE 22, 64, 144, (c AND $02) / 2 * 2, 0 + SPRITE 23, 64, 152, (c AND $01) / 1 * 2, 0 + + c = CONT1.KEY + + PRINT AT 335,<>c," " + + c = CONT2 + + SPRITE 24, 192, 96, (c AND $80) / 128 * 2, 0 + SPRITE 25, 192, 104, (c AND $40) / 64 * 2, 0 + SPRITE 26, 192, 112, (c AND $20) / 32 * 2, 0 + SPRITE 27, 192, 120, (c AND $10) / 16 * 2, 0 + SPRITE 28, 192, 128, (c AND $08) / 8 * 2, 0 + SPRITE 29, 192, 136, (c AND $04) / 4 * 2, 0 + SPRITE 30, 192, 144, (c AND $02) / 2 * 2, 0 + SPRITE 31, 192, 152, (c AND $01) / 1 * 2, 0 + + c = CONT2.KEY + + PRINT AT 847,<>c," " GOTO game_loop From 3d77e7c18d2ee4065c8a084bf01d1051aa809de0 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 16:12:29 -0600 Subject: [PATCH 083/155] NES adjustments --- cvbasic_nes_prologue.asm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 297a139..0f4b778 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -124,6 +124,7 @@ PPUCTRL: EQU $2000 PPUMASK: EQU $2001 PPUSTATUS: EQU $2002 OAMADDR: EQU $2003 +OAMDATA: EQU $2004 PPUSCROLL: EQU $2005 PPUADDR: EQU $2006 PPUDATA: EQU $2007 @@ -653,8 +654,8 @@ nmi_handler: LDA #$00 .6: STA OAMADDR - LDA #SPRITE_PAGE - STA SPRRAM ; Use DMA for sprite loading + LDX #SPRITE_PAGE + STX SPRRAM ; Use DMA for sprite loading ; Screen changes LDA ppu_pointer ; Any change? From d43a41c0c66c9302dd8bbbb6951f3b91d4a653bc Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 16:57:00 -0600 Subject: [PATCH 084/155] Added more games made with CVBasic --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 115d081..11ec444 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ CVBasic is a BASIC language cross-compiler with a syntax alike to QBasic origina The CVBasic compiler can create programs up to 1 MB using the BANK statements (using 16K bank switching on most platforms, 8k on TI-99/4A). -Later it was extended to support the following platforms: +It has been extended to support the following platforms: * Sega SG-1000 / SC-3000 (supporting bank switching with Sega mapper) * MSX 1 (supporting bank switching with ASCII16 mapper) @@ -270,12 +270,22 @@ There are some very good examples of games developed with CVBasic. * Gun Fight by Eric Damain. Video at [https://forums.atariage.com/topic/379102-gun-fight-dev-log-cvbasic/](https://forums.atariage.com/topic/379102-gun-fight-dev-log-cvbasic/) +* Jurl by Tonsomo Entertainment. Available from [https://tonsomo.itch.io/jurl-colecovision-edition](https://tonsomo.itch.io/jurl-colecovision-edition) + * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) * Monkey Moon by nanochess, example from the book **Programming Games for Colecovision**. Available from [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249) +* Operation Hibernation by Jess Ragan. Available from [https://forums.atariage.com/topic/383365-operation-hibernation-nearing-completion/](https://forums.atariage.com/topic/383365-operation-hibernation-nearing-completion/) + +* Pipe Dreams by visrealm. Available from [https://forums.atariage.com/topic/382747-pipe-dreams-clone-for-the-colecovision-and-others-cvbasic/](https://forums.atariage.com/topic/382747-pipe-dreams-clone-for-the-colecovision-and-others-cvbasic/) + * Rogue-like Wip by Skywaffle. Available from [https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/](https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/) +* Shamus by nanochess. Available from [https://forums.atariage.com/topic/383531-shamus-for-colecovision/](https://forums.atariage.com/topic/383531-shamus-for-colecovision/) + +* Solar Fox 2 by Jess Ragan. Available from [https://forums.atariage.com/topic/382881-solar-fox-2-is-finished-link-inside/](https://forums.atariage.com/topic/382881-solar-fox-2-is-finished-link-inside/) + * Sub Hunt by Eric Damain. Demo videos [https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/](https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/) * Whack'em Smack'em Byron by Jess Ragan. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) @@ -290,7 +300,7 @@ You can also get my book **Programming Games for Colecovision** including an int The foreword is written by the legendary David R. Megarry, programmer of Zaxxon™ for Colecovision, and creator of the Dungeon!™ Board game. -All the games in the book will compile for **all** the platforms (exception of Dungeon Warrior for Sord M5 and Casio PV2000 because the small 16KB ROM size) +All the games in the book will compile for **all** the platforms, except Sega Master System and NES/Famicom (because the different video processor, but can be adapted), and Dungeon Warrior cannot compile for Sord M5 and Casio PV2000 because the small 16KB ROM size. * [Programming Games for Colecovision, paperback, 250 pages](https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-colecovision/paperback/product-95qvzj8.html?page=1&pageSize=4) * [Programming Games for Colecovision, hardcover, 250 pages](https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-colecovision/hardcover/product-84nm767.html?page=1&pageSize=4) From ee31cebaff08f8ce1aeea0074d4fc641201ffee7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 26 Aug 2025 21:03:21 -0600 Subject: [PATCH 085/155] Updated to official version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11ec444..0d83730 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ Using CVBasic to compile a NES/Famicom program: ### Notes -The current official version is v0.8.0. +The current official version is v0.9.0. All platforms have been tested in emulation. From 02815eaea76e1e1dff454e8d2279ffa66a1e26e1 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 29 Aug 2025 20:59:53 -0600 Subject: [PATCH 086/155] cpu6502.c added register labeling, saves stack temporary --- cpu6502.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++------ cpu6502.h | 5 + 2 files changed, 416 insertions(+), 45 deletions(-) diff --git a/cpu6502.c b/cpu6502.c index 6e975bb..1f85eda 100644 --- a/cpu6502.c +++ b/cpu6502.c @@ -14,6 +14,9 @@ #include "node.h" #include "cpu6502.h" +#define REG_NONE 0 +#define REG_ALL (REG_ACC | REG_X | REG_Y | REG_TEMP) + static char temp2[MAX_LINE_SIZE]; static char cpu6502_line[MAX_LINE_SIZE]; @@ -24,7 +27,6 @@ static char cpu6502_y[MAX_LINE_SIZE]; static int cpu6502_flag_z_valid; static void cpu6502_emit_line(void); -static int cpu6502_8bit_simple(struct node *); void cpu6502_emit_line(void) { @@ -236,50 +238,402 @@ void cpu6502_1op(char *mnemonic, char *operand) */ void cpu6502_node_label(struct node *node) { - /* Nothing to do, yet */ -} - -/* - ** Detect operations that only use A. - */ -static int cpu6502_8bit_simple(struct node *node) -{ + struct node *explore; + int stack; + int c; + char *p; + switch (node->type) { - case N_LOAD8: - case N_NUM8: - case N_INP: - case N_JOY1: - case N_JOY2: - case N_KEY1: - case N_KEY2: - case N_MUSIC: - case N_NTSC: - case N_VDPSTATUS: - return 1; - case N_NEG8: - case N_NOT8: - return cpu6502_8bit_simple(node->left); - case N_LESSEQUAL8: /* 8-bit <= */ - case N_GREATER8: /* 8-bit > */ - if (node->left->type != N_NUM8 && node->left->type != N_LOAD8) - return 0; - return cpu6502_8bit_simple(node->right); + case N_USR: /* Assembly language function with result */ + if (node->left != NULL) + cpu6502_node_label(node->left->left); + node->regs = REG_ALL; + break; + case N_LOAD8: /* Load 8-bit value from address */ + case N_NUM8: /* Load 8-bit constant */ + case N_INP: /* Read port */ + case N_JOY1: /* Read joystick 1 */ + case N_JOY2: /* Read joystick 2 */ + case N_KEY1: /* Read keypad 1 */ + case N_KEY2: /* Read keypad 2 */ + case N_MUSIC: /* Read music playing status */ + case N_NTSC: /* Read NTSC flag */ + case N_VDPSTATUS: /* Read VDP status */ + node->regs = REG_ACC; + break; + case N_ADDR: /* Get address of variable */ + case N_POS: /* Get screen cursor position */ + case N_READ8: /* Read 8-bit value */ + case N_READ16: /* Read 16-bit value */ + case N_LOAD16: /* Load 16-bit value from address */ + case N_NUM16: /* Load 16-bit constant */ + case N_FRAME: /* Read current frame number */ + node->regs = REG_ACC | REG_Y; + break; + case N_RANDOM: /* Read pseudorandom generator */ + node->regs = REG_ACC | REG_Y | REG_TEMP; + break; + case N_NEG8: /* Negate 8-bit value */ + case N_NOT8: /* Complement 8-bit value */ + case N_REDUCE16: /* Reduce 16-bit value to 8-bit */ + case N_VPEEK: /* Read VRAM */ + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; + case N_NEG16: /* Negate 16-bit value */ + case N_NOT16: /* Complement 16-bit value */ + case N_ABS16: /* Get absolute 16-bit value */ + cpu6502_node_label(node->left); + node->regs = node->left->regs | REG_X; + break; + case N_SGN16: /* Get sign of 16-bit value */ + cpu6502_node_label(node->left); + node->regs = node->left->regs | REG_X | REG_TEMP; + break; + case N_EXTEND8S: /* Extend 8-bit signed value to 16-bit */ + cpu6502_node_label(node->left); + node->regs = node->left->regs | REG_X | REG_Y; + break; + case N_EXTEND8: /* Extend 8-bit value to 16-bit */ + cpu6502_node_label(node->left); + node->regs = node->left->regs | REG_Y; + break; + case N_PEEK8: /* Load 8-bit content */ + if (node->left->type == N_ADDR) { /* Optimize address */ + node->regs = REG_ACC; + break; + } + if ((node->left->type == N_PLUS16 || node->left->type == N_MINUS16) + && node->left->left->type == N_ADDR + && node->left->right->type == N_NUM16) { /* Optimize address plus constant */ + node->regs = REG_ACC; + break; + } + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; + case N_PEEK16: /* Load 16-bit content */ + if (node->left->type == N_ADDR) { /* Optimize address */ + node->regs = REG_ACC | REG_Y; + break; + } + if ((node->left->type == N_PLUS16 || node->left->type == N_MINUS16) + && node->left->left->type == N_ADDR + && node->left->right->type == N_NUM16) { /* Optimize address plus constant */ + node->regs = REG_ACC | REG_Y; + break; + } + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; case N_OR8: /* 8-bit OR */ case N_XOR8: /* 8-bit XOR */ case N_AND8: /* 8-bit AND */ case N_EQUAL8: /* 8-bit = */ case N_NOTEQUAL8: /* 8-bit <> */ case N_LESS8: /* 8-bit < */ + case N_LESSEQUAL8: /* 8-bit <= */ + case N_GREATER8: /* 8-bit > */ case N_GREATEREQUAL8: /* 8-bit >= */ case N_PLUS8: /* 8-bit + */ case N_MINUS8: /* 8-bit - */ case N_MUL8: /* 8-bit * */ case N_DIV8: /* 8-bit / */ - if (node->right->type != N_NUM8 && node->right->type != N_LOAD8) - return 0; - return cpu6502_8bit_simple(node->left); - default: - return 0; + if (node->type == N_MUL8 && node->right->type == N_NUM8 && is_power_of_two(node->right->value)) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; + } + if (node->type == N_DIV8 && node->right->type == N_NUM8 && is_power_of_two(node->right->value)) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; + } + if (node->type == N_LESSEQUAL8 || node->type == N_GREATER8) { + if (node->left->type == N_NUM8) { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + } else if (node->left->type == N_LOAD8) { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + } else { + cpu6502_node_label(node->right); + cpu6502_node_label(node->left); + node->regs = node->left->regs | node->right->regs | REG_TEMP; + } + } else if (node->right->type == N_LOAD8) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + } else if (node->right->type == N_NUM8) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu6502_node_label(node->left); + cpu6502_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_TEMP; + } + break; + case N_ASSIGN8: /* 8-bit assignment */ + if ((node->left->type == N_PLUS8 || node->left->type == N_MINUS8 || node->left->type == N_OR8 || node->left->type == N_AND8 || node->left->type == N_XOR8) + && (node->left->right->type == N_NUM8 || node->left->right->type == N_LOAD8) + && node_same_address(node->left->left, node->right)) { + if (node->right->type == N_ADDR) { + node->regs = REG_NONE; + c = 0; + } else if (((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16)) { + node->regs = REG_NONE; + c = 0; + } else { + if (node->right->type == N_PLUS16 && node->right->left->type == N_ADDR && node->right->right->type == N_EXTEND8 && node->right->right->left->type == N_LOAD8) { + node->regs = REG_ACC | REG_TEMP | REG_Y; + } else { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + } + c = 1; + node->regs |= REG_Y; + } + if (c == 0 && (node->left->type == N_PLUS8 || node->left->type == N_MINUS8) && node->left->right->type == N_NUM8 && node->left->right->value < 4) { + } else { + node->regs |= REG_ACC; + } + break; + } + + if (node->right->type == N_ADDR + || ((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16)) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; + } + cpu6502_node_label(node->right); + cpu6502_node_label(node->left); + node->regs = node->right->regs | node->left->regs | REG_TEMP; + break; + case N_ASSIGN16: /* 16-bit assignment */ + if (node->right->type == N_ADDR) { + c = 1; + } else if (((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16)) { + c = 1; + } else { + c = 0; + } + if (node->left->type == N_PLUS16 + && node->left->right->type == N_NUM16 + && ((c && node->left->right->value == 1) || !c) + && node_same_address(node->left->left, node->right)) { + if (node->right->type == N_ADDR) { + node->regs = REG_NONE; + c = 0; + } else if (((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16)) { + node->regs = REG_NONE; + c = 0; + } else { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + c = 1; + } + break; + } + + if (node->right->type == N_ADDR + || ((node->right->type == N_PLUS16 || node->right->type == N_MINUS16) && node->right->left->type == N_ADDR && node->right->right->type == N_NUM16)) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + break; + } + if (node->left->type == N_NUM16 || node->left->type == N_LOAD16) { + cpu6502_node_label(node->right); + cpu6502_node_label(node->left); + node->regs = node->right->regs | node->left->regs | REG_X | REG_TEMP; + } else { + cpu6502_node_label(node->left); + cpu6502_node_label(node->right); + node->regs = node->right->regs | node->left->regs | REG_TEMP; + } + break; + default: /* Every other node, all remaining are 16-bit operations */ + /* Optimization of address plus/minus constant */ + if (node->type == N_PLUS16 || node->type == N_MINUS16) { + if (node->left->type == N_ADDR) { + if (node->right->type == N_NUM16) { + node->regs = REG_ACC | REG_Y; + break; + } else if (node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { + node->regs = REG_ACC | REG_X | REG_Y; + break; + } + } + } + if (node->type == N_PLUS16) { + if (node->left->type == N_ADDR) { + cpu6502_node_label(node->right); + node->regs = node->right->regs | REG_ACC | REG_X | REG_Y; + break; + } + if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { + if (node->left->type == N_NUM16) + explore = node->left; + else + explore = node->right; + if (node->left != explore) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + } + c = explore->value; + if ((c & 0xff) == 0 && (c & 0xff00) < 0x0800) { + break; + } + node->regs |= REG_X; + break; + } + } + if (node->type == N_MINUS16) { + if (node->right->type == N_NUM16) + explore = node->right; + else + explore = NULL; + if (explore != NULL) { + int c = explore->value; + + cpu6502_node_label(node->left); + node->regs = node->left->regs; + if ((c & 0xff) == 0 && (c & 0xff00) < 0x0800) { + break; + } + node->regs |= REG_X; + break; + } + } + if (node->type == N_OR16 || node->type == N_AND16 || node->type == N_XOR16) { + if (node->right->type == N_NUM16) + explore = node->right; + else + explore = NULL; + if (explore != NULL) { + int value = explore->value; + int byte; + char *mnemonic; + + if (node->left != explore) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + } else { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + } + byte = (value >> 8) & 0xff; + if ((node->type == N_OR16 || node->type == N_XOR16) && byte == 0x00) { + /* Nothing to do :) */ + } else if (node->type == N_AND16 && byte == 0xff) { + /* Nothing to do :) */ + } else if (node->type == N_AND16 && byte == 0x00) { + } else if (node->type == N_OR16 && byte == 0xff) { + } else { + node->regs |= REG_X; + } + break; + } + } + if (node->type == N_MUL16) { + if (node->left->type == N_NUM16) + explore = node->left; + else if (node->right->type == N_NUM16) + explore = node->right; + else + explore = NULL; + if (explore != NULL && (explore->value == 0 || explore->value == 1 || is_power_of_two(explore->value))) { + c = explore->value; + if (c == 0) { + node->regs = REG_ACC | REG_Y; + } else { + if (node->left != explore) + explore = node->left; + else + explore = node->right; + if (c == 2 && explore->type == N_EXTEND8) { + cpu6502_node_label(explore->left); + explore->regs = explore->left->regs; + node->regs = explore->regs; + break; + } + if (c >= 256) { + if (explore->type == N_EXTEND8 || explore->type == N_EXTEND8S) { + cpu6502_node_label(explore->left); + explore->regs = explore->left->regs | REG_Y; + } else { + cpu6502_node_label(explore); + explore->regs |= REG_Y; + } + c /= 256; + } else { + cpu6502_node_label(explore); + } + node->regs = explore->regs; + } + break; + } + } + if (node->type == N_DIV16) { + if (node->right->type == N_NUM16 && (node->right->value == 2 || node->right->value == 4 || node->right->value == 8)) { + cpu6502_node_label(node->left); + node->regs = node->left->regs | REG_TEMP; + break; + } + } + if (node->type == N_LESSEQUAL16 || node->type == N_GREATER16) { + if (node->left->type == N_NUM16) { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + stack = 0; + } else if (node->left->type == N_LOAD16) { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + stack = 0; + } else if (node->left->type == N_EXTEND8 && node->left->left->type == N_LOAD8) { + cpu6502_node_label(node->right); + node->regs = node->right->regs; + stack = 0; + } else { + cpu6502_node_label(node->right); + cpu6502_node_label(node->left); + node->regs = node->right->regs | node->left->regs | REG_TEMP; + stack = 1; + } + } else { + if (node->right->type == N_NUM16) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + stack = 0; + } else if (node->right->type == N_LOAD16) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + stack = 0; + } else if (node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { + cpu6502_node_label(node->left); + node->regs = node->left->regs; + stack = 0; + } else { + cpu6502_node_label(node->left); + cpu6502_node_label(node->right); + node->regs = node->left->regs | node->right->regs | REG_TEMP; + stack = 1; + } + } + if (node->type == N_OR16 || node->type == N_XOR16 || node->type == N_AND16) { + if (!stack) { + node->regs |= REG_X; + } + } else if (node->type == N_EQUAL16 || node->type == N_NOTEQUAL16) { + if (!stack) + node->regs |= REG_TEMP; + } else { + node->regs |= REG_X; + } + break; } } @@ -522,11 +876,17 @@ void cpu6502_node_generate(struct node *node, int decision) cpu6502_node_generate(node->right, 0); node_get_label(node->left, 0); } else { - cpu6502_node_generate(node->right, 0); - cpu6502_noop("PHA"); - cpu6502_node_generate(node->left, 0); - cpu6502_1op("STA", "temp"); - cpu6502_noop("PLA"); + if ((node->right->regs & REG_TEMP) == 0) { + cpu6502_node_generate(node->left, 0); + cpu6502_1op("STA", "temp"); + cpu6502_node_generate(node->right, 0); + } else { + cpu6502_node_generate(node->right, 0); + cpu6502_noop("PHA"); + cpu6502_node_generate(node->left, 0); + cpu6502_1op("STA", "temp"); + cpu6502_noop("PLA"); + } strcpy(temp, "temp"); } } else if (node->right->type == N_LOAD8) { @@ -537,11 +897,17 @@ void cpu6502_node_generate(struct node *node, int decision) cpu6502_node_generate(node->left, 0); sprintf(temp, "#%d", c); } else { - cpu6502_node_generate(node->left, 0); - cpu6502_noop("PHA"); - cpu6502_node_generate(node->right, 0); - cpu6502_1op("STA", "temp"); - cpu6502_noop("PLA"); + if ((node->left->regs & REG_TEMP) == 0) { + cpu6502_node_generate(node->right, 0); + cpu6502_1op("STA", "temp"); + cpu6502_node_generate(node->left, 0); + } else { + cpu6502_node_generate(node->left, 0); + cpu6502_noop("PHA"); + cpu6502_node_generate(node->right, 0); + cpu6502_1op("STA", "temp"); + cpu6502_noop("PLA"); + } strcpy(temp, "temp"); } if (node->type == N_OR8) { @@ -720,7 +1086,7 @@ void cpu6502_node_generate(struct node *node, int decision) break; } - if (cpu6502_8bit_simple(node->left)) { + if ((node->left->regs & REG_TEMP) == 0) { cpu6502_node_generate(node->right, 0); cpu6502_1op("STA", "temp"); cpu6502_1op("STY", "temp+1"); @@ -817,7 +1183,7 @@ void cpu6502_node_generate(struct node *node, int decision) cpu6502_1op("STY", temp); break; } - if (node->left->type == N_NUM16 || node->left->type == N_LOAD16) { + if ((node->left->regs & REG_TEMP) == 0) { cpu6502_node_generate(node->right, 0); cpu6502_1op("STA", "temp"); cpu6502_1op("STY", "temp+1"); diff --git a/cpu6502.h b/cpu6502.h index cfca3d3..1124b2f 100644 --- a/cpu6502.h +++ b/cpu6502.h @@ -6,6 +6,11 @@ ** Creation date: Aug/04/2024. Separated from CVBasic.c */ +#define REG_ACC 1 +#define REG_X 2 +#define REG_Y 4 +#define REG_TEMP 8 + extern void cpu6502_dump(void); extern void cpu6502_label(char *); extern void cpu6502_empty(void); From b1758928c67c6f33b2df37d91ecbe8d3a84492e8 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 5 Oct 2025 14:10:00 -0600 Subject: [PATCH 087/155] Solved bug in SPRITE FLICKER OFF for SMS --- README.md | 4 ++-- cvbasic_prologue.asm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0d83730..2b6d0c4 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ The following files compose the compiler: cvbasic_prologue.asm Prologue file needed for compiled programs. cvbasic_epilogue.asm Epilogue file needed for compiled programs. - cvbasic_6502_prologue.asm Prologue file needed for 6502 compiled programs. - cvbasic_6502_epilogue.asm Epilogue file needed for 6502 compiled programs. + cvbasic_6502_prologue.asm Prologue file needed for Creativision compiled programs. + cvbasic_6502_epilogue.asm Epilogue file needed for Creativision compiled programs. cvbasic_9900_prologue.asm Prologue file needed for TMS9900 compiled programs. cvbasic_9900_epilogue.asm Epilogue file needed for TMS9900 compiled programs. cvbasic_nes_prologue.asm Prologue file needed for NES/Famicom compiled programs. diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 8179506..d4b3bfb 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1468,7 +1468,7 @@ nmi_handler: jp nz,$-2 ld hl,$3f80 call SETWRT - ld hl,sprites + ld hl,sprites+128 ld bc,$8000+VDP outi jp nz,$-2 From 2316dd82b96cdcc44e5387fa1dd42c2d9d353d52 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 28 Nov 2025 10:21:30 -0600 Subject: [PATCH 088/155] Added note in manual for Blue and Purple buttons. Added support to controller test --- examples/controller.bas | 32 +++++++++++++++++++++++++++++++- manual.txt | 13 +++++++++---- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/examples/controller.bas b/examples/controller.bas index 88771c5..c78db56 100644 --- a/examples/controller.bas +++ b/examples/controller.bas @@ -2,9 +2,12 @@ ' Controller test ' ' by Oscar Toledo G. + ' https://nanochess.org/ ' ' Creation date: Aug/21/2024. ' Revision date: Oct/15/2024. Solved wrong display for number key in 2nd controller. + ' Revision date: Nov/28/2025. Added support for Blue and Purple buttons (Super + ' Action Controller) ' CONST left_x = 56 @@ -37,7 +40,7 @@ d = VPEEK(#c) VPOKE #c, (d / 2) OR (d / 4) NEXT #c - DEFINE CHAR 42,2,number_bitmap + DEFINE CHAR 42,4,number_bitmap VDP(1) = $E0 ' 8x8 sprites VDP(6) = $00 ' Sprites use character bitmaps. @@ -162,6 +165,14 @@ prepare_key: PROCEDURE x = ((c - 1) % 3) * 16 y = 63 + ((c - 1) / 3) * 16 c = c + 48 + ELSEIF c = 12 THEN + x = 8 + y = 0 + c = 44 + ELSEIF c = 13 THEN + x = 8 + y = 8 + c = 45 ELSE ' Some systems have extra characters x = 16 @@ -251,3 +262,22 @@ number_bitmap: BITMAP "..XX.XX." BITMAP "..XX.XX." BITMAP "........" + + BITMAP "XXXXXXX." + BITMAP "XX....XX" + BITMAP "XX....XX" + BITMAP "XXXXXXX." + BITMAP "XX....XX" + BITMAP "XX....XX" + BITMAP "XXXXXXX." + BITMAP "........" + + BITMAP "XXXXXXX." + BITMAP "XX....XX" + BITMAP "XX....XX" + BITMAP "XXXXXXX." + BITMAP "XX......" + BITMAP "XX......" + BITMAP "XX......" + BITMAP "........" + diff --git a/manual.txt b/manual.txt index 0ec7336..8e3602f 100644 --- a/manual.txt +++ b/manual.txt @@ -1359,8 +1359,9 @@ The expression parser will take advantage of 8-bit variables and numbers to opti CONT.RIGHT Non-zero if any controller pointing right CONT.BUTTON Non-zero if any controller left button is pressed. CONT.BUTTON2 Non-zero if any controller right button is pressed. - CONT.KEY Current pressed key in any controller (0-9 for numbers, - 10-*, 11-#, 15-Not pressed) + CONT.KEY Current pressed key in any controller: 0-9 for numbers, + 10-*, 11-#, 15-Not pressed. For Super Action Controllers, + 12 is the Blue button, and 13 is the Purple button. CONT1 Contains the state of the first controller. CONT1.UP Non-zero if controller pointing up @@ -1369,7 +1370,9 @@ The expression parser will take advantage of 8-bit variables and numbers to opti CONT1.RIGHT Non-zero if controller pointing right CONT1.BUTTON Non-zero if the controller left button is pressed. CONT1.BUTTON2 Non-zero if the controller right button is pressed. - CONT1.KEY Current pressed key (0-9 for numbers, 10-*, 11-#, 15-Not pressed) + CONT1.KEY Current pressed key: 0-9 for numbers, 10-*, 11-#, 15-Not pressed. + For Super Action Controllers, 12 is the Blue button, + and 13 is the Purple button. CONT2 Contains the state of the second controller. CONT2.UP Non-zero if controller pointing up @@ -1378,7 +1381,9 @@ The expression parser will take advantage of 8-bit variables and numbers to opti CONT2.RIGHT Non-zero if controller pointing right CONT2.BUTTON Non-zero if the controller left button is pressed. CONT2.BUTTON2 Non-zero if the controller right button is pressed. - CONT2.KEY Current pressed key (0-9 for numbers, 10-*, 11-#, 15-Not pressed) + CONT2.KEY Current pressed key: 0-9 for numbers, 10-*, 11-#, 15-Not pressed. + For Super Action Controllers, 12 is the Blue button, + and 13 is the Purple button. RANDOM Produces a pseudo-random value between 0 and 65535. From 277fd62c031d06be5ddaa592473fb3d14b7d891d Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 8 Dec 2025 08:16:23 +0100 Subject: [PATCH 089/155] Update cvbasic target to include LDFLAGS I need flags for floating point. See https://aminet.net/package/dev/cross/CVBasic --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8d2ff67..bf4991a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS = -O cvbasic: cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o - @$(CC) cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o -o $@ + @$(CC) cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o -o $@ $(LDFLAGS) check: cvbasic @./$< examples/viboritas.bas /tmp/viboritas.asm From 99aa5359bea2aac8cda4827daa4f96c12b926949 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 10 Jan 2026 10:32:29 -0600 Subject: [PATCH 090/155] Added note about .sym files for blueMSX/openMSX --- contrib/Boom_NES_v1.0.bas | 2125 +++++++++++++++++++++++++++++++++++++ cvbasic.c | 2 +- manual.txt | 14 +- 3 files changed, 2139 insertions(+), 2 deletions(-) create mode 100644 contrib/Boom_NES_v1.0.bas diff --git a/contrib/Boom_NES_v1.0.bas b/contrib/Boom_NES_v1.0.bas new file mode 100644 index 0000000..dd707f6 --- /dev/null +++ b/contrib/Boom_NES_v1.0.bas @@ -0,0 +1,2125 @@ +' BOOM! NES v1.0.25 +' Compiles with CVBasic v0.90 +' Steve Engelhardt +' 12/29/2025 + +' -- Global Palettes -- +PALETTE 0, $0F +PALETTE 1, $1A +PALETTE 2, $01 +PALETTE 3, $00 + +' -- Sprite Palettes -- +' Palette 0: Bomber & General (Black, White, Orange) +PALETTE 16, $0F +PALETTE 17, $0F +PALETTE 18, $30 ' White (Face) +PALETTE 19, $27 + +' Palette 1: Bombs (Black, White, Red) +PALETTE 20, $0F +PALETTE 21, $0F +PALETTE 22, $00 +PALETTE 23, $30 + +' Palette 2: Score (Orange) +PALETTE 24, $0F +PALETTE 25, $0F +PALETTE 26, $0F +PALETTE 27, $27 + +' Palette 3: Buckets (Black, Blue, Brown) +PALETTE 28, $0F ' Transparent +PALETTE 29, $0F ' 1 = Black (Outline) +PALETTE 30, $12 ' 2 = Blue (Water) +PALETTE 31, $07 ' 3 = Dark Brown (Body) + +' -- Variables -- + +' Bomb Arrays (Up to 8 active bombs) +DIM bomb_x(8) ' Horizontal position of each active bomb +DIM bomb_y(8) ' Vertical position of each active bomb +DIM bomb_s(8) ' Status of bomb slot (0=Inactive, 1=Active) + +' Player Bucket (Paddle) +DIM x_bucket ' Current X position of player buckets +DIM y_bucket ' Vertical anchor for buckets (usually static) + +' Bomber (Bomber) +DIM x_bomber ' Current X position of the Bomber +DIM y_bomber ' Current Y position of the Bomber +DIM bomber_dir ' Movement direction (0=Left, 1=Right) +DIM bomber_timer ' Timer used for random direction changes +DIM bomber_attr ' Sprite attribute (used for horizontal flipping) + +' Loop & Utility +DIM digit ' Temporary variable for digit calculations +DIM c ' Primary loop counter (Universal) +DIM lives ' Remaining buckets (1 to 3) +DIM r ' Secondary loop counter / temp math flag +DIM spawn_timer ' Frames until the next bomb can drop +DIM wait_timer ' General purpose delay timer + +' Drawing & Flicker Control +DIM col1_x ' Sprite column 1 X offset +DIM col2_x ' Sprite column 2 X offset +DIM col3_x ' Sprite column 3 X offset +DIM col4_x ' Sprite column 4 X offset +DIM b_vis_1 ' Visibility/Y-pos for bucket row 1 +DIM b_vis_2 ' Visibility/Y-pos for bucket row 2 +DIM b_vis_3 ' Visibility/Y-pos for bucket row 3 + +' Difficulty & Game Loop +DIM bomb_speed ' Falling speed (pixels per frame) +DIM max_spawn_delay ' Base delay between bomb drops for current wave +DIM rng_seed ' Rolling counter used for random numbers +DIM hit_detected ' Flag (1 if bomb caught, 0 if not) +DIM difficulty ' Skill level (0=Easy, 1=Std, 2=Hard) +DIM input_delay ' Prevents rapid-fire menu scrolling +DIM hit_width ' Collision width based on bucket size +DIM right_limit ' Screen boundary based on bucket size + +' Velocity / Smooth Movement +DIM b_dir ' Current velocity direction (0=none, 1=L, 2=R) +DIM b_speed ' Current pixel-speed of momentum +DIM b_subpixel ' Fractional movement for smooth acceleration + +' Wave Logic +DIM wave ' Current wave number +DIM bombs_remaining ' Bombs left to drop in current wave +DIM active_bombs ' Current count of bombs on screen +DIM found_slot ' Used to find available array index for new bomb + +' Current Score Digit Variables (for display) +DIM d_tthou ' Ten-Thousands digit +DIM d_thou ' Thousands digit +DIM d_hund ' Hundreds digit +DIM d_tens ' Tens digit +DIM d_ones ' Ones digit +DIM temp_val ' Temp storage for scoring and PPU logic + +' High Score Digit Variables +DIM h_tthou ' High Score: Ten-Thousands +DIM h_thou ' High Score: Thousands +DIM h_hund ' High Score: Hundreds +DIM h_tens ' High Score: Tens +DIM h_ones ' High Score: Ones + +' Splash Animation Arrays +DIM splash_x(3) ' Horizontal offset for catch splash +DIM splash_y(3) ' Vertical offset for catch splash +DIM splash_t(3) ' Frames remaining for splash animation + +' Menu & Rotation +DIM control_type ' 0=Digital, 1=Velocity +DIM menu_sel ' Current menu cursor selection +DIM s_row1 ' Sprite index for bucket row 1 (Priority rotation) +DIM s_row2 ' Sprite index for bucket row 2 (Priority rotation) +DIM s_row3 ' Sprite index for bucket row 3 (Priority rotation) +DIM s_ex1 ' Extra sprite for Easy mode bucket expansion +DIM s_ex2 ' Extra sprite for Easy mode bucket expansion +DIM s_ex3 ' Extra sprite for Easy mode bucket expansion +DIM last_wave ' Records wave reached before Game Over + +' Music Engine +DIM music_step ' Current step in the sequence (0-3 or 0-15) +DIM music_timer ' Frames remaining until next music step +DIM music_pattern ' Current pattern state (0=Intro, 1=Main, 2=Bridge) +DIM melody_index ' Note table index for Square 1 +DIM harmony_index ' Note table index for Square 2 +DIM bass_index ' Note table index for Triangle +DIM drum_index ' Sound type for Noise channel (1=Snare, 2=Kick) +DIM duration ' Frame length of the current note +DIM music_active ' Music toggle (1=Play, 0=Silent) +DIM sfx_timer ' Frames remaining for active Sound Effect + + +' ========================================================================= +' BOOT +' ========================================================================= +boot: + rng_seed = 0 ' Initialize random seed (will increment during title loop) + difficulty = 1 ' Default to "Standard" difficulty for a balanced first game + control_type = 0 ' Default to "Digital" controls as it's most familiar to players + menu_sel = 0 ' Start the menu cursor on the first row (Skill selection) + + ' -- Initialize Music State -- + music_active = 1 ' Enable the music engine so the title theme plays immediately + music_pattern = 0 ' Start with the Intro sequence rather than the main loop + music_timer = 0 ' Set to 0 so the engine triggers the first note instantly + music_step = 0 ' Start at the very first note (Step 0) of the Intro + +' ========================================================================= +' TITLE SCREEN +' ========================================================================= +title_screen: + SCREEN DISABLE + CLS + + ' -- Title Palettes -- + ' Palette 0: Borders & Buildings + PALETTE 0, $0F ' Slot 0 (Transparent/Global Back - Black) + PALETTE 1, $16 ' Slot 1 (Outer Border "*" - Dark Blue) + PALETTE 2, $01 ' Slot 2 (Medium Blue/Navy) + PALETTE 3, $10 ' Slot 3 (Light Grey) + + ' Palette 1: BOOM! Logo + PALETTE 4, $0F ' Slot 0 (Black) + PALETTE 5, $16 ' Slot 1 (Logo - Dark Blue) + PALETTE 6, $01 ' Slot 2 (Navy) + PALETTE 7, $10 ' Slot 3 (Light Grey) + + ' Palette 2: Box Borders + PALETTE 8, $0F ' Slot 0 (Black) + PALETTE 9, $0F ' Slot 1 (Inner Borders "\201" - Black) + PALETTE 10, $01 ' Slot 2 (Navy) + PALETTE 11, $10 ' Slot 3 (Light Grey) + + ' Palette 3: UI Text + PALETTE 12, $0F ' Slot 0 (Black) + PALETTE 13, $10 ' Slot 1 (Text - Light Grey) + PALETTE 14, $01 ' Slot 2 (Navy) + PALETTE 15, $10 ' Slot 3 (Light Grey) + + ' Sprite Palette 0: Title Screen Bomber (Bomber) + PALETTE 16, $0F ' Slot 0 (Transparent) + PALETTE 17, $0F ' Slot 1 (Black Outline) + PALETTE 18, $30 ' Slot 2 (Face/Eyes - White) + PALETTE 19, $27 ' Slot 3 (Clothes/Hat - Orange) + + ' -- DRAWING PHASE 1: Top Borders -- + PRINT AT 0, "********************************" + PRINT AT 32, "********************************" + PRINT AT 64, "*((((((((((((((((((((((((((((((*" + PRINT AT 96, "*((((((((((((((((((((((((((((((*" + PRINT AT 128, "*((((((((((((((((((((((((((((((*" + PRINT AT 160, "*((((((((((((((((((((((((((((((*" + + WAIT + + ' -- DRAWING PHASE 2: Logo Area -- + PRINT AT 192, "*((((((((((((((((((((((((((((((*" + PRINT AT 224, "*((((((((((((((((((((((((((((((*" + PRINT AT 256, "*((((((((((((((((((((((((((((((*" + PRINT AT 288, "*((((((((((((((((((((((((((((((*" + PRINT AT 320, "*((((((((((((((((((((((((((((((*" + PRINT AT 352, "*((((((((((((((((((((((((((((((*" + PRINT AT 384, "*((((((((((((((((((((((((((((((*" + + WAIT + + ' -- DRAWING PHASE 3: Score Box -- + PRINT AT 416, "*(((((\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201(((((*" + PRINT AT 448, "*(((((\201 \201(((((*" + PRINT AT 480, "*(((((\201 \201(((((*" + PRINT AT 512, "*(((((\201 \201(((((*" + PRINT AT 544, "*(((((\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201(((((*" + + PRINT AT 576, "*((((((((((((((((((((((((((((((*" + + WAIT + + ' -- DRAWING PHASE 4: Difficulty Box -- + PRINT AT 608, "*(((((\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201(((((*" + PRINT AT 640, "*(((((\201 \201(((((*" + PRINT AT 672, "*(((((\201 \201(((((*" + PRINT AT 704, "*(((((\201 \201(((((*" + PRINT AT 736, "*(((((\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201\201(((((*" + + WAIT + + ' -- DRAWING PHASE 5: Bottom Closure -- + PRINT AT 768, "*((((((((((((((((((((((((((((((*" + PRINT AT 800, "********************************" + + WAIT + + ' Row 27 (864 + 4): Copyright shifted up one row + PRINT AT 868, "\127 2026 STEVE ENGELHARDT" + + ' Sprites for Bomber + SPRITE 0, 16, 110, 128, 0 + SPRITE 1, 16, 110 + 8, 130, 0 + SPRITE 2, 16 + 16, 110, 132, 0 + SPRITE 3, 16 + 16, 110 + 8, 134, 0 + + ' Hide all unused sprites (4-63) by moving them off-screen to Y=240 + FOR c = 4 TO 63: SPRITE c, 240, 0, 0, 0: NEXT c + + ' Title Logo (BOOM!) + PRINT AT 197, "\200\200\200" + PRINT AT 229, "\200((\200" + PRINT AT 261, "\200\200\200" + PRINT AT 293, "\200((\200" + PRINT AT 325, "\200\200\200" + PRINT AT 202, "(\200\200(" + PRINT AT 234, "\200((\200" + PRINT AT 266, "\200((\200" + PRINT AT 298, "\200((\200" + PRINT AT 330, "(\200\200(" + PRINT AT 207, "(\200\200(" + PRINT AT 239, "\200((\200" + PRINT AT 271, "\200((\200" + PRINT AT 303, "\200((\200" + PRINT AT 335, "(\200\200(" + PRINT AT 212, "\200(((\200" + PRINT AT 244, "\200\200(\200\200" + PRINT AT 276, "\200(\200(\200" + PRINT AT 308, "\200(((\200" + PRINT AT 340, "\200(((\200" + PRINT AT 218, "\200" + PRINT AT 250, "\200" + PRINT AT 282, "\200" + PRINT AT 346, "\200" + + ' -- HIGH SCORE (Row 14, Col 7) -- + PRINT AT 455, "HIGH SCORE: ", d_tthou, d_thou, d_hund, d_tens, d_ones + + ' -- LAST SCORE (Row 15, Col 7) -- + PRINT AT 487, "LAST SCORE: ", d_tthou, d_thou, d_hund, d_tens, d_ones + + ' -- LAST WAVE (Row 16, Col 7) -- + temp_val = last_wave + ' Calculate wave digits manually + r = temp_val / 10 + c = temp_val % 10 + PRINT AT 519, "LAST WAVE: ", 0, 0, 0, r, c + + ' Labels + PRINT AT 647, "SKILL:" + PRINT AT 679, "CONTROLS:" + PRINT AT 711, "PRESS A TO START" + + SCREEN ENABLE ' Turn on the PPU to begin displaying the title screen + input_delay = 0 ' Reset controller delay so menu navigation is instant + + ' -- Title Screen Music Initialization -- + music_step = 0 ' Start sequence at the first note + music_timer = 0 ' Reset timer to trigger the first note immediately + music_pattern = 0 ' Start with Intro (Pattern 0) + music_active = 1 ' Enable the music engine for the title loop + + ' -- Setup Title Bomber (Bomber) -- + x_bomber = 110 ' Center the Bomber horizontally at start + y_bomber = 16 ' Position Bomber at the top of the screen + bomber_dir = 1 ' Set initial movement to the Right + bomber_timer = 0 ' Reset movement timer for random direction changes + + ' -- Setup Title Bomb (Sprite 11) -- + ' This manages the bomb that falls behind the title screen text + found_slot = 0 ' State: 0 = Ready to drop, 1 = Currently falling + temp_val = 0 ' Stores current Y position of the title bomb + r = 0 ' Stores current X position of the title bomb + +title_loop: + WAIT ' Synchronize with the NES Vertical Blank (60 frames per second) + + ' Call the music sequencer every frame if it is currently enabled + IF music_active = 1 THEN GOSUB title_music_update + + ' Increment the random number generator seed while the user is on the title screen + rng_seed = rng_seed + 1 + + ' --- RANDOM BOMBER MOVEMENT (Logo Range: 40 to 199) --- + bomber_timer = bomber_timer + 1 ' Increment the decision timer + + ' Check every 11 frames to see if the Bomber wants to change direction + IF bomber_timer > 10 THEN + bomber_timer = 0 ' Reset the decision timer + c = RANDOM(127) ' Generate a random value between 0 and 127 + IF c > 100 THEN bomber_dir = 1 ' Small chance to force movement Right + IF c < 27 THEN bomber_dir = 0 ' Small chance to force movement Left + END IF + + ' Apply movement based on current direction + IF bomber_dir = 1 THEN + x_bomber = x_bomber + 2 ' Move Right at a constant title-speed + + ' Right Limit: 199 (Strictly above the main logo text) + IF x_bomber > 199 THEN + x_bomber = 199 ' Snap back to the boundary edge + bomber_dir = 0 ' Force direction change to Left + bomber_timer = 0 ' Reset timer to prevent instant jitter + END IF + ELSE + x_bomber = x_bomber - 2 ' Move Left at a constant title-speed + + ' Left Limit: Start of the "B" (40) + IF x_bomber < 40 THEN + x_bomber = 40 ' Snap back to the boundary edge + bomber_dir = 1 ' Force direction change to Right + bomber_timer = 0 ' Reset timer to prevent instant jitter + END IF + END IF + + ' --- TITLE BOMB LOGIC (Decorative Animation) --- + ' Check if the title bomb is currently "reloading" or active + IF found_slot = 0 THEN + ' Bomb is ready: Roll for a random drop chance (~11% chance per frame) + c = RANDOM(255) + IF c > 225 THEN + found_slot = 1 ' Set state to "Falling" + temp_val = y_bomber + 16 ' Set start Y relative to Bomber's height + r = x_bomber + 4 ' Set start X to center under the Bomber + END IF + ELSE + ' Bomb is active: Move it down 2 pixels per frame + temp_val = temp_val + 2 + + ' Update hardware Sprite 11 (Pattern 138, Palette 1) + SPRITE 11, temp_val, r, 138, 1 + + ' Check if bomb reached the "Floor" of the title logo area + IF temp_val >= 88 THEN + found_slot = 0 ' Reset state to "Ready" + temp_val = 0 ' Reset Y position variable + ' Move Sprite 11 off-screen to Y=240 to hide it until next drop + SPRITE 11, 240, 0, 0, 0 + END IF + END IF + + ' --- DRAW THE BOMBER (Sprites 0-3) --- + ' This handles the multi-sprite Bomber and flips the tiles when turning + IF bomber_dir = 1 THEN + ' Moving RIGHT: Use standard tile layout and attributes + SPRITE 0, y_bomber, x_bomber, 128, 0 ' Head Left + SPRITE 1, y_bomber, x_bomber + 8, 130, 0 ' Head Right + SPRITE 2, y_bomber + 16, x_bomber, 132, 0 ' Body Left + SPRITE 3, y_bomber + 16, x_bomber + 8, 134, 0 ' Body Right + ELSE + ' Moving LEFT: Swap tile positions and apply Horizontal Flip (Attribute 64) + SPRITE 0, y_bomber, x_bomber, 130, 64 ' Right tile moves to Left pos, flipped + SPRITE 1, y_bomber, x_bomber + 8, 128, 64 ' Left tile moves to Right pos, flipped + SPRITE 2, y_bomber + 16, x_bomber, 134, 64 ' Right body moves to Left, flipped + SPRITE 3, y_bomber + 16, x_bomber + 8, 132, 64 ' Left body moves to Right, flipped + END IF + + ' --- MENU LOGIC (Selection & Input Debouncing) --- + ' Count down the input delay to prevent ultra-fast scrolling + IF input_delay > 0 THEN + input_delay = input_delay - 1 + END IF + + ' Process new inputs only when the delay timer has reached zero + IF input_delay = 0 THEN + ' NAVIGATE ROWS (Up/Down) + ' Switch between Skill (0) and Control (1) rows + IF cont1.up AND menu_sel > 0 THEN + menu_sel = 0 + input_delay = 12 ' 12-frame pause before next movement + END IF + IF cont1.down AND menu_sel < 1 THEN + menu_sel = 1 + input_delay = 12 ' 12-frame pause before next movement + END IF + + ' CHANGE VALUES (Left/Right) + ' Logic depends on which row the cursor is currently on + IF menu_sel = 0 THEN + ' Modify Difficulty Level (0=Easy, 1=Std, 2=Hard) + IF cont1.left AND difficulty > 0 THEN + difficulty = difficulty - 1 + input_delay = 10 ' Slightly faster repeat for value changes + END IF + IF cont1.right AND difficulty < 2 THEN + difficulty = difficulty + 1 + input_delay = 10 ' Slightly faster repeat for value changes + END IF + ELSE + ' Toggle Control Type (0=Standard, 1=Velocity) + ' This uses binary flipping (1 - current_value) + IF cont1.left OR cont1.right THEN + control_type = 1 - control_type + input_delay = 12 ' Standard pause for toggle + END IF + END IF + END IF + + ' --- REDRAW UI (Text Updates) --- + ' Update the difficulty box text based on current selection + IF difficulty = 0 THEN + PRINT AT 657, "< EASY >" + ELSEIF difficulty = 1 THEN + PRINT AT 657, "< STD >" + ELSE + PRINT AT 657, "< HARD >" + END IF + + ' Update the control mode box text (Standard vs. Velocity) + IF control_type = 0 THEN + PRINT AT 689, "< STD >" + ELSE + PRINT AT 689, "< VEL >" + END IF + + ' --- DRAW CURSOR (Sprite 10) --- + ' Position the circular cursor sprite next to the active menu row + IF menu_sel = 0 THEN + ' Row 0: Skill/Difficulty (Y=159, X=48, Tile 146, Palette 3) + SPRITE 10, 159, 48, 146, 3 + ELSE + ' Row 1: Controls (Y=167, X=48, Tile 146, Palette 3) + SPRITE 10, 167, 48, 146, 3 + END IF + + ' --- START GAME TRIGGER --- + ' Check if the Start/A button is pressed to begin the game + IF cont1.button THEN + ' Use the current title-screen timer to finalize the random seed + c = RANDOM(rng_seed) + + ' Clean up UI elements before transitioning + SPRITE 10, 240, 0, 0, 0 ' Hide the menu cursor off-screen + music_active = 0 ' Stop the title music sequence + GOSUB audio_silence_all ' Immediately kill all active sound registers + + GOTO restart ' Jump to the main game setup + END IF + + GOTO title_loop ' Repeat the title loop until a button is pressed + +' ========================================================================= +' SUBROUTINE: TITLE MUSIC UPDATE +' ========================================================================= +title_music_update: + + ' Note-Off / Staccato Logic + ' Briefly silences channels before a new note to prevent a "slurring" sound + IF music_timer = 2 THEN + POKE $4000, $30 ' Mute Square 1 (Melody) + POKE $4004, $30 ' Mute Square 2 (Harmony) + POKE $4008, $80 ' Mute Triangle (Bass) + ' Noise is skipped here to allow drum decay to finish naturally + END IF + + ' Countdown Timer + ' Stays on the current note until the duration reaches zero + IF music_timer > 0 THEN + music_timer = music_timer - 1 + RETURN ' Exit sub; note is still playing + END IF + + ' FETCH DATA & ADVANCE PATTERNS + ' Determines which musical section we are in and pulls data from arrays + IF music_pattern = 0 THEN + ' --- INTRO (4 Steps) --- + melody_index = title_intro_melody(music_step) + harmony_index = title_intro_harmony(music_step) + bass_index = title_intro_bass(music_step) + drum_index = title_intro_drums(music_step) + duration = title_intro_duration(music_step) + + music_step = music_step + 1 + IF music_step > 3 THEN + music_step = 0 + music_pattern = 1 ' Advance to Main Loop (Pattern A) + END IF + + ELSEIF music_pattern = 1 THEN + ' --- PATTERN A: Main Theme (16 Steps) --- + melody_index = title_melody(music_step) + harmony_index = title_harmony(music_step) + bass_index = title_bass(music_step) + drum_index = title_drums(music_step) + duration = title_duration(music_step) + + music_step = music_step + 1 + IF music_step > 15 THEN + music_step = 0 + music_pattern = 2 ' Advance to Bridge (Pattern B) + END IF + + ELSE + ' --- PATTERN B: Bridge / Variation (16 Steps) --- + melody_index = title_melody_b(music_step) + harmony_index = title_harmony_b(music_step) + bass_index = title_bass_b(music_step) + drum_index = title_drums_b(music_step) + duration = title_duration_b(music_step) + + music_step = music_step + 1 + IF music_step > 15 THEN + music_step = 0 + music_pattern = 1 ' Loop back to Main Theme + END IF + END IF + + ' WRITE TO HARDWARE (POKE TO APU REGISTERS) + + ' Square 1 (Melody) + ' $BF = Duty 10, Length Ctr Disabled, Constant Vol, Vol 15 + IF melody_index = 255 THEN + POKE $4000, $30 ' Silence channel if data is a REST + ELSE + POKE $4000, $BF ' Set volume and duty cycle + POKE $4002, note_table_low(melody_index) ' Fine tune frequency + POKE $4003, note_table_high(melody_index) ' Course tune frequency & trigger + END IF + + ' Square 2 (Harmony) + ' $7A = Duty 01, Length Ctr Disabled, Constant Vol, Vol 10 + IF harmony_index = 255 THEN + POKE $4004, $30 + ELSE + POKE $4004, $7A ' Set volume and different duty for texture + POKE $4006, note_table_low(harmony_index) + POKE $4007, note_table_high(harmony_index) + END IF + + ' Triangle (Bass) + ' $FF = Linear Counter control enabled + IF bass_index = 255 THEN + POKE $4008, $80 + ELSE + POKE $4008, $FF ' Turn Triangle ON + POKE $400A, note_table_low(bass_index) + POKE $400B, note_table_high(bass_index) + END IF + + ' Noise (Drums) + ' Uses Hardware Envelopes ($1x) for percussion decay + IF drum_index = 1 THEN + ' Snare Drum: Mid-pitch hiss with decay + POKE $400C, $18 + POKE $400E, $01 + ELSEIF drum_index = 2 THEN + ' Kick Drum: Low-frequency thud with decay + POKE $400C, $1A + POKE $400E, $0F + ELSE + ' Silence Noise Channel + POKE $400C, $30 + END IF + + ' Start Note Timer + ' Set duration for the current note before next update cycle + music_timer = duration + + RETURN + +' ========================================================================= +' GAME SETUP +' ========================================================================= +restart: + + POKE $4015, $0F ' enable all APU channels (including noise) + + ' -- GAME PALETTES (Reset for Gameplay) -- + ' Background Palettes (Used by Cityscape and Sky) + PALETTE 0, $0F ' Slot 0 (Black - Global Background) + PALETTE 1, $1A ' Slot 1 (Green - Floor/Grass) + PALETTE 2, $01 ' Slot 2 (Medium Blue - Sky/Buildings) + PALETTE 3, $00 ' Slot 3 (Dark Grey - Buildings) + + ' Sprite Palette 0 (Bomber / Bomber) + PALETTE 16, $0F ' Slot 0 (Transparent) + PALETTE 17, $0F ' Slot 1 (Black - Outline) + PALETTE 18, $30 ' Slot 2 (White - Face/Eyes) + PALETTE 19, $27 ' Slot 3 (Orange - Hat/Clothes) + + ' Sprite Palette 1 (Bombs) + PALETTE 20, $0F ' Slot 0 (Transparent) + PALETTE 21, $0F ' Slot 1 (Black - Fuse/Wick) + PALETTE 22, $00 ' Slot 2 (Grey - Highlight) + PALETTE 23, $30 ' Slot 3 (White - Spark) + + ' Sprite Palette 2 (Score Digits) + PALETTE 24, $0F ' Slot 0 (Transparent) + PALETTE 25, $0F ' Slot 1 (Black - Drop Shadow) + PALETTE 26, $0F ' Slot 2 (Black - Unused) + PALETTE 27, $27 ' Slot 3 (Orange - Digit Color) + + ' Sprite Palette 3 (Buckets & Splash) + PALETTE 28, $0F ' Slot 0 (Transparent) + PALETTE 29, $0F ' Slot 1 (Black - Outline) + PALETTE 30, $12 ' Slot 2 (Blue - Water/Splash) + PALETTE 31, $07 ' Slot 3 (Dark Brown - Bucket Body) + + ' -- Reset Gameplay Variables -- + score = 0 ' Clear current session score + d_tthou = 0 ' Reset Ten-Thousands digit display + d_thou = 0 ' Reset Thousands digit display + d_hund = 0 ' Reset Hundreds digit display + d_tens = 0 ' Reset Tens digit display + d_ones = 0 ' Reset Ones digit display + lives = 3 ' Start player with a full stack of 3 buckets + wave = 1 ' Begin the challenge at Wave 1 + + ' -- Position Actors -- + x_bucket = 110 ' Start player buckets in the center of the screen + x_bomber = 110 ' Start the Bomber in the center of the sky + y_bomber = 26 ' Position the Bomber just below the cityscape skyline + bomber_dir = 1 ' Set initial Bomber movement to the Right + + ' -- Global Sprite Reset -- + ' Clear all 64 sprites by moving them to Y=255 (Off-screen) + FOR c = 0 TO 63 + SPRITE c, 255, 0, 0, 0 + NEXT c + + ' -- Difficulty Scaling Update -- + ' Adjust collision math and movement boundaries based on Title Screen selection + IF difficulty = 0 THEN + ' EASY: Wide catch area (4 sprites / 32 pixels) + hit_width = 32 + right_limit = 216 ' Clamp X earlier to account for wider sprites + ELSEIF difficulty = 1 THEN + ' STD: Medium catch area (3 sprites / 24 pixels) + hit_width = 24 + right_limit = 224 ' Standard screen clamping + ELSE + ' HARD: Narrow catch area (2 sprites / 16 pixels) + hit_width = 16 + right_limit = 232 ' Allow further movement to the right + END IF + + ' -- Reset Splash Animation State -- + ' Clear all active water splash timers and offsets across all 3 bucket rows + FOR r = 0 TO 2 + splash_t(r) = 0 ' Reset frame timer (kills active splashes) + splash_x(r) = 0 ' Reset horizontal offset + splash_y(r) = 0 ' Reset vertical offset + NEXT r + + ' -- Prepare Display for Game World -- + SCREEN DISABLE ' Turn off PPU to allow fast background tile writing + CLS ' Clear the current Name Table (background) + + ' Clean OAM (Sprite Memory) by hiding all 64 sprites off-screen + FOR c = 0 TO 63 + SPRITE c, 240, 0, 0, 0 + NEXT c + + ' --- DRAW STATIC CITYSCAPE --- + ' Draw the sky/clouds (Pattern 42 '*') across the top 2 rows + FOR r = 0 TO 1 + PRINT AT r * 32, "***********************(((******" + NEXT r + + ' Draw the building tops and skyline details (Rows 2-6) + PRINT AT 2 * 32, "****(((((*(((*((((*****( (*(((((" + PRINT AT 3 * 32, "****( ( (*( (*( ((*****(((*( ( (" + PRINT AT 4 * 32, "(((*(((((*(((*((((*(((*(((*(((((" + PRINT AT 5 * 32, "( (*( ( (*( (*((((*(((*(((*( (((" + PRINT AT 6 * 32, "(((*(((((*(((*((((*(((*(((*(((((" + + ' Draw the main city wall/floor (Pattern 41 ')') from Row 7 down to 27 + FOR r = 7 TO 27 + PRINT AT r * 32, "))))))))))))))))))))))))))))))))" + NEXT r + + SCREEN ENABLE ' Turn display back on now that background is ready + + ' -- Final Game State Initialization -- + ' Ensure all 8 bomb slots are marked as inactive (0) before the wave starts + FOR c = 0 TO 7 + bomb_s(c) = 0 + NEXT c + + GOSUB new_game_pause ' Show "Ready?" prompt and wait for player input + GOTO start_wave ' Jump to the wave-specific logic and bomb spawning + +' ========================================================================= +' WAVE SETUP (Difficulty & Scaling Logic) +' ========================================================================= +start_wave: + spawn_timer = 30 ' Initial 0.5-second pause before the first bomb drops + + ' -- BOMB QUANTITY -- + ' Gradually increase total bombs per wave (e.g., Wave 1 = 17, Wave 10 = 35) + bombs_remaining = 15 + (wave * 2) + + ' -- VERTICAL FALL SPEED -- + bomb_speed = 2 ' Base speed for Standard/Easy early waves + IF difficulty = 2 THEN bomb_speed = 3 ' Hard mode starts at a higher base speed + IF wave > 2 THEN bomb_speed = 3 ' Increase speed at Wave 3 + IF wave > 5 THEN bomb_speed = 4 ' Increase speed at Wave 6 + IF wave > 8 THEN bomb_speed = 5 ' Increase speed at Wave 9 + + ' Fairness Speed Cap: Ensure bombs never exceed 5 pixels per frame + IF bomb_speed > 5 THEN bomb_speed = 5 + + ' -- SPAWN DENSITY (The "Rhythm") -- + ' Formula creates a tighter drop interval as waves progress + max_spawn_delay = 20 - (wave * 2) + + ' Adjust spawn rhythm based on chosen skill level + IF difficulty = 0 THEN max_spawn_delay = max_spawn_delay + 4 ' Slower drops for Easy + IF difficulty = 2 THEN max_spawn_delay = max_spawn_delay - 4 ' Faster drops for Hard + + ' fairness Floor: Never drop faster than once every 4 frames (the limit of human reaction) + IF max_spawn_delay < 4 THEN max_spawn_delay = 4 + + WAIT ' Final frame sync before jumping into the game loop + +' ========================================================================= +' MAIN GAME LOOP +' ========================================================================= +game_loop: + + ' --- MOVEMENT SELECTION (Player Input & Physics) --- + + IF control_type = 0 THEN + ' -- TIGHT CONTROLS (Classic Digital Style) -- + ' Instant 4-pixel movement with boundary checking + IF cont1.left AND x_bucket > 8 THEN + x_bucket = x_bucket - 4 + END IF + IF cont1.right AND x_bucket < right_limit THEN + x_bucket = x_bucket + 4 + END IF + ELSE + ' -- SMOOTH CONTROLS (Momentum Physics + Magnet Assist) -- + + ' Acceleration Logic + IF cont1.left THEN + b_dir = 1 ' Set intent to Left + b_subpixel = b_subpixel + 80 + ' If subpixel overflows (8-bit roll), increment actual speed + IF b_subpixel < 80 THEN + IF b_speed < 4 THEN b_speed = b_speed + 1 + END IF + ELSEIF cont1.right THEN + b_dir = 2 ' Set intent to Right + b_subpixel = b_subpixel + 80 + IF b_subpixel < 80 THEN + IF b_speed < 4 THEN b_speed = b_speed + 1 + END IF + ELSE + ' 2. Friction/Deceleration (Active when no buttons are pressed) + b_subpixel = b_subpixel + 40 + IF b_subpixel < 40 THEN + IF b_speed > 0 THEN + b_speed = b_speed - 1 + ELSE + b_dir = 0 ' Full stop + END IF + END IF + END IF + + ' Apply Velocity to Screen Position + IF b_dir = 1 THEN x_bucket = x_bucket - b_speed + IF b_dir = 2 THEN x_bucket = x_bucket + b_speed + + ' Magnet Assist (Corrects for near-misses in Smooth mode) + ' Loops through all active bombs to see if any are close enough to "pull" the bucket + FOR c = 0 TO 7 + IF bomb_s(c) = 1 THEN + ' Manual Absolute Difference calculation (8-bit safe) + temp_val = bomb_x(c) - x_bucket + IF temp_val > 127 THEN temp_val = 256 - temp_val + + ' If bucket is within 12 pixels of a falling bomb, apply a 1-pixel nudge + IF temp_val < 12 THEN + IF b_dir = 2 AND bomb_x(c) > x_bucket THEN x_bucket = x_bucket + 1 + IF b_dir = 1 AND bomb_x(c) < x_bucket THEN x_bucket = x_bucket - 1 + END IF + END IF + NEXT c + END IF + + ' -- Global Boundary Clamping -- + ' Prevents the bucket from sliding off the left or right edges of the city + IF x_bucket < 8 THEN + x_bucket = 8 ' Snap to left boundary + b_speed = 0 ' Kill momentum in Velocity mode + END IF + IF x_bucket > right_limit THEN + x_bucket = right_limit ' Snap to right boundary (calculated by difficulty) + b_speed = 0 ' Kill momentum in Velocity mode + END IF + + ' -- Bomber (Bomber) AI & Movement -- + ' Decision Logic: Every 11 frames, roll for a possible direction change + bomber_timer = bomber_timer + 1 + IF bomber_timer > 10 THEN + bomber_timer = 0 + c = RANDOM(127) + IF c > 100 THEN bomber_dir = 1 ' Shift intent to Right + IF c < 27 THEN bomber_dir = 0 ' Shift intent to Left + END IF + + ' Physical Movement & Screen Wrapping + IF bomber_dir = 1 THEN + x_bomber = x_bomber + 2 ' Standard horizontal speed + IF x_bomber > 220 THEN bomber_dir = 0 ' Turn around at right edge + ELSE + x_bomber = x_bomber - 2 + IF x_bomber < 16 THEN bomber_dir = 1 ' Turn around at left edge + END IF + + ' -- Bomb Spawning Logic -- + active_bombs = 0 ' Reset counter for the frame's update + + ' Only decrement spawn timer if there are bombs left in the wave + IF spawn_timer > 0 THEN spawn_timer = spawn_timer - 1 + + ' Trigger a new drop when timer hits zero and wave is not empty + IF spawn_timer = 0 AND bombs_remaining > 0 THEN + ' Find an empty slot in the bomb array (Indices 0-7) + FOR c = 0 TO 7 + IF bomb_s(c) = 0 THEN + bomb_x(c) = x_bomber + 4 ' Spawn at Bomber's current X center + bomb_y(c) = y_bomber + 24 ' Spawn just below the Bomber's sprites + bomb_s(c) = 1 ' Activate the bomb + spawn_timer = max_spawn_delay ' Reset rhythm timer + bombs_remaining = bombs_remaining - 1 ' Deduct from wave pool + c = 7 ' Exit the search early (one bomb per frame) + END IF + NEXT c + END IF + + FOR c = 0 TO 7 + IF bomb_s(c) = 1 THEN + active_bombs = active_bombs + 1 + bomb_y(c) = bomb_y(c) + bomb_speed + hit_detected = 0 + + ' Catch zones + IF bomb_x(c) > x_bucket - 4 AND bomb_x(c) < x_bucket + hit_width THEN + ' Bottom bucket row: centered at 212, 8px tall + IF bomb_y(c) >= 212 AND bomb_y(c) < 220 THEN hit_detected = 1 + + ' Middle bucket row (only if 2+ lives): centered at 194 + IF lives >= 2 THEN + IF bomb_y(c) >= 194 AND bomb_y(c) < 202 THEN hit_detected = 1 + END IF + + ' Top bucket row (only if 3 lives): centered at 176 + IF lives >= 3 THEN + IF bomb_y(c) >= 176 AND bomb_y(c) < 184 THEN hit_detected = 1 + END IF + END IF + + IF hit_detected = 1 THEN + bomb_s(c) = 0 + GOSUB splash_sfx + IF score < 9999 THEN score = score + 1 + GOSUB add_score_point + + ' --- SPLASH TRIGGER --- + ' Determine which bucket row was hit (matching the ranges above) + IF bomb_y(c) >= 212 AND bomb_y(c) < 220 THEN r = 0 + IF bomb_y(c) >= 194 AND bomb_y(c) < 202 THEN r = 1 + IF bomb_y(c) >= 176 AND bomb_y(c) < 184 THEN r = 2 + + splash_x(r) = bomb_x(c) - x_bucket + splash_y(0) = 212 - 8 + splash_y(1) = 194 - 8 + splash_y(2) = 176 - 8 + splash_t(r) = 12 ' lasts 12 frames + + + END IF + + IF bomb_y(c) >= 230 THEN + bomb_s(c) = 0 + GOSUB bomb_missed_sfx + lives = lives - 1 + IF lives < 1 THEN + lives = 0 + + ' Clear splash before game over + FOR r = 0 TO 2 + splash_t(r) = 0 + SPRITE 4 + r, 255, 0, 0, 0 + NEXT r + GOSUB game_over_sfx + GOTO game_over_screen + END IF + WAIT + + ' Clear splash before life-lost screen + FOR r = 0 TO 2 + splash_t(r) = 0 + SPRITE 4 + r, 255, 0, 0, 0 + NEXT r + + GOTO life_lost_draw + END IF + END IF + NEXT c + + ' If wave is done, clear splash and go to wave complete + IF bombs_remaining = 0 AND active_bombs = 0 THEN + GOSUB wave_complete_sfx + FOR r = 0 TO 2 + splash_t(r) = 0 + SPRITE 4 + r, 255, 0, 0, 0 + NEXT r + GOTO wave_completed + END IF + + ' --- DRAWING --- + FOR c = 20 TO 39 : SPRITE c, 255, 0, 0, 0 : NEXT c + FOR c = 48 TO 63 : SPRITE c, 255, 0, 0, 0 : NEXT c + + GOSUB draw_bomber_sub + + ' -- DETERMINE PRIORITY ROTATION -- + ' We rotate which row gets the "low" (high priority) sprite indices + ' using the rng_seed as a frame counter. + ' This was designed to help with flicker, but honestly doesn't really help much. + temp_val = rng_seed % 3 + IF temp_val = 0 THEN + s_row1 = 24 + s_row2 = 27 + s_row3 = 30 + s_ex1 = 33 + s_ex2 = 34 + s_ex3 = 35 + ELSEIF temp_val = 1 THEN + s_row1 = 30 + s_row2 = 24 + s_row3 = 27 + s_ex1 = 35 + s_ex2 = 33 + s_ex3 = 34 + ELSE + s_row1 = 27 + s_row2 = 30 + s_row3 = 24 + s_ex1 = 34 + s_ex2 = 35 + s_ex3 = 33 + END IF + + ' -- DRAW BUCKET ROWS -- + col1_x = x_bucket + col2_x = x_bucket + 8 + col3_x = x_bucket + 16 + col4_x = x_bucket + 24 + + b_vis_1 = 212 + IF lives >= 2 THEN + b_vis_2 = 194 + ELSE + b_vis_2 = 255 + END IF + IF lives >= 3 THEN + b_vis_3 = 176 + ELSE + b_vis_3 = 255 + END IF + + ' Draw Row 1 + SPRITE s_row1, b_vis_1, col1_x, 136, 3 + SPRITE s_row1 + 1, b_vis_1, col2_x, 136, 3 + IF difficulty < 2 THEN + SPRITE s_row1 + 2, b_vis_1, col3_x, 136, 3 + ELSE + SPRITE s_row1 + 2, 255, 0, 0, 0 + END IF + IF difficulty = 0 THEN + SPRITE s_ex1, b_vis_1, col4_x, 136, 3 + ELSE + SPRITE s_ex1, 255, 0, 0, 0 + END IF + + ' Draw Row 2 + SPRITE s_row2, b_vis_2, col1_x, 136, 3 + SPRITE s_row2 + 1, b_vis_2, col2_x, 136, 3 + IF difficulty < 2 AND b_vis_2 < 255 THEN + SPRITE s_row2 + 2, b_vis_2, col3_x, 136, 3 + ELSE + SPRITE s_row2 + 2, 255, 0, 0, 0 + END IF + IF difficulty = 0 AND b_vis_2 < 255 THEN + SPRITE s_ex2, b_vis_2, col4_x, 136, 3 + ELSE + SPRITE s_ex2, 255, 0, 0, 0 + END IF + + ' Draw Row 3 + SPRITE s_row3, b_vis_3, col1_x, 136, 3 + SPRITE s_row3 + 1, b_vis_3, col2_x, 136, 3 + IF difficulty < 2 AND b_vis_3 < 255 THEN + SPRITE s_row3 + 2, b_vis_3, col3_x, 136, 3 + ELSE + SPRITE s_row3 + 2, 255, 0, 0, 0 + END IF + IF difficulty = 0 AND b_vis_3 < 255 THEN + SPRITE s_ex3, b_vis_3, col4_x, 136, 3 + ELSE + SPRITE s_ex3, 255, 0, 0, 0 + END IF + + ' Splash animation follows bucket + FOR r = 0 TO 2 + IF splash_t(r) > 0 THEN + SPRITE 4 + r, splash_y(r), x_bucket + splash_x(r), 140, 3 + splash_t(r) = splash_t(r) - 1 + ELSE + SPRITE 4 + r, 255, 0, 0, 0 + END IF + NEXT r + + ' Draw Score + GOSUB redraw_score + + FOR c = 0 TO 7 + IF bomb_s(c) = 1 THEN + SPRITE 40 + c, bomb_y(c), bomb_x(c), 138, 1 + ELSE + SPRITE 40 + c, 255, 0, 0, 0 + END IF + NEXT c + + WAIT + + GOTO game_loop + +' ========================================================================= +' MUSIC DATA: NOTE TABLE +' ========================================================================= + +note_table_low: + DATA $F1, $D5, $BC, $A8, $8F, $7A, $68, $5A, $4E, $45, $3D, $36 + +note_table_high: + DATA $02, $02, $02, $02, $03, $03, $03, $03, $03, $03, $03, $03 + +' ========================================================================= +' MUSIC DATA: TITLE THEME SEQUENCES +' ========================================================================= + +title_intro_melody: + DATA 7, 9, 12, 11 + +title_intro_harmony: + DATA 4, 7, 9, 7 + +title_intro_bass: + DATA 0, 0, 0, 0 + +title_intro_drums: + DATA 2,1,2,1 + +title_intro_duration: + DATA 18,18,18,18 + +title_melody: + DATA 0,2,4,5,7,5,4,2,0,2,4,7,5,4,2,0 + +title_harmony: + DATA 7,9,11,0,2,0,11,9,7,9,11,2,0,11,9,7 + +title_bass: + DATA 0,0,7,7,0,0,7,7,0,0,7,7,0,0,7,7 + +title_drums: + DATA 2,0,1,0,2,0,1,0,2,0,1,0,2,1,2,1 + +title_duration: + DATA 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12 + +title_melody_b: + DATA 4,5,7,9,11,9,7,5,7,9,11,12,11,9,7,5 + +title_harmony_b: + DATA 7,9,11,12,12,11,9,7,9,11,12,14,12,11,9,7 + +title_bass_b: + DATA 0,0,5,5,7,7,9,9,5,5,7,7,9,9,11,11 + +title_drums_b: + DATA 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1 + +title_duration_b: + DATA 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14 + +audio_silence_all: + ' Square 1 + POKE $4000, $30 + POKE $4001, $00 + POKE $4002, $00 + POKE $4003, $00 + + ' Square 2 + POKE $4004, $30 + POKE $4005, $00 + POKE $4006, $00 + POKE $4007, $00 + + ' Triangle + POKE $4008, $80 + POKE $400A, $00 + POKE $400B, $00 + + ' Noise + POKE $400C, $00 + POKE $400E, $00 + POKE $400F, $00 + + RETURN + +splash_sfx: + ' Ensure noise channel is enabled + POKE $4015, $0F + + ' --- Start of splash --- + ' Volume = 0x1F (loud), constant envelope + POKE $400C, $1F + + ' Start with a mid‑pitch noise (watery) + POKE $400E, $84 + + ' Trigger the noise channel (critical) + POKE $400F, $FF + + ' Hold the initial burst for a frame + WAIT + + ' Slightly lower pitch (falling splash) + POKE $400E, $06 + WAIT + + ' Lower again (tail of splash) + POKE $400E, $08 + WAIT + + ' Fade out + POKE $400C, $0C + WAIT + + ' Silence + POKE $400C, $00 + RETURN + +bomb_missed_sfx: + ' Enable channels + POKE $4015, $0F + + ' --- Initial blast --- + POKE $400C, $1F ' max volume + POKE $400E, $80 ' short-mode noise, high pitch + POKE $400F, $20 ' trigger with a longer length + WAIT + WAIT + + ' --- Mid burst --- + POKE $400E, $88 + WAIT + WAIT + + ' --- Tail rumble --- + POKE $400E, $8F + WAIT + WAIT + + ' --- Fade --- + POKE $400C, $0C + WAIT + WAIT + + ' Silence + POKE $400C, $00 + RETURN + +wave_complete_sfx: + ' Enable channels + POKE $4015, $0F + + ' First note (high) + POKE $4000, $BF ' square 1, constant volume + POKE $4002, $4E ' B5 low byte + POKE $4003, $03 ' B5 high byte + WAIT + WAIT + + ' Second note (higher) + POKE $4002, $45 ' C6 low byte + POKE $4003, $03 ' C6 high byte + WAIT + WAIT + + ' Silence + POKE $4000, $30 + RETURN + +game_over_sfx: + ' Enable channels + POKE $4015, $0F + + ' Note 1 (mid) + POKE $4000, $BF + POKE $4002, $A8 ' D5-ish + POKE $4003, $02 + WAIT + WAIT + + ' Note 2 (lower) + POKE $4002, $BC ' C#5-ish + POKE $4003, $02 + WAIT + WAIT + + ' Note 3 (lowest) + POKE $4002, $D5 ' B4-ish + POKE $4003, $02 + WAIT + WAIT + + ' Silence + POKE $4000, $30 + RETURN + +' --------------------------------------------------------- +' SUBROUTINE: ADD SCORE POINT +' --------------------------------------------------------- +add_score_point: + ' Increment total score tracker (for high score comparison later) + IF score_val < 32767 THEN + score_val = score_val + 1 + END IF + + ' Ripple Carry Logic for 5 Digits + d_ones = d_ones + 1 + IF d_ones > 9 THEN + d_ones = 0 + d_tens = d_tens + 1 + IF d_tens > 9 THEN + d_tens = 0 + d_hund = d_hund + 1 + IF d_hund > 9 THEN + d_hund = 0 + d_thou = d_thou + 1 + ' Extra Life every 1,000 points + IF lives < 3 THEN + lives = lives + 1 + END IF + IF d_thou > 9 THEN + d_thou = 0 + d_tthou = d_tthou + 1 + IF d_tthou > 9 THEN + ' Hard Cap at 99,999 + d_tthou = 9 + d_thou = 9 + d_hund = 9 + d_tens = 9 + d_ones = 9 + END IF + END IF + END IF + END IF + END IF + RETURN + +' --------------------------------------------------------- +' SUBROUTINE: DRAW BOMBER +' --------------------------------------------------------- +draw_bomber_sub: + IF bomber_dir = 1 THEN + bomber_attr = 0 + SPRITE 0, y_bomber, x_bomber, 128, bomber_attr + SPRITE 1, y_bomber, x_bomber + 8, 130, bomber_attr + SPRITE 2, y_bomber + 16, x_bomber, 132, bomber_attr + SPRITE 3, y_bomber + 16, x_bomber + 8, 134, bomber_attr + ELSE + bomber_attr = 64 + SPRITE 0, y_bomber, x_bomber, 130, bomber_attr + SPRITE 1, y_bomber, x_bomber + 8, 128, bomber_attr + SPRITE 2, y_bomber + 16, x_bomber, 134, bomber_attr + SPRITE 3, y_bomber + 16, x_bomber + 8, 132, bomber_attr + END IF + RETURN + +' --------------------------------------------------------- +' SUBROUTINE: WAVE COMPLETED +' --------------------------------------------------------- +wave_completed: + FOR r = 0 TO 2 + splash_t(r) = 0 + SPRITE 4 + r, 255, 0, 0, 0 + NEXT r + FOR c = 0 TO 7 + bomb_s(c) = 0 + SPRITE 40 + c, 255, 0, 0, 0 + NEXT c + GOSUB draw_bomber_sub + + ' Display using the wave variable directly + PRINT AT 898, "WAVE " + PRINT AT 903, wave + PRINT AT 905, " COMPLETE! - PRESS A" + + WAIT + + WHILE 1 + WAIT + IF cont1.button THEN + PRINT AT 896, " " + GOSUB redraw_score + wave = wave + 1 + GOTO start_wave + END IF + WEND + +' --------------------------------------------------------- +' SUBROUTINE: LIFE LOST +' --------------------------------------------------------- +life_lost_draw: + FOR c = 0 TO 7 + IF bomb_s(c) = 1 THEN + SPRITE 40 + c, bomb_y(c), bomb_x(c), 138, 1 + ELSE + SPRITE 40 + c, 255, 0, 0, 0 + END IF + NEXT c + GOSUB draw_bomber_sub + + temp_val = rng_seed % 3 + IF temp_val = 0 THEN + s_row1 = 24 + s_row2 = 27 + s_row3 = 30 + s_ex1 = 33 + s_ex2 = 34 + s_ex3 = 35 + ELSEIF temp_val = 1 THEN + s_row1 = 30 + s_row2 = 24 + s_row3 = 27 + s_ex1 = 35 + s_ex2 = 33 + s_ex3 = 34 + ELSE + s_row1 = 27 + s_row2 = 30 + s_row3 = 24 + s_ex1 = 34 + s_ex2 = 35 + s_ex3 = 33 + END IF + + col1_x = x_bucket + col2_x = x_bucket + 8 + col3_x = x_bucket + 16 + col4_x = x_bucket + 24 + + b_vis_1 = 212 + IF lives >= 2 THEN + b_vis_2 = 194 + ELSE + b_vis_2 = 255 + END IF + IF lives >= 3 THEN + b_vis_3 = 176 + ELSE + b_vis_3 = 255 + END IF + + ' Draw Row 1 + SPRITE s_row1, b_vis_1, col1_x, 136, 3 + SPRITE s_row1 + 1, b_vis_1, col2_x, 136, 3 + IF difficulty < 2 THEN + SPRITE s_row1 + 2, b_vis_1, col3_x, 136, 3 + ELSE + SPRITE s_row1 + 2, 255, 0, 0, 0 + END IF + IF difficulty = 0 THEN + SPRITE s_ex1, b_vis_1, col4_x, 136, 3 + ELSE + SPRITE s_ex1, 255, 0, 0, 0 + END IF + + ' Draw Row 2 + SPRITE s_row2, b_vis_2, col1_x, 136, 3 + SPRITE s_row2 + 1, b_vis_2, col2_x, 136, 3 + IF difficulty < 2 AND b_vis_2 < 255 THEN + SPRITE s_row2 + 2, b_vis_2, col3_x, 136, 3 + ELSE + SPRITE s_row2 + 2, 255, 0, 0, 0 + END IF + IF difficulty = 0 AND b_vis_2 < 255 THEN + SPRITE s_ex2, b_vis_2, col4_x, 136, 3 + ELSE + SPRITE s_ex2, 255, 0, 0, 0 + END IF + + ' Draw Row 3 + SPRITE s_row3, b_vis_3, col1_x, 136, 3 + SPRITE s_row3 + 1, b_vis_3, col2_x, 136, 3 + IF difficulty < 2 AND b_vis_3 < 255 THEN + SPRITE s_row3 + 2, b_vis_3, col3_x, 136, 3 + ELSE + SPRITE s_row3 + 2, 255, 0, 0, 0 + END IF + IF difficulty = 0 AND b_vis_3 < 255 THEN + SPRITE s_ex3, b_vis_3, col4_x, 136, 3 + ELSE + SPRITE s_ex3, 255, 0, 0, 0 + END IF + + GOTO life_lost_pause + +' --------------------------------------------------------- +' SUBROUTINE: LIFE LOST PAUSE +' --------------------------------------------------------- +life_lost_pause: + FOR c = 0 TO 7 + bomb_s(c) = 0 + SPRITE 40 + c, 255, 0, 0, 0 + NEXT c + FOR r = 0 TO 2 + splash_t(r) = 0 + SPRITE 4 + r, 255, 0, 0, 0 + NEXT r + GOSUB draw_bomber_sub + + ' UI on Row 28 + PRINT AT 901, "BOMB MISSED! - PRESS A" + + WHILE 1 + WAIT + IF cont1.button THEN + PRINT AT 896, " " + GOSUB redraw_score + GOTO start_wave + END IF + WEND + +' --------------------------------------------------------- +' SUBROUTINE: NEW GAME PAUSE +' --------------------------------------------------------- +new_game_pause: + FOR r = 0 TO 2 + splash_t(r) = 0 + SPRITE 4 + r, 255, 0, 0, 0 + NEXT r + FOR c = 0 TO 7 + bomb_s(c) = 0 + SPRITE 40 + c, 240, 0, 0, 0 + NEXT c + GOSUB draw_bomber_sub + + ' Print to Row 28 + PRINT AT 900, "READY? PRESS A TO START" + + WHILE 1 + WAIT + IF cont1.button THEN + ' Clear Row 28 + PRINT AT 896, " " + GOSUB redraw_score + RETURN + END IF + WEND + +' --------------------------------------------------------- +' SUBROUTINE: GAME OVER +' --------------------------------------------------------- +game_over_screen: + FOR c = 0 TO 63 + SPRITE c, 255, 0, 0, 0 + NEXT c + + PRINT AT 896, " " + GOSUB redraw_score + PRINT AT 907, "GAME OVER" + + ' Save the current wave + last_wave = wave + + ' Manual Digit-by-Digit High Score Comparison + ' (We only update high score if current score is higher) + r = 0 ' Flag for "is current score higher?" + IF d_tthou > h_tthou THEN r = 1 + IF d_tthou = h_tthou AND d_thou > h_thou THEN r = 1 + IF d_tthou = h_tthou AND d_thou = h_thou AND d_hund > h_hund THEN r = 1 + IF d_tthou = h_tthou AND d_thou = h_thou AND d_hund = h_hund AND d_tens > h_tens THEN r = 1 + IF d_tthou = h_tthou AND d_thou = h_thou AND d_hund = h_hund AND d_tens = h_tens AND d_ones > h_ones THEN r = 1 + + IF r = 1 THEN + ' Update High Score Digit Variables + h_tthou = d_tthou + h_thou = d_thou + h_hund = d_hund + h_tens = d_tens + h_ones = d_ones + END IF + + WHILE 1 + WAIT + IF cont1.button THEN + GOTO title_screen + END IF + WEND + +' --------------------------------------------------------- +' SUBROUTINE: REFRESH GAME SCREEN +' Wipes everything and redraws the clean cityscape +' --------------------------------------------------------- +refresh_game_screen: + SCREEN DISABLE + CLS + ' Redraw the Sky and Top of Buildings + FOR r = 0 TO 1 + PRINT AT r * 32, "***********************(((******" + NEXT r + PRINT AT 64, "****(((((*(((*((((*****( (*(((((" + PRINT AT 96, "****( ( (*( (*( ((*****(((*( ( (" + PRINT AT 128, "(((*(((((*(((*((((*(((*(((*(((((" + PRINT AT 160, "( (*( ( (*( (*((((*(((*(((*( (((" + PRINT AT 192, "(((*(((((*(((*((((*(((*(((*(((((" + + ' Redraw the Main Building Area (The green area) + FOR r = 7 TO 27 + PRINT AT r * 32, "))))))))))))))))))))))))))))))))" + NEXT r + + SCREEN ENABLE + RETURN + +redraw_score: + ' All digits on Row 1 (Y=8) + ' Ten Thousands + SPRITE 15, 8, 208, 160 + (d_tthou * 2), 2 + ' Thousands + SPRITE 16, 8, 216, 160 + (d_thou * 2), 2 + ' Hundreds + SPRITE 17, 8, 224, 160 + (d_hund * 2), 2 + ' Tens + SPRITE 18, 8, 232, 160 + (d_tens * 2), 2 + ' Ones + SPRITE 19, 8, 240, 160 + (d_ones * 2), 2 + RETURN + +' -- GRAPHICS -- + CHRROM 0 + +' == BACKGROUND NUMBERS (48+) == + CHRROM PATTERN 48 + ' 0 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + ' 1 + BITMAP "...33..." + BITMAP "..333..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP ".333333." + BITMAP "........" + ' 2 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP ".....33." + BITMAP "...33..." + BITMAP "..33...." + BITMAP "33......" + BITMAP "3333333." + BITMAP "........" + ' 3 + BITMAP "333333.." + BITMAP "....33.." + BITMAP "...33..." + BITMAP "....33.." + BITMAP ".....33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + ' 4 + BITMAP "...333.." + BITMAP "..333..." + BITMAP ".33.3..." + BITMAP "33..3..." + BITMAP "3333333." + BITMAP "....3..." + BITMAP "....3..." + BITMAP "........" + ' 5 + BITMAP "3333333." + BITMAP "33......" + BITMAP "333333.." + BITMAP ".....33." + BITMAP ".....33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + ' 6 + BITMAP ".33333.." + BITMAP "33......" + BITMAP "333333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + ' 7 + BITMAP "3333333." + BITMAP "33...33." + BITMAP "...33..." + BITMAP "..33...." + BITMAP "..33...." + BITMAP "..33...." + BITMAP "..33...." + BITMAP "........" + ' 8 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + ' 9 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP ".333333." + BITMAP ".....33." + BITMAP "....33.." + BITMAP "...33..." + BITMAP ".333...." + BITMAP "........" + + ' Pattern 58: COLON (Grey on Black) + BITMAP "........" + BITMAP "..33...." + BITMAP "..33...." + BITMAP "........" + BITMAP "..33...." + BITMAP "..33...." + BITMAP "........" + BITMAP "........" + + ' PATTERN 127: COPYRIGHT SYMBOL (Uses 3 = Grey) + CHRROM PATTERN 127 + BITMAP ".33333.." + BITMAP "3.....3." + BITMAP "3.333.3." + BITMAP "3.3...3." + BITMAP "3.3...3." + BITMAP "3.333.3." + BITMAP "3.....3." + BITMAP ".33333.." + + ' PATTERN 200: THE TITLE LOGO BLOCK (Uses 1 = ORANGE) + CHRROM PATTERN 200 + BITMAP "11111111" + BITMAP "1......1" + BITMAP "1.1..1.1" + BITMAP "1..11..1" + BITMAP "1..11..1" + BITMAP "1.1..1.1" + BITMAP "1......1" + BITMAP "11111111" + + ' PATTERN 201: SOLID ORANGE BLOCK (Uses 1 = ORANGE) + CHRROM PATTERN 201 + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + ' == SPRITES (128+) == + CHRROM PATTERN 128 + + ' Bomber + BITMAP "....1111" + BITMAP "...11111" + BITMAP "...11111" + BITMAP "...11111" + BITMAP "11111..1" + BITMAP "11111111" + BITMAP "33333333" + BITMAP "....333." + + BITMAP "....333." + BITMAP "....3333" + BITMAP "....333." + BITMAP "....3..3" + BITMAP ".....333" + BITMAP ".....333" + BITMAP ".....111" + BITMAP "...22222" + + BITMAP "1111...." + BITMAP "11111..." + BITMAP "11111..." + BITMAP "11111..." + BITMAP "1..11111" + BITMAP "11111111" + BITMAP "33333333" + BITMAP ".333...." + + BITMAP ".333...." + BITMAP "3333...." + BITMAP ".333...." + BITMAP "3..3...." + BITMAP "333....." + BITMAP "333....." + BITMAP "111....." + BITMAP "22222..." + + BITMAP "11111111" + BITMAP "22222222" + BITMAP "11111111" + BITMAP "22222222" + BITMAP "11..1111" + BITMAP "22..2222" + BITMAP "11..1111" + BITMAP "22..2222" + + BITMAP "11..1111" + BITMAP "22..2222" + BITMAP "11..1111" + BITMAP "22..2222" + BITMAP "33..1111" + BITMAP "33......" + BITMAP "..3....." + BITMAP "........" + + BITMAP "11111111" + BITMAP "22222222" + BITMAP "11111111" + BITMAP "22222222" + BITMAP "1111..11" + BITMAP "2222..22" + BITMAP "1111..11" + BITMAP "2222..22" + + BITMAP "1111..11" + BITMAP "2222..22" + BITMAP "1111..11" + BITMAP "2222..22" + BITMAP "1111..33" + BITMAP "......33" + BITMAP ".....3.." + BITMAP "........" + + ' BUCKET (136/137) + ' Uses Palette 3 (2s=Blue $12, 3s=Brown $07) + ' 136 = Top Sprite (Water + rim/body) + BITMAP "22222222" ' Row 0 + BITMAP "22222222" ' Row 1 + BITMAP "33333333" ' Row 6 + BITMAP "33333333" ' Row 7 + BITMAP "33333333" ' Row 4 + BITMAP "33333333" ' Row 5 + BITMAP "33333333" ' Row 6 + BITMAP "33333333" ' Row 7 + + ' 137 = Bottom Sprite (Bucket continuation / can be empty if not needed) + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' BOMB (138) + BITMAP "...3...." + BITMAP "...2...." + BITMAP "..1111.." + BITMAP ".111111." + BITMAP "11111111" + BITMAP "11111111" + BITMAP ".111111." + BITMAP "..1111.." + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' SPLASH FRAME A (140) + CHRROM PATTERN 140 + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "2......2" + BITMAP "..2..2.." + BITMAP ".222222." + BITMAP "..2222.." + BITMAP "...22..." + + ' SPLASH FRAME B (141) + CHRROM PATTERN 141 + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' PATTERN 146: CURSOR + ' Uses color 3 (Light Grey in Palette 3) + CHRROM PATTERN 146 + BITMAP "........" + BITMAP "..3333.." + BITMAP ".333333." + BITMAP ".333333." + BITMAP ".333333." + BITMAP ".333333." + BITMAP "..3333.." + BITMAP "........" + + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' PATTERN 40: BUILDING BLOCK (SOLID 3s = DARK GREY) + CHRROM PATTERN 40 + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + BITMAP "33333333" + + ' PATTERN 41: FLOOR MAIN AREA (SOLID 1s = GREEN) + CHRROM PATTERN 41 + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + BITMAP "11111111" + + ' PATTERN 42: DARK BLUE SKY (SOLID 2s = BLUE) + CHRROM PATTERN 42 + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + BITMAP "22222222" + + ' PATTERN 160: NUMBERS FOR SPRITES (Uses 3s = GREY) + ' ** FIXED **: Added blank spacers between digits to align with *2 logic + CHRROM PATTERN 160 + ' 0 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 1 + BITMAP "...33..." + BITMAP "..333..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP "...33..." + BITMAP ".333333." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 2 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP ".....33." + BITMAP "...33..." + BITMAP "..33...." + BITMAP "33......" + BITMAP "3333333." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 3 + BITMAP "333333.." + BITMAP "....33.." + BITMAP "...33..." + BITMAP "....33.." + BITMAP ".....33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 4 + BITMAP "..333..." + BITMAP ".33.3..." + BITMAP "33..3..." + BITMAP "3333333." + BITMAP "....3..." + BITMAP "....3..." + BITMAP "....3..." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 5 + BITMAP "3333333." + BITMAP "33......" + BITMAP "333333.." + BITMAP ".....33." + BITMAP ".....33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 6 + BITMAP ".33333.." + BITMAP "33......" + BITMAP "333333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 7 + BITMAP "3333333." + BITMAP "33...33." + BITMAP "...33..." + BITMAP "..33...." + BITMAP "..33...." + BITMAP "..33...." + BITMAP "..33...." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 8 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "33...33." + BITMAP "33...33." + BITMAP ".33333.." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + ' 9 + BITMAP ".33333.." + BITMAP "33...33." + BITMAP ".333333." + BITMAP ".....33." + BITMAP "....33.." + BITMAP "...33..." + BITMAP ".333...." + BITMAP "........" + + ' Spacer + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + + + diff --git a/cvbasic.c b/cvbasic.c index 056776d..d8f6a24 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.0 Aug/26/2025" +#define VERSION "v0.9.0 Jan/06/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" diff --git a/manual.txt b/manual.txt index 8e3602f..19c1534 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Aug/25/2025 +Last revision: Nov/28/2025 >>>>>>>>>>>>>> Legal notice @@ -22,6 +22,9 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version +v1.0.0 Nov/28/2025 o Added note about support of Blue and Purple buttons + (Super Action Controllers for Colecovision) + v0.9.0 Aug/26/2025 o Added support for NES/Famicom using --nes o MSX: Added support for Konami mapper using -konami o Solved bug in DEF FN precedence inside expressions. @@ -153,6 +156,15 @@ The NABU port requires the gasm output file to be named 000001.nabu and you shou And finally, you can test the generated output.rom file using CoolCV, blueMSX, openMSX, or a Flash cartridge for real hardware. +>>>>>>>>>>>>>> Debugging support + +If you are using the blueMSX or openMSX emulators, you can debug your games with symbols intermixed in the code disassembly window. + +For this you require gasm80 to generate a symbol table in this way: + + gasm80 game.asm -o game.rom -s game.sym + + >>>>>>>>>>>>>> Supporting the developer If you find CVBasic useful, please show your appreciation making a donation via Paypal ($9 USD suggested) to b-i+y-u+b-i (at) gmail.com From 5e63cd450b5f51122696947fcd9ef9832d004b50 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 10 Jan 2026 10:39:02 -0600 Subject: [PATCH 091/155] Added atan2 and boom contribs --- README.md | 4 +- contrib/atan2.bas | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 contrib/atan2.bas diff --git a/README.md b/README.md index 2b6d0c4..ee508f1 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,8 @@ There are some very good examples of games developed with CVBasic. * Beachhead by Eric Damain. Demo screenshots [https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/](https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/) +* Boom by Atarius Maximus for NES/Famicom. Also in the _contrib_ directory. [https://forums.atariage.com/topic/384096-colecovision-fantalicious-basic-compiler-cvbasic-v090-now-with-nesfamicom-support/page/2/#findComment-5769427](https://forums.atariage.com/topic/384096-colecovision-fantalicious-basic-compiler-cvbasic-v090-now-with-nesfamicom-support/page/2/#findComment-5769427) + * Camelot Knights by nanochess. Available from [https://forums.atariage.com/topic/363252-camelot-knights-game/](https://forums.atariage.com/topic/363252-camelot-knights-game/) * Colecovania demo by Skywaffle. Video at [https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl](https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl) @@ -309,4 +311,4 @@ All the games in the book will compile for **all** the platforms, except Sega Ma ### Acknowledgments -Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. +Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, Atarius Maximus, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. diff --git a/contrib/atan2.bas b/contrib/atan2.bas new file mode 100644 index 0000000..74301d8 --- /dev/null +++ b/contrib/atan2.bas @@ -0,0 +1,143 @@ + ' + ' atan2 and getsincos functions for 256 degrees circles + ' + ' Contributed by Arturo Ragozini (ARTRAG) + ' + ' Added Jan/10/2026. + ' + +'''''''''''''''''''''''''''''''''''''''''''''''' +' ;;;;;;;; atan(2^(x/32))*128/pi ;;;;;;;; +atan_tab: + data $20,$20,$20,$21,$21,$22,$22,$23,$23,$23,$24,$24,$25,$25,$26,$26 + data $26,$27,$27,$28,$28,$28,$29,$29,$2A,$2A,$2A,$2B,$2B,$2C,$2C,$2C + data $2D,$2D,$2D,$2E,$2E,$2E,$2F,$2F,$2F,$30,$30,$30,$31,$31,$31,$31 + data $32,$32,$32,$32,$33,$33,$33,$33,$34,$34,$34,$34,$35,$35,$35,$35 + data $36,$36,$36,$36,$36,$37,$37,$37,$37,$37,$37,$38,$38,$38,$38,$38 + data $38,$39,$39,$39,$39,$39,$39,$39,$39,$3A,$3A,$3A,$3A,$3A,$3A,$3A + data $3A,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3C,$3C,$3C,$3C + data $3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3D,$3D,$3D,$3D,$3D,$3D,$3D + data $3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3E,$3E,$3E,$3E + data $3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E + data $3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3F,$3F,$3F,$3F + data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F + data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F + data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F + data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F + data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F + +' ;;;;;;;; log2(x)*32 ;;;;;;;; +log2_tab: + data $00,$00,$20,$32,$40,$4A,$52,$59,$60,$65,$6A,$6E,$72,$76,$79,$7D + data $80,$82,$85,$87,$8A,$8C,$8E,$90,$92,$94,$96,$98,$99,$9B,$9D,$9E + data $A0,$A1,$A2,$A4,$A5,$A6,$A7,$A9,$AA,$AB,$AC,$AD,$AE,$AF,$B0,$B1 + data $B2,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$B9,$BA,$BB,$BC,$BD,$BD,$BE,$BF + data $C0,$C0,$C1,$C2,$C2,$C3,$C4,$C4,$C5,$C6,$C6,$C7,$C7,$C8,$C9,$C9 + data $CA,$CA,$CB,$CC,$CC,$CD,$CD,$CE,$CE,$CF,$CF,$D0,$D0,$D1,$D1,$D2 + data $D2,$D3,$D3,$D4,$D4,$D5,$D5,$D5,$D6,$D6,$D7,$D7,$D8,$D8,$D9,$D9 + data $D9,$DA,$DA,$DB,$DB,$DB,$DC,$DC,$DD,$DD,$DD,$DE,$DE,$DE,$DF,$DF + data $DF,$E0,$E0,$E1,$E1,$E1,$E2,$E2,$E2,$E3,$E3,$E3,$E4,$E4,$E4,$E5 + data $E5,$E5,$E6,$E6,$E6,$E7,$E7,$E7,$E7,$E8,$E8,$E8,$E9,$E9,$E9,$EA + data $EA,$EA,$EA,$EB,$EB,$EB,$EC,$EC,$EC,$EC,$ED,$ED,$ED,$ED,$EE,$EE + data $EE,$EE,$EF,$EF,$EF,$EF,$F0,$F0,$F0,$F1,$F1,$F1,$F1,$F1,$F2,$F2 + data $F2,$F2,$F3,$F3,$F3,$F3,$F4,$F4,$F4,$F4,$F5,$F5,$F5,$F5,$F5,$F6 + data $F6,$F6,$F6,$F7,$F7,$F7,$F7,$F7,$F8,$F8,$F8,$F8,$F9,$F9,$F9,$F9 + data $F9,$FA,$FA,$FA,$FA,$FA,$FB,$FB,$FB,$FB,$FB,$FC,$FC,$FC,$FC,$FC + data $FD,$FD,$FD,$FD,$FD,$FD,$FE,$FE,$FE,$FE,$FE,$FF,$FF,$FF,$FF,$FF + data $FF ' trick to cope with 256 + + +'----------------------------------------------- +' Source: https://www.msx.org/forum/msx-talk/development/8-bit-atan2?page=0 +' 8-bit atan2 +' Calculate the angle, in a 256-degree circle. +' The trick is to use logarithms to get the y/x ratio and +' integrate the power function into the atan table. +' input +' #dx_in, #dy_in in -256,255 +' +' output +' angle in 0-255 +' ^ +' q1 | q0 +'------+------> +' q3 | q2 +' | + + signed #dx_in + signed #dy_in + +atan2: procedure + if (#dy_in>0) then + if (#dx_in>0) then + gosub atan2_q0 ' q0 + else + #dx_in=-#dx_in ' q1 + gosub atan2_q0 + angle = (-angle) and $7F + return + end if + else + if (#dx_in>0) then + #dy_in=-#dy_in ' q2 + gosub atan2_q0 + angle = -angle + return + else + #dx_in=-#dx_in ' q3 + #dy_in=-#dy_in + gosub atan2_q0 + angle = angle + 128 + return + end if + end if + return + end + +atan2_q0: procedure + if (#dx_in>=#dy_in) then + angle = (-atan_tab(log2_tab(#dx_in)-log2_tab(#dy_in))) and $3F + else + angle = atan_tab(log2_tab(#dy_in)-log2_tab(#dx_in)) + end if + return + end + + + +';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +' input +' angle in 0-255 +' +' output +' #dy_out = sin(angle) in -256,256 +' #dx_out = cos(angle) in -256,256 + +getsincos: procedure + #dy_out = #sin_table(angle) + #dx_out = #cos_table(angle) + end + +#sin_table: + data 0, 6, 12, 18, 25, 31, 37, 43, 49, 56, 62, 68, 74, 80, 86, 92 + data 97, 103, 109, 115, 120, 126, 131, 136, 142, 147, 152, 157, 162, 167, 171, 176 + data 181, 185, 189, 193, 197, 201, 205, 209, 212, 216, 219, 222, 225, 228, 231, 234 + data 236, 238, 241, 243, 244, 246, 248, 249, 251, 252, 253, 254, 254, 255, 255, 255 +#cos_table: + data 256, 255, 255, 255, 254, 254, 253, 252, 251, 249, 248, 246, 244, 243, 241, 238 + data 236, 234, 231, 228, 225, 222, 219, 216, 212, 209, 205, 201, 197, 193, 189, 185 + data 181, 176, 171, 167, 162, 157, 152, 147, 142, 136, 131, 126, 120, 115, 109, 103 + data 97, 92, 86, 80, 74, 68, 62, 56, 49, 43, 37, 31, 25, 18, 12, 6 + data 0, -6, -12, -18, -25, -31, -37, -43, -49, -56, -62, -68, -74, -80, -86, -92 + data -97, -103, -109, -115, -120, -126, -131, -136, -142, -147, -152, -157, -162, -167, -171, -176 + data -181, -185, -189, -193, -197, -201, -205, -209, -212, -216, -219, -222, -225, -228, -231, -234 + data -236, -238, -241, -243, -244, -246, -248, -249, -251, -252, -253, -254, -254, -255, -255, -255 + data -256, -255, -255, -255, -254, -254, -253, -252, -251, -249, -248, -246, -244, -243, -241, -238 + data -236, -234, -231, -228, -225, -222, -219, -216, -212, -209, -205, -201, -197, -193, -189, -185 + data -181, -176, -171, -167, -162, -157, -152, -147, -142, -136, -131, -126, -120, -115, -109, -103 + data -97, -92, -86, -80, -74, -68, -62, -56, -49, -43, -37, -31, -25, -18, -12, -6 + data 0, 6, 12, 18, 25, 31, 37, 43, 49, 56, 62, 68, 74, 80, 86, 92 + data 97, 103, 109, 115, 120, 126, 131, 136, 142, 147, 152, 157, 162, 167, 171, 176 + data 181, 185, 189, 193, 197, 201, 205, 209, 212, 216, 219, 222, 225, 228, 231, 234 + data 236, 238, 241, 243, 244, 246, 248, 249, 251, 252, 253, 254, 254, 255, 255, 255 + From 8b9e112f03bde1e43eb3e75c0e4a4172c230645d Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 5 Feb 2026 17:28:44 -0600 Subject: [PATCH 092/155] Added CONT1/CONT2.SPINNER for spinners and Roller Controller support for Colecovision --- README.md | 2 +- cpuz80.c | 20 ++++++++++++ cvbasic.c | 27 ++++++++++++--- cvbasic_epilogue.asm | 8 +++++ cvbasic_prologue.asm | 78 +++++++++++++++++++++++++++++++++++++++++++- examples/spinner.bas | 44 +++++++++++++++++++++++++ manual.txt | 12 ++++++- node.c | 2 +- node.h | 2 +- 9 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 examples/spinner.bas diff --git a/README.md b/README.md index ee508f1..8bd2107 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CVBasic compiler v0.9.0 +# CVBasic compiler v0.9.1 *(c) Copyright 2024-2025 Óscar Toledo Gutiérrez* *https://nanochess.org/* diff --git a/cpuz80.c b/cpuz80.c index 403d2d9..e94c797 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -393,6 +393,8 @@ void cpuz80_node_label(struct node *node) case N_JOY2: /* Read joystick 2 */ case N_KEY1: /* Read keypad 1 */ case N_KEY2: /* Read keypad 2 */ + case N_SPINNER1: /* Read spinner 1 */ + case N_SPINNER2: /* Read spinner 2 */ case N_MUSIC: /* Read music playing status */ case N_NTSC: /* Read NTSC flag */ case N_VDPSTATUS: /* Read VDP status */ @@ -917,6 +919,24 @@ void cpuz80_node_generate(struct node *node, int decision) case N_KEY2: /* Read keypad 2 */ cpuz80_2op("LD", "A", "(key2_data)"); break; + case N_SPINNER1: /* Read spinner 1 */ + cpuz80_noop("DI"); + cpuz80_2op("LD", "A", "(spinner_data+1)"); + cpuz80_1op("PUSH", "AF"); + cpuz80_1op("XOR", "A"); + cpuz80_2op("LD", "(spinner_data+1)", "A"); + cpuz80_1op("POP", "AF"); + cpuz80_noop("EI"); + break; + case N_SPINNER2: /* Read spinner 2 */ + cpuz80_noop("DI"); + cpuz80_2op("LD", "A", "(spinner_data+2)"); + cpuz80_1op("PUSH", "AF"); + cpuz80_1op("XOR", "A"); + cpuz80_2op("LD", "(spinner_data+2)", "A"); + cpuz80_1op("POP", "AF"); + cpuz80_noop("EI"); + break; case N_RANDOM: /* Read pseudorandom generator */ cpuz80_1op("CALL", "random"); break; diff --git a/cvbasic.c b/cvbasic.c index d8f6a24..fc5d484 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.0 Jan/06/2026" +#define VERSION "v0.9.1 Feb/05/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -115,6 +115,7 @@ static char path[4096]; static int last_is_return; static int music_used; static int compression_used; +static int spinner_used; static int bank_switching; static int bank_rom_size; static int bank_current; @@ -1524,6 +1525,7 @@ struct node *evaluate_level_7(int *type) struct node *tree = NULL; int cont; + *type = TYPE_8; if (strcmp(name, "CONT1") == 0) cont = 1; else if (strcmp(name, "CONT2") == 0) @@ -1533,7 +1535,22 @@ struct node *evaluate_level_7(int *type) get_lex(); if (lex == C_PERIOD) { get_lex(); - if (strcmp(name, "KEY") == 0) { + if (strcmp(name, "SPINNER") == 0) { + if (machine != COLECOVISION && machine != COLECOVISION_SGM) { + emit_error("SPINNER is only available for Colecovision"); + tree = node_create(N_NUM8, 0, NULL, NULL); + } else if (cont == 1) { + tree = node_create(N_SPINNER1, 0, NULL, NULL); + } else if (cont == 2) { + tree = node_create(N_SPINNER2, 0, NULL, NULL); + } else { + emit_error("Using CONT.SPINNER instead of CONT1 or CONT2"); + tree = node_create(N_NUM8, 0, NULL, NULL); + } + tree = node_create(N_EXTEND8S, 0, tree, NULL); + *type = TYPE_16; + spinner_used = 1; + } else if (strcmp(name, "KEY") == 0) { if (cont == 1) { tree = node_create(N_KEY1, 0, NULL, NULL); } else if (cont == 2) { @@ -1572,7 +1589,7 @@ struct node *evaluate_level_7(int *type) } else if (strcmp(name, "BUTTON2") == 0) { get_lex(); tree = node_create(N_AND8, 0, tree, node_create(N_NUM8, 0x80, NULL, NULL)); - } else if (strcmp(name, "KEY") == 0) { + } else if (strcmp(name, "KEY") == 0 || strcmp(name, "SPINNER") == 0) { get_lex(); } else { emit_error("Wrong field for CONT"); @@ -1587,7 +1604,6 @@ struct node *evaluate_level_7(int *type) tree = node_create(N_OR8, 0, tree, node_create(N_JOY2, 0, NULL, NULL)); } } - *type = TYPE_8; return tree; } if (strcmp(name, "RANDOM") == 0) { @@ -3782,7 +3798,7 @@ void compile_statement(int check_for_else) node_generate(value, 0); cpu9900_2op("movb", "r0", "@SOUND"); } else { - emit_warning("OUT to 0xff for audio is the only supported use."); + emit_warning("OUT to $ff for audio is the only supported use."); } } else { node_generate(port, 0); @@ -6826,6 +6842,7 @@ int main(int argc, char *argv[]) fprintf(output, "CVBASIC_COMPRESSION:\tequ %d\n", compression_used); fprintf(output, "CVBASIC_BANK_SWITCHING:\tequ %d\n", bank_switching); fprintf(output, "CVBASIC_BANK_ROM_SIZE:\tequ %d\n", bank_rom_size); + fprintf(output, "COLECO_SPINNER:\tequ %d\n", spinner_used); fprintf(output, "\n"); fprintf(output, "BASE_RAM:\tequ %c%04x\t; Base of RAM\n", hex, consoles[machine].base_ram - extra_ram); fprintf(output, "RAM_SIZE:\tequ %c%04x\t; Base of RAM\n", hex, consoles[machine].memory_size + extra_ram); diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 4547aaf..00a9d88 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -20,6 +20,8 @@ ; Revision date: Aug/15/2024. Added support for Tatung Einstein. ; Revision date: Nov/12/2024. Added vdp_status. ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. + ; Revision date: Feb/05/2026. Added support for spinners and roller controller + ; (Colecovision). ; rom_end: @@ -86,6 +88,12 @@ ntsc: rb 1 vdp_status: rb 1 + if COLECO + if COLECO_SPINNER +spinner_data: + rb 3 + endif + endif if NABU nabu_data0: rb 1 nabu_data1: rb 1 diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index d4b3bfb..36f9914 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -39,6 +39,8 @@ ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number ; keys values were inverted. ; Revision date: Nov/12/2024. Saves the VDP status. + ; Revision date: Feb/05/2026. Added support for spinners and roller controller + ; (Colecovision). ; JOYSEL: equ $c0 @@ -79,9 +81,45 @@ JOY2: equ $ff-$22*(SG1000+SMS) jp 0 ; rst $20 jp 0 ; rst $28 jp 0 ; rst $30 + if COLECO_SPINNER + jp spinner_handler + else jp 0 ; rst $38 - + endif jp nmi_handler + + if COLECO_SPINNER +spinner_handler: + PUSH AF + PUSH HL + LD A,$FF + LD (spinner_data),A + OUT (JOYSEL),A + PUSH AF + POP AF + LD HL,spinner_data+1 + IN A,(JOY1) + BIT 4,A + JR NZ,.1 + BIT 5,A + JR NZ,$+4 + INC (HL) + DB $3E + DEC (HL) +.1: INC HL + IN A,(JOY2) + BIT 4,A + JR NZ,.2 + BIT 5,A + JR NZ,$+4 + INC (HL) + DB $3E + DEC (HL) +.2: POP HL + POP AF + EI + RETI + endif endif endif if SG1000+SMS+SVI @@ -326,27 +364,45 @@ LDIRVM: else ; Normal platforms with VDP connected via ports (IORQ) WRTVDP: + if COLECO_SPINNER + di + endif ld a,b out (VDP+1),a ld a,c or $80 out (VDP+1),a + if COLECO_SPINNER + ei + endif ret SETWRT: + if COLECO_SPINNER + di + endif ld a,l out (VDP+1),a ld a,h or $40 out (VDP+1),a + if COLECO_SPINNER + ei + endif ret SETRD: + if COLECO_SPINNER + di + endif ld a,l out (VDP+1),a ld a,h and $3f out (VDP+1),a + if COLECO_SPINNER + ei + endif ret WRTVRM: @@ -1599,6 +1655,9 @@ nmi_handler: endif if COLECO + if COLECO_SPINNER + DI + endif out (JOYSEL),a ex (sp),hl ex (sp),hl @@ -1606,15 +1665,24 @@ nmi_handler: or $b0 ld b,a in a,(JOY2) + if COLECO_SPINNER + EI + endif or $b0 ld c,a + if COLECO_SPINNER + DI + endif out (KEYSEL),a ex (sp),hl ex (sp),hl in a,(JOY1) ld d,a in a,(JOY2) + if COLECO_SPINNER + EI + endif ld e,a ld a,d @@ -3774,6 +3842,9 @@ Z80_CTC: equ $28 djnz .delay1 else di + if COLECO_SPINNER + im 1 + endif ld sp,STACK endif if NABU @@ -4003,5 +4074,10 @@ WRITE_VRAM: equ $1fdf ld hl,nmi_handler ld ($7006),hl endif + if COLECO + if COLECO_SPINNER + ei + endif + endif ; CVBasic program start. diff --git a/examples/spinner.bas b/examples/spinner.bas new file mode 100644 index 0000000..b594178 --- /dev/null +++ b/examples/spinner.bas @@ -0,0 +1,44 @@ + ' + ' Spinner / Roller Controller test (Colecovision) + ' Demo for CVBasic. + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Feb/05/2026. + ' + + DEFINE SPRITE 0,1,happy_face + + PRINT AT 36,"Happy face!" + + x = 120 + y = 88 + +game_loop: + WAIT + WAIT + SPRITE 0, y - 1, x, 0, 10 + + x = x + CONT1.SPINNER + y = y - CONT2.SPINNER + + GOTO game_loop + +happy_face: + BITMAP "......XXXX......" + BITMAP "....XXXXXXXX...." + BITMAP "...XXXXXXXXXX..." + BITMAP "..XXXXXXXXXXXX.." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP "XXXX..XXXX..XXXX" + BITMAP "XXXX..XXXX..XXXX" + BITMAP "XXXXXXXXXXXXXXXX" + BITMAP "XXXXXXXXXXXXXXXX" + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXX..XXXX..XXX." + BITMAP "..XXX......XXX.." + BITMAP "...XXX....XXX..." + BITMAP "....XXXXXXXX...." + BITMAP "......XXXX......" diff --git a/manual.txt b/manual.txt index 19c1534..c677860 100644 --- a/manual.txt +++ b/manual.txt @@ -22,8 +22,10 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v1.0.0 Nov/28/2025 o Added note about support of Blue and Purple buttons +v0.9.1 Feb/05/2026 o Added note about support of Blue and Purple buttons (Super Action Controllers for Colecovision) + o Added support for spinners and roller controller + using CONT1.SPINNER and CONT2.SPINNER (Colecovision) v0.9.0 Aug/26/2025 o Added support for NES/Famicom using --nes o MSX: Added support for Konami mapper using -konami @@ -1385,6 +1387,10 @@ The expression parser will take advantage of 8-bit variables and numbers to opti CONT1.KEY Current pressed key: 0-9 for numbers, 10-*, 11-#, 15-Not pressed. For Super Action Controllers, 12 is the Blue button, and 13 is the Purple button. + CONT1.SPINNER Reads the spinner displacement for this controller, + and resets the count (save in a variable if required). + This is the X displacement for the Roller Controller. + Only supported for Colecovision. CONT2 Contains the state of the second controller. CONT2.UP Non-zero if controller pointing up @@ -1396,6 +1402,10 @@ The expression parser will take advantage of 8-bit variables and numbers to opti CONT2.KEY Current pressed key: 0-9 for numbers, 10-*, 11-#, 15-Not pressed. For Super Action Controllers, 12 is the Blue button, and 13 is the Purple button. + CONT2.SPINNER Reads the spinner displacement for this controller, + and resets the count (save in a variable if required). + This is the Y displacement for the Roller Controller. + Only supported for Colecovision. RANDOM Produces a pseudo-random value between 0 and 65535. diff --git a/node.c b/node.c index c4b037f..2f67497 100644 --- a/node.c +++ b/node.c @@ -94,7 +94,7 @@ static char *node_types[] = { "N_READ8", "N_READ16", "N_NUM8", "N_NUM16", "N_PEEK8", "N_PEEK16", "N_VPEEK", "N_INP", "N_ABS16", "N_SGN16", - "N_JOY1", "N_JOY2", "N_KEY1", "N_KEY2", + "N_JOY1", "N_JOY2", "N_KEY1", "N_KEY2", "N_SPINNER1", "N_SPINNER2", "N_RANDOM", "N_FRAME", "N_MUSIC", "N_NTSC", "N_POS", "N_VDPSTATUS", "N_ADDR", "N_USR", "N_COMMA", diff --git a/node.h b/node.h index 64dbfad..7e27ee2 100644 --- a/node.h +++ b/node.h @@ -29,7 +29,7 @@ enum node_type { N_READ8, N_READ16, N_NUM8, N_NUM16, N_PEEK8, N_PEEK16, N_VPEEK, N_INP, N_ABS16, N_SGN16, - N_JOY1, N_JOY2, N_KEY1, N_KEY2, + N_JOY1, N_JOY2, N_KEY1, N_KEY2, N_SPINNER1, N_SPINNER2, N_RANDOM, N_FRAME, N_MUSIC, N_NTSC, N_POS, N_VDPSTATUS, N_ADDR, N_USR, N_COMMA, From 87328b098e2176284c2d42c176ec14e51406592f Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 5 Feb 2026 22:33:11 -0600 Subject: [PATCH 093/155] Updated README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8bd2107..1005683 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ The following files compose the compiler: examples/space_attack.bas Game example. examples/space_attack_nes.bas Game example (NES/Famicom) examples/space_attack_sms.bas Game example (Sega Master System) + examples/spinner.bas Spinner / Roller Controller example (Colecovision) examples/test1.bas Moving stars. examples/test2.bas Arithmetic test. examples/test3.bas Shows usage of SELECT CASE / END CASE From f46286222ad5736631880920618d3f4cff1706b6 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 9 Feb 2026 20:24:02 -0600 Subject: [PATCH 094/155] Added --msx2 option and PALETTE support for MSX2 --- cvbasic.c | 54 ++++++++++++++++++-------- cvbasic.h | 1 + cvbasic_prologue.asm | 15 +++++++ examples/palette_msx2.bas | 82 +++++++++++++++++++++++++++++++++++++++ manual.txt | 15 ++++++- 5 files changed, 148 insertions(+), 19 deletions(-) create mode 100644 examples/palette_msx2.bas diff --git a/cvbasic.c b/cvbasic.c index fc5d484..392fc56 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.1 Feb/05/2026" +#define VERSION "v0.9.2 Feb/09/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -105,6 +105,9 @@ struct console consoles[TOTAL_TARGETS] = { {"nes", "", "NES/Famicom (2K RAM)", "NES/Famicom", 0x0050, 0x01ff, 0x0800, 0, 0, 0, 1, CPU_6502}, + {"msx2", "-ram16", "MSX2 (8K RAM), use -ram16 for 16K of RAM,\n use -konami for Konami mapper instead of ASCII16", + "MSX2", + 0xe000, 0xf380, 0x1380, 0x98, 0x98, 0, 1, CPU_Z80}, }; static int err_code; @@ -437,7 +440,7 @@ void bank_finish(void) } fprintf(output, "\tDB $%02x\n", bank_current); fprintf(output, "\tTIMES $40 DB $ff\n"); - } else if (machine == MSX) { + } else if (machine == MSX || machine == MSX2) { if (bank_current == 0) { fprintf(output, "BANK_0_FREE:\tEQU $7fff-$\n"); fprintf(output, "\tTIMES $7fff-$ DB $ff\n"); @@ -4929,13 +4932,13 @@ void compile_statement(int check_for_else) cpu6502_1op("STY", "scroll_y+1"); } } - } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System / NES */ + } else if (strcmp(name, "PALETTE") == 0) { /* Sega Master System / NES / MSX2 */ int type; struct node *source; get_lex(); - if (machine != SMS && machine != NES) - emit_error("PALETTE is only available on Sega Master System and NES/Famicom"); + if (machine != SMS && machine != NES && machine != MSX2) + emit_error("PALETTE is only available on SMS/NES/Famicom/MSX2"); if (lex == C_NAME && strcmp(name, "LOAD") == 0) { get_lex(); if (lex != C_NAME) { @@ -4945,7 +4948,7 @@ void compile_statement(int check_for_else) node_generate(source, 0); node_delete(source); } else { - if (machine == SMS) { + if (machine == SMS || machine == MSX2) { strcpy(temp, LABEL_PREFIX); strcat(temp, name); cpuz80_2op("LD", "HL", temp); @@ -4980,12 +4983,17 @@ void compile_statement(int check_for_else) cpu6502_1op("STA", "PPUBUF,X"); cpu6502_1op("LDA", "#$7f"); cpu6502_1op("STA", "PPUBUF+1,X"); + } else if (machine == MSX2) { + generic_interrupt_disable(); + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "$10"); + cpuz80_1op("CALL", "WRTVDP"); } if (lex != C_COMMA) emit_error("missing comma in PALETTE"); else get_lex(); - type = evaluate_expression(1, TYPE_8, 0); + type = evaluate_expression(1, (machine == MSX2 ? TYPE_16 : TYPE_8), 0); if (machine == SMS) { cpuz80_2op("OUT", "(VDP)", "A"); generic_interrupt_enable(); @@ -4996,6 +5004,12 @@ void compile_statement(int check_for_else) cpu6502_noop("INX"); cpu6502_noop("INX"); cpu6502_1op("STX", "ppu_pointer"); + } else if (machine == MSX2) { + cpuz80_2op("LD", "A", "L"); + cpuz80_2op("OUT", "(VDP+2)", "A"); + cpuz80_2op("LD", "A", "H"); + cpuz80_2op("OUT", "(VDP+2)", "A"); + generic_interrupt_enable(); } } } else if (strcmp(name, "NAMETABLE") == 0) { /* Select nametable arrangement */ @@ -5560,9 +5574,9 @@ void compile_statement(int check_for_else) } else { if (value < 10 && machine == NES) { emit_warning("using SOUND 0-9 with NES/Famicom target"); - } else if (value >= 0 && value <= 4 && (machine == MSX || machine == SVI || machine == EINSTEIN || machine == NABU)) { + } else if (value >= 0 && value <= 4 && (machine == MSX || machine == MSX2 || machine == SVI || machine == EINSTEIN || machine == NABU)) { emit_warning("using SOUND 0-3 with AY-3-8910 target"); - } else if (value >= 5 && value <= 9 && machine != MSX && machine != COLECOVISION_SGM && machine != SVI && machine != SORD && machine != MEMOTECH && machine != NABU) { + } else if (value >= 5 && value <= 9 && machine != MSX && machine != MSX2 && machine != COLECOVISION_SGM && machine != SVI && machine != SORD && machine != MEMOTECH && machine != NABU) { emit_warning("using SOUND 5-9 with SN76489 target"); } switch (value) { @@ -5839,7 +5853,7 @@ void compile_statement(int check_for_else) if (machine == EINSTEIN || machine == NABU) { cpuz80_1op("OR", "$40"); } else { - /* Protect these MSX machines! */ + /* Protect these MSX1/MSX2 machines! */ cpuz80_1op("OR", "$80"); } cpuz80_2op("LD", "B", "$07"); @@ -6075,7 +6089,7 @@ void compile_statement(int check_for_else) sprintf(temp, "%d", c); cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "($fffe)", "A"); - } else if (machine == MSX) { + } else if (machine == MSX || machine == MSX2) { if (bank_konami) { sprintf(temp, "%d", c * 2); cpuz80_noop("DI"); @@ -6168,7 +6182,7 @@ void compile_statement(int check_for_else) if (machine == SG1000 || machine == SMS) { cpuz80_1op("FORG", temp); cpuz80_1op("ORG", "$4000"); - } else if (machine == MSX) { + } else if (machine == MSX || machine == MSX2) { cpuz80_1op("FORG", temp); cpuz80_1op("ORG", "$8000"); } else if (machine == NES) { @@ -6642,10 +6656,10 @@ int main(int argc, char *argv[]) tolower(argv[c][3] == 'm') && argv[c][4] == '1' && argv[c][5] == '6' && argv[c][6] == '\0') { c++; - if (machine == MSX) { + if (machine == MSX || machine == MSX2) { extra_ram = 8192; } else { - fprintf(stderr, "-ram16 option only applies to MSX.\n"); + fprintf(stderr, "-ram16 option only applies to MSX/MSX2.\n"); exit(2); } } @@ -6654,10 +6668,10 @@ int main(int argc, char *argv[]) tolower(argv[c][3] == 'n') && tolower(argv[c][4]) == 'a' && tolower(argv[c][5]) == 'm' && tolower(argv[c][6]) == 'i' && argv[c][7] == '\0') { c++; - if (machine == MSX) { + if (machine == MSX || machine == MSX2) { bank_konami = 1; } else { - fprintf(stderr, "-konami option only applies to MSX.\n"); + fprintf(stderr, "-konami option only applies to MSX/MSX2.\n"); exit(2); } } @@ -6815,8 +6829,14 @@ int main(int argc, char *argv[]) fprintf(output, "COLECO:\tequ %d\n", (machine == COLECOVISION || machine == COLECOVISION_SGM) ? 1 : 0); fprintf(output, "SG1000:\tequ %d\n", (machine == SG1000) ? 1 : 0); - fprintf(output, "MSX:\tequ %d\n", (machine == MSX) ? 1 : 0); if (machine == MSX) + c = 1; + else if (machine == MSX2) + c = 2; + else + c = 0; + fprintf(output, "MSX:\tequ %d\n", c); + if (c) fprintf(output, "KONAMI:\tequ %d\n", bank_konami); fprintf(output, "SGM:\tequ %d\n", (machine == COLECOVISION_SGM) ? 1 : 0); fprintf(output, "SVI:\tequ %d\n", (machine == SVI) ? 1 : 0); diff --git a/cvbasic.h b/cvbasic.h index 2a7f11a..e7f5151 100644 --- a/cvbasic.h +++ b/cvbasic.h @@ -34,6 +34,7 @@ enum supported_machine { NABU, SMS, NES, + MSX2, TOTAL_TARGETS }; diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 36f9914..9f018c4 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -41,6 +41,7 @@ ; Revision date: Nov/12/2024. Saves the VDP status. ; Revision date: Feb/05/2026. Added support for spinners and roller controller ; (Colecovision). + ; Revision date: Feb/09/2026. Added support for palette in MSX2. ; JOYSEL: equ $c0 @@ -1220,6 +1221,20 @@ font_bitmaps: db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f endif + if MSX&2 +palette_load: + push hl + di + ld bc,$0010 + call WRTVDP + pop hl + ld bc,32*256+VDP+2 + outi + jp nz,$-2 + ei + ret + endif + if SMS palette_load: push hl diff --git a/examples/palette_msx2.bas b/examples/palette_msx2.bas new file mode 100644 index 0000000..cdad7b4 --- /dev/null +++ b/examples/palette_msx2.bas @@ -0,0 +1,82 @@ + ' + ' MSX2 Palette demo + ' + ' by Oscar Toledo G. (example for CVBasic) + ' https://nanochess.org/ + ' + ' Creation date: Feb/09/2026. + ' + + ' + ' The RGB (red-green-blue) color order inside the 16-bit word is: + ' 0 0 0 0 0 g g g 0 r r r 0 b b b + ' + + PRINT AT 33,"Hello world!" + + PALETTE LOAD main_palette + + FOR #c = $0400 TO $043F + VPOKE #c, $ff + NEXT #c + + d = $41 + FOR #c = $2400 TO $2438 STEP 8 + VPOKE #c, d + VPOKE #c + 1, d + VPOKE #c + 2, d + VPOKE #c + 3, d + VPOKE #c + 4, d + VPOKE #c + 5, d + VPOKE #c + 6, d + VPOKE #c + 7, d + d = d + $10 + NEXT #c + + e = $80 + FOR #c = $1810 TO $181E STEP 2 + FOR d = 0 TO 7 + VPOKE #c + d * 32, e + VPOKE #c + d * 32 + 1, e + NEXT d + e = e + 1 + NEXT #c + +main_loop: + FOR #c = $0010 TO $0070 STEP $0010 + WAIT + WAIT + PALETTE 15, #c + NEXT #c + + FOR #c = $0100 TO $0700 STEP $0100 + WAIT + WAIT + PALETTE 15, #c + NEXT #c + + FOR #c = $0001 TO $0007 STEP $0001 + WAIT + WAIT + PALETTE 15, #c + NEXT #c + + GOTO main_loop + +main_palette: + DATA $0000 + DATA $0462 + DATA $0777 + DATA $0777 + DATA $0000 + DATA $0001 + DATA $0012 + DATA $0123 + DATA $0234 + DATA $0345 + DATA $0456 + DATA $0567 + DATA $0777 + DATA $0777 + DATA $0777 + DATA $0777 diff --git a/manual.txt b/manual.txt index c677860..3776f62 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Nov/28/2025 +Last revision: Feb/09/2026 >>>>>>>>>>>>>> Legal notice @@ -22,7 +22,9 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.1 Feb/05/2026 o Added note about support of Blue and Purple buttons +v0.9.2 Feb/09/2026 o Added support for MSX2 using --msx2 + o MSX2: It supports the PALETTE statement. + o Added note about support of Blue and Purple buttons (Super Action Controllers for Colecovision) o Added support for spinners and roller controller using CONT1.SPINNER and CONT2.SPINNER (Colecovision) @@ -895,6 +897,15 @@ The following statements are available: PALETTE LOAD array_data_byte PALETTE LOAD VARPTR array_data_byte(0) + For MSX2: + + Sets a single palette register (0-15) to the color. Color bits are + specified in a word as 0000 0GGG 0RRR 0BBB (three bits each for + red, green, and blue) + + Alternatively, you can load a full 16 entries palette using PALETTE LOAD. + The array should be specified with DATA. + For the Sega Master System: Sets a single palette register (0-31) to the color (0-63). Color bits are From cd2f793b01e2ab1acdc0a24b04eae6d6f0a5c320 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 15:48:11 -0600 Subject: [PATCH 095/155] MSX2: Added support for extended sprite mode --- cvbasic.c | 321 +++++++++++++++++++++----------------- cvbasic_epilogue.asm | 6 +- cvbasic_prologue.asm | 81 +++++++++- examples/palette_msx2.bas | 31 +++- 4 files changed, 297 insertions(+), 142 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 392fc56..c3457bf 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -4120,88 +4120,13 @@ void compile_statement(int check_for_else) emit_error("syntax error in DEFINE"); } else if (strcmp(name, "SPRITE") == 0) { get_lex(); - if (lex == C_NAME && strcmp(name, "PLETTER") == 0) { - pletter = 1; - get_lex(); - } - if (pletter) { - type = evaluate_expression(1, TYPE_16, 0); - if (target == CPU_6502) { - cpu6502_1op("ASL", "A"); - cpu6502_1op("ASL", "A"); - cpu6502_1op("LDY", "#7"); - cpu6502_1op("STY", "pointer+1"); - cpu6502_1op("ASL", "A"); - cpu6502_1op("ROL", "pointer+1"); - cpu6502_1op("ASL", "A"); - cpu6502_1op("ROL", "pointer+1"); - cpu6502_1op("ASL", "A"); - cpu6502_1op("ROL", "pointer+1"); - cpu6502_1op("STA", "pointer"); - } else if (target == CPU_9900) { - cpu9900_2op("mov","r0","r4"); - cpu9900_2op("sla","r4","5"); - cpu9900_2op("ai","r4",">3800"); - } else { - cpuz80_2op("ADD", "HL", "HL"); - cpuz80_2op("ADD", "HL", "HL"); - if (machine == SMS) - cpuz80_2op("SET", "1", "H"); - else - cpuz80_2op("LD", "H", "$07"); - cpuz80_2op("ADD", "HL", "HL"); - cpuz80_2op("ADD", "HL", "HL"); - cpuz80_2op("ADD", "HL", "HL"); - if (machine == SMS) - cpuz80_2op("ADD", "HL", "HL"); - cpuz80_2op("EX", "DE", "HL"); - } - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in DEFINE"); - type = evaluate_expression(2, TYPE_8, 0); - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in DEFINE"); - if (lex != C_NAME) { - emit_error("missing label in DEFINE"); - } else { - if (target == CPU_6502) { - strcpy(temp, "#" LABEL_PREFIX); - strcat(temp, name); - cpu6502_1op("LDA", temp); - strcat(temp, ">>8"); - cpu6502_1op("LDY", temp); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); - } else if (target == CPU_9900) { - strcpy(temp, LABEL_PREFIX); - strcat(temp, name); - cpu9900_2op("li", "r2", temp); - cpu9900_2op("mov","r4","r1"); - } else { - strcpy(temp, LABEL_PREFIX); - strcat(temp, name); - cpuz80_2op("LD", "HL", temp); - } - get_lex(); - } - generic_call("unpack"); - compression_used = 1; - } else { + if (lex == C_NAME && strcmp(name, "COLOR") == 0 && machine == MSX2) { struct node *length; struct node *source = NULL; - type = evaluate_expression(1, TYPE_16, 0); /* char number */ - if (target == CPU_6502) { - cpu6502_1op("STA", "pointer"); - } else if (target == CPU_9900) { - cpu9900_2op("mov","r0","r4"); - } else { - cpuz80_1op("PUSH", "HL"); - } + get_lex(); + type = evaluate_expression(1, TYPE_16, 0); /* sprite number */ + cpuz80_1op("PUSH", "HL"); if (lex == C_COMMA) get_lex(); else @@ -4216,49 +4141,162 @@ void compile_statement(int check_for_else) } else if (strcmp(name, "VARPTR") == 0) { source = evaluate_save_expression(1, TYPE_16); /* CPU address (variable) */ node_generate(length, 0); + if ((source->regs & REG_A) != 0) + cpuz80_1op("PUSH", "AF"); + node_generate(source, 0); + if ((source->regs & REG_A) != 0) + cpuz80_1op("POP", "AF"); + } else { + node_generate(length, 0); /* CPU address (immediate) */ + strcpy(temp, LABEL_PREFIX); + strcat(temp, name); + cpuz80_2op("LD", "HL", temp); + get_lex(); + } + generic_call("define_sprite_color"); + node_delete(length); + node_delete(source); + } else { + if (lex == C_NAME && strcmp(name, "PLETTER") == 0) { + pletter = 1; + get_lex(); + } + if (pletter) { + type = evaluate_expression(1, TYPE_16, 0); if (target == CPU_6502) { - cpu6502_noop("PHA"); - node_generate(source, 0); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); - cpu6502_noop("PLA"); + cpu6502_1op("ASL", "A"); + cpu6502_1op("ASL", "A"); + cpu6502_1op("LDY", "#7"); + cpu6502_1op("STY", "pointer+1"); + cpu6502_1op("ASL", "A"); + cpu6502_1op("ROL", "pointer+1"); + cpu6502_1op("ASL", "A"); + cpu6502_1op("ROL", "pointer+1"); + cpu6502_1op("ASL", "A"); + cpu6502_1op("ROL", "pointer+1"); + cpu6502_1op("STA", "pointer"); } else if (target == CPU_9900) { - cpu9900_2op("mov","r0","r5"); - node_generate(source, 0); + cpu9900_2op("mov","r0","r4"); + cpu9900_2op("sla","r4","5"); + cpu9900_2op("ai","r4",">3800"); } else { - if ((source->regs & REG_A) != 0) - cpuz80_1op("PUSH", "AF"); - node_generate(source, 0); - if ((source->regs & REG_A) != 0) - cpuz80_1op("POP", "AF"); + cpuz80_2op("ADD", "HL", "HL"); + cpuz80_2op("ADD", "HL", "HL"); + if (machine == SMS) + cpuz80_2op("SET", "1", "H"); + else + cpuz80_2op("LD", "H", "$07"); + cpuz80_2op("ADD", "HL", "HL"); + cpuz80_2op("ADD", "HL", "HL"); + cpuz80_2op("ADD", "HL", "HL"); + if (machine == SMS) + cpuz80_2op("ADD", "HL", "HL"); + cpuz80_2op("EX", "DE", "HL"); + } + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in DEFINE"); + type = evaluate_expression(2, TYPE_8, 0); + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in DEFINE"); + if (lex != C_NAME) { + emit_error("missing label in DEFINE"); + } else { + if (target == CPU_6502) { + strcpy(temp, "#" LABEL_PREFIX); + strcat(temp, name); + cpu6502_1op("LDA", temp); + strcat(temp, ">>8"); + cpu6502_1op("LDY", temp); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + } else if (target == CPU_9900) { + strcpy(temp, LABEL_PREFIX); + strcat(temp, name); + cpu9900_2op("li", "r2", temp); + cpu9900_2op("mov","r4","r1"); + } else { + strcpy(temp, LABEL_PREFIX); + strcat(temp, name); + cpuz80_2op("LD", "HL", temp); + } + get_lex(); } + generic_call("unpack"); + compression_used = 1; } else { - node_generate(length, 0); /* CPU address (immediate) */ + struct node *length; + struct node *source = NULL; + + type = evaluate_expression(1, TYPE_16, 0); /* sprite number */ if (target == CPU_6502) { - cpu6502_noop("PHA"); - strcpy(temp, "#" LABEL_PREFIX); - strcat(temp, name); - cpu6502_1op("LDA", temp); - cpu6502_1op("STA", "temp"); - strcat(temp, ">>8"); - cpu6502_1op("LDA", temp); - cpu6502_1op("STA", "temp+1"); - cpu6502_noop("PLA"); + cpu6502_1op("STA", "pointer"); } else if (target == CPU_9900) { - cpu9900_2op("mov","r0","r5"); - strcpy(temp, LABEL_PREFIX); - strcat(temp, name); - cpu9900_2op("li","r0",temp); + cpu9900_2op("mov","r0","r4"); } else { - strcpy(temp, LABEL_PREFIX); - strcat(temp, name); - cpuz80_2op("LD", "HL", temp); + cpuz80_1op("PUSH", "HL"); } - get_lex(); + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in DEFINE"); + length = evaluate_save_expression(1, TYPE_8); /* count */ + if (lex == C_COMMA) + get_lex(); + else + emit_error("missing comma in DEFINE"); + if (lex != C_NAME) { + emit_error("missing label in DEFINE"); + } else if (strcmp(name, "VARPTR") == 0) { + source = evaluate_save_expression(1, TYPE_16); /* CPU address (variable) */ + node_generate(length, 0); + if (target == CPU_6502) { + cpu6502_noop("PHA"); + node_generate(source, 0); + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); + cpu6502_noop("PLA"); + } else if (target == CPU_9900) { + cpu9900_2op("mov","r0","r5"); + node_generate(source, 0); + } else { + if ((source->regs & REG_A) != 0) + cpuz80_1op("PUSH", "AF"); + node_generate(source, 0); + if ((source->regs & REG_A) != 0) + cpuz80_1op("POP", "AF"); + } + } else { + node_generate(length, 0); /* CPU address (immediate) */ + if (target == CPU_6502) { + cpu6502_noop("PHA"); + strcpy(temp, "#" LABEL_PREFIX); + strcat(temp, name); + cpu6502_1op("LDA", temp); + cpu6502_1op("STA", "temp"); + strcat(temp, ">>8"); + cpu6502_1op("LDA", temp); + cpu6502_1op("STA", "temp+1"); + cpu6502_noop("PLA"); + } else if (target == CPU_9900) { + cpu9900_2op("mov","r0","r5"); + strcpy(temp, LABEL_PREFIX); + strcat(temp, name); + cpu9900_2op("li","r0",temp); + } else { + strcpy(temp, LABEL_PREFIX); + strcat(temp, name); + cpuz80_2op("LD", "HL", temp); + } + get_lex(); + } + generic_call("define_sprite"); + node_delete(length); + node_delete(source); } - generic_call("define_sprite"); - node_delete(length); - node_delete(source); } } else if (strcmp(name, "CHAR") == 0 || strcmp(name, "COLOR") == 0) { int color; @@ -4564,39 +4602,44 @@ void compile_statement(int check_for_else) cpu6502_1op("STA", "sprite_data+3"); else cpu6502_1op("STA", "sprite_data+1"); - } else if (target == CPU_9900) + } else if (target == CPU_9900) { cpu9900_2op("movb","r0","r6"); - else + } else { cpuz80_1op("PUSH", "AF"); + } if (lex == C_COMMA) get_lex(); else emit_error("missing comma in SPRITE"); type = evaluate_expression(1, TYPE_8, 0); - if (machine != SMS) { - if (target == CPU_6502) { - if (machine == NES) - cpu6502_1op("STA", "sprite_data+1"); + if (machine == MSX2 && lex != C_COMMA) { + generic_call("update_sprite2"); + } else { + if (machine != SMS) { + if (target == CPU_6502) { + if (machine == NES) + cpu6502_1op("STA", "sprite_data+1"); + else + cpu6502_1op("STA", "sprite_data+2"); + } else if (target == CPU_9900) + cpu9900_2op("movb","r0","r7"); else - cpu6502_1op("STA", "sprite_data+2"); - } else if (target == CPU_9900) - cpu9900_2op("movb","r0","r7"); - else - cpuz80_1op("PUSH", "AF"); - if (lex == C_COMMA) - get_lex(); - else - emit_error("missing comma in SPRITE"); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_6502) { - if (machine == NES) - cpu6502_1op("STA", "sprite_data+2"); + cpuz80_1op("PUSH", "AF"); + if (lex == C_COMMA) + get_lex(); else - cpu6502_1op("STA", "sprite_data+3"); - cpu6502_noop("PLA"); + emit_error("missing comma in SPRITE"); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_6502) { + if (machine == NES) + cpu6502_1op("STA", "sprite_data+2"); + else + cpu6502_1op("STA", "sprite_data+3"); + cpu6502_noop("PLA"); + } } + generic_call("update_sprite"); } - generic_call("update_sprite"); } } else if (strcmp(name, "BITMAP") == 0) { generic_dump(); @@ -5116,22 +5159,22 @@ void compile_statement(int check_for_else) get_lex(); if (value == 0) { if (machine == SMS) - emit_error("Use SG1000 if you want to use MODE 0"); + emit_warning("MODE 0 isn't upward compatible with Sega Genesis/Mega Drive"); generic_call("mode_0"); } if (value == 1) { if (machine == SMS) - emit_error("Use SG1000 if you want to use MODE 1"); + emit_warning("MODE 1 isn't upward compatible with Sega Genesis/Mega Drive"); generic_call("mode_1"); } if (value == 2) { if (machine == SMS) - emit_error("Use SG1000 if you want to use MODE 2"); + emit_warning("MODE 2 isn't upward compatible with Sega Genesis/Mega Drive"); generic_call("mode_2"); } if (value == 4) { - if (machine != SMS) - emit_error("MODE 4 only supported for Sega Master System"); + if (machine != SMS && machine != MSX2) + emit_error("MODE 4 not supported by this platform"); generic_call("mode_4"); } } else if (strcmp(name, "SCREEN") == 0) { /* Copy screen */ diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 00a9d88..2db8b1d 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -73,7 +73,11 @@ cursor: lfsr: rb 2 mode: - rb 1 + rb 1 ; bit 0: NMI disabled. + ; bit 1: NMI received. + ; bit 2: No sprite flicker. + ; bit 3: Single charset mode. + ; bit 4: MSX2 sprites. flicker: rb 1 joy1_data: diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 9f018c4..c681236 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -42,6 +42,7 @@ ; Revision date: Feb/05/2026. Added support for spinners and roller controller ; (Colecovision). ; Revision date: Feb/09/2026. Added support for palette in MSX2. + ; Revision date: Feb/10/2026. Added support for sprites in MSX2. ; JOYSEL: equ $c0 @@ -1233,6 +1234,72 @@ palette_load: jp nz,$-2 ei ret + +define_sprite_color: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + add hl,hl ; x16 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld h,$0e + add hl,hl ; x16 + ex de,hl + call nmi_off + call LDIRVM + jp nmi_on + +update_sprite2: + pop bc + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + ld de,sprites + add a,a + add a,a + ld e,a + ld hl,sprite_data + ld bc,3 + ldir + ret + +mode_4: + ld hl,mode + res 3,(hl) + set 4,(hl) + ld bc,$0400 ; Normal mode but with enhanced sprites enabled. + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld bc,$3c05 ; $1e00 for sprite attribute table... + call WRTVDP ; ...so sprite colors appear at $1c00-$1dff. + ld hl,($0004) + inc h + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites endif if SMS @@ -1333,6 +1400,7 @@ vdp_generic_mode: mode_0: ld hl,mode res 3,(hl) + res 4,(hl) ld bc,$0200 ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode @@ -1365,7 +1433,11 @@ mode_0: call cls vdp_generic_sprites: call nmi_off + ld a,(mode) + bit 4,a ld hl,$1b00 + jr z,$+4 + ld h,$1e ld bc,$0080 ld a,$d1 call FILVRM @@ -1380,6 +1452,7 @@ vdp_generic_sprites: mode_1: ld hl,mode res 3,(hl) + res 4,(hl) ld bc,$0200 ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode @@ -1410,6 +1483,7 @@ mode_1: mode_2: ld hl,mode set 3,(hl) + res 4,(hl) ld bc,$0000 ld de,$8000 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode @@ -1581,8 +1655,11 @@ nmi_handler: ld bc,$8000+VDP bit 2,(hl) jr z,.4 - + bit 4,(hl) ld hl,$1b00 + jr z,$+4 +.10: + ld h,$1e call SETWRT ld hl,sprites .7: @@ -1602,7 +1679,9 @@ nmi_handler: jr .5 .4: + bit 4,(hl) ld hl,$1b00 + jr nz,.10 ; No flicker sprites in MSX2 mode. call SETWRT ld a,(flicker) add a,$04 diff --git a/examples/palette_msx2.bas b/examples/palette_msx2.bas index cdad7b4..a2963d1 100644 --- a/examples/palette_msx2.bas +++ b/examples/palette_msx2.bas @@ -12,6 +12,11 @@ ' 0 0 0 0 0 g g g 0 r r r 0 b b b ' + MODE 4 + + DEFINE SPRITE 0, 1, happy_face + DEFINE SPRITE COLOR 0,1,sprite_color + PRINT AT 33,"Hello world!" PALETTE LOAD main_palette @@ -43,6 +48,8 @@ NEXT #c main_loop: + SPRITE 0, $60, $40, 0 + FOR #c = $0010 TO $0070 STEP $0010 WAIT WAIT @@ -76,7 +83,29 @@ main_palette: DATA $0345 DATA $0456 DATA $0567 + DATA $0374 DATA $0777 DATA $0777 DATA $0777 - DATA $0777 + +happy_face: + BITMAP "......XXXX......" + BITMAP "....XXXXXXXX...." + BITMAP "...XXXXXXXXXX..." + BITMAP "..XXXXXXXXXXXX.." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP "XXXX..XXXX..XXXX" + BITMAP "XXXX..XXXX..XXXX" + BITMAP "XXXXXXXXXXXXXXXX" + BITMAP "XXXXXXXXXXXXXXXX" + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXX..XXXX..XXX." + BITMAP "..XXX......XXX.." + BITMAP "...XXX....XXX..." + BITMAP "....XXXXXXXX...." + BITMAP "......XXXX......" + +sprite_color: + DATA BYTE $0B,$0B,$0A,$0A,$09,$09,$08,$08 + DATA BYTE $07,$07,$06,$06,$05,$05,$04,$04 From 97131950589ec8f229d42224a29546ff8495093c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 16:12:34 -0600 Subject: [PATCH 096/155] MSX2: Added manual notes about extended sprite mode --- README.md | 16 +++++++++++++++- manual.txt | 48 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1005683..80b519c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The CVBasic compiler can create programs up to 1 MB using the BANK statements (u It has been extended to support the following platforms: * Sega SG-1000 / SC-3000 (supporting bank switching with Sega mapper) -* MSX 1 (supporting bank switching with ASCII16 mapper) +* MSX 1 and MSX 2 (supporting bank switching with ASCII16 mapper) * Texas Instruments TI-99/4A (courtesy of @tursilion, supporting bank switching) * Spectravideo SVI-318 / 328. * Sord M5. @@ -79,6 +79,7 @@ The following files compose the compiler: examples/oscar.bas High-resolution graphics example. examples/oscar_nes.bas High-resolution graphics example (NES/Famicom) examples/oscar_sms.bas High-resolution graphics example (Sega Master System) + examples/palette_msx2.bas Example of palette support in MSX2 examples/portrait.bas Data used by demo.bas examples/portrait_sms.bas Data used by demo_sms.bas examples/space_attack.bas Game example. @@ -127,6 +128,19 @@ Using CVBasic to compile a MSX program for 8K RAM (wider compatibility) and 16K For bank-switched programs the default mapper is ASCII16, but you have the option of using a standard Konami 8K mapper using the -konami switch. +Using CVBasic to compile a MSX2 program for 8K RAM (wider compatibility) and 16K RAM: + + cvbasic --msx2 game.bas game.asm + gasm80 game.asm -o game.rom + + cvbasic --msx2 -ram16 game.bas game.asm + gasm80 game.asm -o game.rom + + cvbasic --msx2 -ram16 -konami game.bas game.asm + gasm80 game.asm -o game.rom + +For bank-switched programs the default mapper is ASCII16, but you have the option of using a standard Konami 8K mapper using the -konami switch. + Using CVBasic to compile a Colecovision Super Game Module program: cvbasic --sgm game.bas game.asm diff --git a/manual.txt b/manual.txt index 3776f62..79dda1f 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Feb/09/2026 +Last revision: Feb/10/2026 >>>>>>>>>>>>>> Legal notice @@ -24,6 +24,8 @@ All trademarks are property of their respective owners. v0.9.2 Feb/09/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. + o MSX2: It supports MODE 4, extended sprites, and + DEFINE SPRITE COLOR. o Added note about support of Blue and Purple buttons (Super Action Controllers for Colecovision) o Added support for spinners and roller controller @@ -647,6 +649,25 @@ The following statements are available: with the Pletter compressor (TMSColor does the compression if you give the option -z) + DEFINE SPRITE COLOR sprite_num,total,label + DEFINE SPRITE COLOR sprite_num,total,VARPTR array(expr) + + This is for MSX2 sprites (MODE 4) + + It allows to define the color for each pixel row of a 16x16 sprite. + + The data should be represente as DATA BYTE and 16 values for each sprite. + + Each byte contains the color (bits 3-0) + + bit 5 = IC bit. The sprite with this bit set doesn't generate a + collision. + bit 6 = CC bit. The sprite with this bit set has its pixels OR'ed + with the immediately preceding sprite with CC bit 0 (useful + to create more colors) + bit 7 = EC bit, When set the sprite is rendered 32 pixels to the + left. + DEFINE VRAM address,length,label DEFINE VRAM address,length,VARPTR array(expr) DEFINE VRAM PLETTER address,length,label @@ -753,7 +774,8 @@ The following statements are available: SPRITE index,y,x,f,c (All others) - SPRITE index,y,x,f. (SMS) + SPRITE index,y,x,f (SMS) + SPRITE index,y,x,f (MSX2) SPRITE index,y,x,f,a (NES/Famicom) The first parameter indicates the number of the sprite (0-31). @@ -776,6 +798,10 @@ The following statements are available: The fourth argument (color) isn't used on Sega Master System, and it will generate an error from CVBasic if present. + For MSX2, the fourth argument is optional if MODE 4 has been + selected, and the color for the sprites should be defined using + the statement DEFINE COLOR SPRITE. + Sprites are updated on the vertical retrace. The Y-coordinate visible range for sprites is 240 to 255, and 0 @@ -786,7 +812,8 @@ The following statements are available: Additionally, the value 208 for the Y-coordinate disables sprite processing starting on that very sprite. For example, - SPRITE 0,$d0,0,0,0 forces sprites 1-31 to disappear even if active. + SPRITE 0,$d0,0,0,0 forces sprites 1-31 to disappear even if active + (For MSX2 the value disabling sprite processing is 216 or $d8) NES/Famicom notes: @@ -994,11 +1021,16 @@ The following statements are available: MODE 4 - It is only available on Sega Master System, and it is the only mode supported - in this console. VRAM $0000-$1fff are setup as background bitmaps, $2000-$37ff - for sprites bitmaps, $3800-$3dff for the background patterns, and $3f00-$3fff - for the sprites attributes. The unused portion $3e00-$3eff and $3f40-$3f7f - can be used for extra sprites (sprite numbers 120-123 and 125) + Sega Master System: It is the only mode supported. VRAM $0000-$1fff are + setup as background bitmaps, $2000-$37ff for sprites bitmaps, $3800-$3dff + for the background patterns, and $3f00-$3fff for the sprites attributes. + The unused portion $3e00-$3eff and $3f40-$3f7f can be used for extra sprites + (sprite numbers 120-123 and 125) + + MSX2: It is pretty similar to MODE 0, except that extended sprites are + enabled. This allows for eight sprites in a row. And each sprite can have + a different color per row. The colors for the sprites should be defined + using the statement DEFINE SPRITE COLOR. SCREEN DISABLE From a0a5ff74692a9671a8ce45a70935fe37148c049c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 17:06:46 -0600 Subject: [PATCH 097/155] MSX2: It now can access 64K of VRAM. Relocated sprite color table --- cvbasic_prologue.asm | 46 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index c681236..4c6f93b 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -42,7 +42,8 @@ ; Revision date: Feb/05/2026. Added support for spinners and roller controller ; (Colecovision). ; Revision date: Feb/09/2026. Added support for palette in MSX2. - ; Revision date: Feb/10/2026. Added support for sprites in MSX2. + ; Revision date: Feb/10/2026. Added support for sprites in MSX2 and 64K VRAM + ; access. ; JOYSEL: equ $c0 @@ -383,6 +384,18 @@ SETWRT: if COLECO_SPINNER di endif + if MSX&2 + xor a + rlc h + rla + rlc h + rla + srl h + srl h + out (VDP+1),a + ld a,$8e + out (VDP+1),a + endif ld a,l out (VDP+1),a ld a,h @@ -397,6 +410,18 @@ SETRD: if COLECO_SPINNER di endif + if MSX&2 + xor a + rlc h + rla + rlc h + rla + srl h + srl h + out (VDP+1),a + ld a,$8e + out (VDP+1),a + endif ld a,l out (VDP+1),a ld a,h @@ -1251,7 +1276,7 @@ define_sprite_color: add hl,hl ; x2 add hl,hl ; x4 add hl,hl ; x8 - ld h,$0e + ld h,$40/2 add hl,hl ; x16 ex de,hl call nmi_off @@ -1284,8 +1309,10 @@ mode_4: ld bc,$0400 ; Normal mode but with enhanced sprites enabled. ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode - ld bc,$3c05 ; $1e00 for sprite attribute table... - call WRTVDP ; ...so sprite colors appear at $1c00-$1dff. + ld bc,$8405 ; $4200 for sprite attribute table... + call WRTVDP ; ...so sprite colors appear at $4000-$41ff. + ld bc,$000b + call WRTVDP ld hl,($0004) inc h ld de,$0100 @@ -1436,15 +1463,16 @@ vdp_generic_sprites: ld a,(mode) bit 4,a ld hl,$1b00 - jr z,$+4 - ld h,$1e - ld bc,$0080 ld a,$d1 + jr z,$+6 + ld h,$42 + ld a,$e0 + ld bc,$0080 call FILVRM ld hl,sprites ld de,sprites+1 ld bc,127 - ld (hl),$d1 + ld (hl),a ldir call nmi_on jp ENASCR @@ -1659,7 +1687,7 @@ nmi_handler: ld hl,$1b00 jr z,$+4 .10: - ld h,$1e + ld h,$42 call SETWRT ld hl,sprites .7: From 01706495ae661090f65304639c78ba30567742de Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 18:01:45 -0600 Subject: [PATCH 098/155] MSX2: Added viboritas_msx2.bas example --- examples/viboritas_msx2.bas | 914 ++++++++++++++++++++++++++++++++++++ 1 file changed, 914 insertions(+) create mode 100644 examples/viboritas_msx2.bas diff --git a/examples/viboritas_msx2.bas b/examples/viboritas_msx2.bas new file mode 100644 index 0000000..b7d4696 --- /dev/null +++ b/examples/viboritas_msx2.bas @@ -0,0 +1,914 @@ + ' + ' Viboritas (demo for CVBasic) + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Oct/1990. + ' Revision date: Feb/29/2024. Ported to CVBasic. + ' Revision date: Feb/10/2026. Adapted to MSX2. + ' + + ' The original game was made in Z80 assembler, + ' you can see it here: https://nanochess.org/viboritas.html + + ' It is easier to understand in CVBasic ;) + + MODE 4 + SCREEN DISABLE + PALETTE LOAD game_palette + FOR c = 32 TO 127 + DEFINE COLOR c,1,letter_colors + NEXT c + SCREEN ENABLE + DEFINE CHAR 128,21,game_bitmaps + DEFINE COLOR 128,21,game_colors + DEFINE SPRITE 0,20,game_sprites + DEFINE SPRITE COLOR 0,2,VARPTR sprites_color(0) + DEFINE SPRITE COLOR 2,2,VARPTR sprites_color(32) + DEFINE SPRITE COLOR 4,2,VARPTR sprites_color(32) + DEFINE SPRITE COLOR 6,2,VARPTR sprites_color(32) + +restart_game: + lives = 2 + level = 1 +restart_level: + WAIT + + PRINT AT 684,"Lives: ",lives + PRINT AT 745,"nanochess 1990" + +next_level: + GOSUB draw_level + + x_player = 8 + y_player = 16 + player_frame = 0 + + x_enemy1 = random(128) + 64 + y_enemy1 = 56 + enemy1_frame = 24 + x_enemy2 = random(128) + 80 + y_enemy2 = 96 + enemy2_frame = 32 + x_enemy3 = random(128) + 48 + y_enemy3 = 136 + enemy3_frame = 24 + + enemy_speed = 0 + + GOSUB start_song + +game_loop: + WHILE 1 + WAIT + GOSUB play_song + + SPRITE 0, y_player - 1, x_player, player_frame * 2 + SPRITE 1, y_player - 1, x_player, player_frame * 2 + 4 + SPRITE 2, y_enemy1 - 1, x_enemy1, enemy1_frame * 2 + SPRITE 3, y_enemy1 - 1, x_enemy1, enemy1_frame * 2 + 4 + SPRITE 4, y_enemy2 - 1, x_enemy2, enemy2_frame * 2 + SPRITE 5, y_enemy2 - 1, x_enemy2, enemy2_frame * 2 + 4 + SPRITE 6, y_enemy3 - 1, x_enemy3, enemy3_frame * 2 + SPRITE 7, y_enemy3 - 1, x_enemy3, enemy3_frame * 2 + 4 + + GOSUB move_player + + c = $50 + level * 4 + enemy_speed = enemy_speed + c + WHILE enemy_speed >= $40 + enemy_speed = enemy_speed - $40 + GOSUB move_enemies + WEND + IF cont1.button THEN + IF x_player > 232 AND x_player < 248 AND y_player = 136 THEN + GOSUB sound_off + + FOR c = 1 to 10 + WAIT + SOUND 5, 200 - c * 10, 13 + NEXT c + + level = level + 1 + IF level = 6 THEN + GOSUB sound_off + PRINT AT 267," YOU WIN! " + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + level = 1 + GOTO restart_level + END IF + GOTO next_level + END IF + END IF + IF ABS(y_player + 1 - y_enemy1) < 8 THEN + IF ABS(x_player + 1 - x_enemy1) < 8 THEN GOTO player_dies + END IF + IF ABS(y_player + 1 - y_enemy2) < 8 THEN + IF ABS(x_player + 1 - x_enemy2) < 8 THEN GOTO player_dies + END IF + IF ABS(y_player + 1 - y_enemy3) < 8 THEN + IF ABS(x_player + 1 - x_enemy3) < 8 THEN GOTO player_dies + END IF + WEND + +player_dies: + GOSUB sound_off + + SOUND 5,640,13 + SOUND 6,320,13 + SOUND 7,160,13 + + player_frame = 0 + FOR c = 0 TO 30 + WAIT + WAIT + player_frame = player_frame XOR 8 + SPRITE 0, y_player - 1, x_player, player_frame * 2 + SPRITE 1, y_player - 1, x_player, player_frame * 2 + 4 + NEXT c + + GOSUB sound_off + + DO + WAIT + SOUND 5,200 - y_player,13 + player_frame = player_frame XOR 8 + SPRITE 0, y_player - 1, x_player, player_frame * 2 + SPRITE 1, y_player - 1, x_player, player_frame * 2 + 4 + y_player = y_player + 2 + LOOP WHILE y_player < 160 + + GOSUB sound_off + + IF lives = 0 THEN + PRINT AT 267," GAME OVER " + #c = FRAME + DO + WAIT + LOOP WHILE FRAME - #c < 300 + GOTO restart_game + END IF + lives = lives - 1 + GOTO restart_level + + ' + ' Draw the current level. + ' +draw_level: PROCEDURE + + ' Get the base character to draw the level. + base_character = 128 + (level - 1) * 4 + + ' Draw the background. + FOR #c = $1800 TO $1a7c STEP 4 + VPOKE #c, base_character + VPOKE #c + 1, base_character + VPOKE #c + 2, base_character + VPOKE #c + 3, base_character + 1. + NEXT #c + + ' Draw over the floors. + FOR #c = $1880 TO $1A60 STEP 160 + FOR #d = #c TO #c + 31 + VPOKE #d, base_character + 2. + NEXT #d + NEXT #c + + ' Draw the ladders. + ladders = 6 - level + + FOR #c = $1880 TO $19C0 STEP 160 + FOR d = 1 TO ladders + e = RANDOM(28) + 2 + VPOKE #c + e, base_character + 3. + VPOKE #c + e + 32, base_character + 3. + VPOKE #c + e + 64, base_character + 3. + VPOKE #c + e + 96, base_character + 3. + VPOKE #c + e + 128, base_character + 3. + NEXT d + NEXT #c + + ' Draw the "exit". + VPOKE $1A5E, 148 + + END + + ' + ' Move the player + ' +move_player: PROCEDURE + IF cont1.left THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor + IF x_player > 0 THEN x_player = x_player - 1 + IF FRAME AND 4 THEN player_frame = 8 ELSE player_frame = 12 + END IF + END IF + IF cont1.right THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor + IF x_player < 240 THEN x_player = x_player + 1 + IF FRAME AND 4 THEN player_frame = 0 ELSE player_frame = 4 + END IF + END IF + IF cont1.up THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor. + column = (x_player + 7) /8 + row = (y_player + 8) / 8 + #c = $1800 + row * 32 + column + IF VPEEK(#c) = base_character + 3 THEN ' Ladder? + y_player = y_player - 1 + END IF + ELSE + IF FRAME AND 4 THEN player_frame = 16 ELSE player_frame = 20 + y_player = y_player - 1 + END IF + END IF + IF cont1.down THEN + IF y_player % 40 = 16 THEN ' Player aligned on floor. + column = (x_player + 7) /8 + row = (y_player + 16) / 8 + #c = $1800 + row * 32 + column + IF VPEEK(#c) = base_character + 3 THEN ' Ladder? + y_player = y_player + 1 + END IF + ELSE + IF FRAME AND 4 THEN player_frame = 16 ELSE player_frame = 20 + y_player = y_player + 1 + END IF + END IF + END + + ' + ' Move the enemies. + ' +move_enemies: PROCEDURE + IF enemy1_frame < 32 THEN + x_enemy1 = x_enemy1 - 1. + IF x_enemy1 = 0 THEN enemy1_frame = 32 + ELSE + x_enemy1 = x_enemy1 + 1. + IF x_enemy1 = 240 THEN enemy1_frame = 24 + END IF + enemy1_frame = (enemy1_frame AND $f8) + (FRAME AND 4) + + IF enemy2_frame < 32 THEN + x_enemy2 = x_enemy2 - 1. + IF x_enemy2 = 0 THEN enemy2_frame = 32 + ELSE + x_enemy2 = x_enemy2 + 1. + IF x_enemy2 = 240 THEN enemy2_frame = 24 + END IF + enemy2_frame = (enemy2_frame AND $f8) + (FRAME AND 4) + + IF enemy3_frame < 32 THEN + x_enemy3 = x_enemy3 - 1. + IF x_enemy3 = 0 THEN enemy3_frame = 32 + ELSE + x_enemy3 = x_enemy3 + 1. + IF x_enemy3 = 240 THEN enemy3_frame = 24 + END IF + enemy3_frame = (enemy3_frame AND $f8) + (FRAME AND 4) + END + +game_bitmaps: + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + BITMAP "XXX..XXX" + + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "........" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "........" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + + BITMAP ".X....X." + BITMAP ".X....X." + BITMAP ".XXXXXX." + BITMAP ".X....X." + BITMAP ".X....X." + BITMAP ".XXXXXX." + BITMAP ".X....X." + BITMAP ".X....X." + + BITMAP "XXXXXXX." + BITMAP "X.....X." + BITMAP "X.XXX.X." + BITMAP "X.X.X.X." + BITMAP "X.XXX.X." + BITMAP "X.....X." + BITMAP "XXXXXXX." + BITMAP "........" + + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + BITMAP "X.XXX.X." + + BITMAP "XXX.XXX." + BITMAP "........" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".X....X." + BITMAP ".X....X." + BITMAP ".XXXXXX." + BITMAP ".X....X." + BITMAP ".X....X." + BITMAP ".XXXXXX." + BITMAP ".X....X." + BITMAP ".X....X." + + BITMAP "XXX.XXXX" + BITMAP "XXX.XXXX" + BITMAP "XXX.XXXX" + BITMAP "........" + BITMAP "XXXXXXX." + BITMAP "XXXXXXX." + BITMAP "XXXXXXX." + BITMAP "........" + + BITMAP ".XXXXXX." + BITMAP ".XXXXXX." + BITMAP ".XXXXXX." + BITMAP "........" + BITMAP ".XX.XXX." + BITMAP ".XX.XXX." + BITMAP ".XX.XXX." + BITMAP "........" + + BITMAP "........" + BITMAP "XXXXXXXX" + BITMAP "XXXXXXXX" + BITMAP "X.X.X.X." + BITMAP ".X...X.." + BITMAP "........" + BITMAP "........" + BITMAP "........" + + BITMAP ".X....X." + BITMAP ".X....X." + BITMAP ".XXXXXX." + BITMAP ".X....X." + BITMAP ".X....X." + BITMAP ".XXXXXX." + BITMAP ".X....X." + BITMAP ".X....X." + + BITMAP "XXX.XXX." + BITMAP "XXX.XXX." + BITMAP "XXX.XXX." + BITMAP "........" + BITMAP "XXX.XXX." + BITMAP "XXX.XXX." + BITMAP "XXX.XXX." + BITMAP "........" + + BITMAP ".X......" + BITMAP "..XX...." + BITMAP "....XX.." + BITMAP "......XX" + BITMAP "....XX.." + BITMAP "..XX...." + BITMAP ".X......" + BITMAP ".X......" + + BITMAP "........" + BITMAP "XXXXXXXX" + BITMAP "........" + BITMAP "X.X.X.X." + BITMAP ".X.X.X.X" + BITMAP "........" + BITMAP "XXXXXXXX" + BITMAP "........" + + BITMAP "X......X" + BITMAP "X......X" + BITMAP "XX....XX" + BITMAP "X.XXXX.X" + BITMAP "X......X" + BITMAP "X......X" + BITMAP "XX....XX" + BITMAP "X.XXXX.X" + + BITMAP "X......X" + BITMAP ".X.XX..." + BITMAP "..XX.XXX" + BITMAP ".X...XXX" + BITMAP "..XXX..X" + BITMAP "..X..XXX" + BITMAP ".X..X..X" + BITMAP "..X..XXX" + + BITMAP ".X...XXX" + BITMAP ".X..X..X" + BITMAP "..X..XXX" + BITMAP ".X......" + BITMAP "..X.X..." + BITMAP "...X.X.X" + BITMAP "...X..X." + BITMAP "..X..XXX" + + BITMAP "........" + BITMAP "XXXXXXX." + BITMAP "XXXXXXX." + BITMAP "........" + BITMAP "XXX.XXXX" + BITMAP "XXX.XXXX" + BITMAP "........" + BITMAP "........" + + BITMAP "....XX.." + BITMAP "....XX.." + BITMAP "...XX..." + BITMAP "...XX..." + BITMAP "..XX...." + BITMAP "..XX...." + BITMAP "...XX..." + BITMAP "...XX..." + + BITMAP ".X.X.X.." + BITMAP "XXXXXXX." + BITMAP ".X.X.X.." + BITMAP "XXXXXXX." + BITMAP ".X.X.X.." + BITMAP "XXXXXXX." + BITMAP ".X.X.X.." + BITMAP "........" + +game_colors: + DATA BYTE $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC + DATA BYTE $21,$21,$21,$21,$21,$21,$21,$21 + DATA BYTE $A1,$A1,$A1,$A1,$A1,$A1,$A1,$A1 + DATA BYTE $51,$51,$51,$51,$51,$51,$51,$51 + + DATA BYTE $54,$54,$54,$54,$54,$54,$54,$54 + DATA BYTE $51,$51,$51,$51,$51,$51,$51,$51 + DATA BYTE $71,$11,$B1,$B1,$B1,$11,$11,$11 + DATA BYTE $51,$51,$51,$51,$51,$51,$51,$51 + + DATA BYTE $38,$38,$38,$38,$38,$38,$38,$38 + DATA BYTE $81,$81,$81,$81,$81,$81,$81,$81 + DATA BYTE $51,$51,$51,$51,$51,$51,$51,$51 + DATA BYTE $51,$51,$51,$51,$51,$51,$51,$51 + + DATA BYTE $31,$31,$31,$31,$31,$31,$31,$31 + DATA BYTE $A1,$A1,$A1,$A1,$A1,$A1,$A1,$A1 + DATA BYTE $71,$71,$71,$51,$51,$71,$71,$71 + DATA BYTE $B1,$B1,$B1,$B1,$B1,$B1,$B1,$B1 + + DATA BYTE $83,$83,$83,$83,$83,$83,$83,$83 + DATA BYTE $2C,$2C,$2C,$2C,$2C,$2C,$2C,$2C + DATA BYTE $11,$3B,$3B,$3B,$3B,$3B,$3B,$11 + DATA BYTE $C1,$C1,$C1,$C1,$C1,$C1,$C1,$C1 + + DATA BYTE $71,$71,$71,$71,$71,$71,$71,$71 + +letter_colors: + DATA BYTE $71,$71,$71,$71,$71,$71,$71,$71 + +game_palette: + DATA $0000 ' 0 + DATA $0000 ' 1 + DATA $0700 ' 2 Green + DATA $0250 ' 3 Red + DATA $0057 ' 4 Blue + DATA $0427 ' 5 Light blue + DATA $0507 ' 6 Player suit + DATA $0777 ' 7 White + DATA $0371 ' 8 Light red + DATA $0464 ' 9 Player face + DATA $0570 ' 10 Yellow + DATA $0555 ' 11 Gray + DATA $0400 ' 12 Dark green + DATA $0777 ' 13 Snake tongue + DATA $0600 ' 14 Snake body + DATA $0000 ' 15 Black border for sprites + +game_sprites: + BITMAP ".......X.X.X...." + BITMAP ".....XXXXX.XX..." + BITMAP "....XXX.....X..." + BITMAP ".....XX.....X..." + BITMAP "....XX....X.X..." + BITMAP ".....XX.X...X..." + BITMAP "....XXX.XXX.X..." + BITMAP "..XXXXXX...X...." + BITMAP ".XXXXXXXXXXXX..." + BITMAP "XXXXXXXXXXXXXX.." + BITMAP "XXXXXXXXXXXXXX.." + BITMAP "XXXXXXXXXXXXX..." + BITMAP ".XXXXXXXXXXXX..." + BITMAP "...XXXXXXXXXXX.." + BITMAP "...XXXXXXXXXXXX." + BITMAP "...XXXXXXXXXXX.." + + BITMAP ".......X.X.X...." + BITMAP ".....XXXXXXXX..." + BITMAP "....XXXXXXXXX..." + BITMAP ".....XXXXXXXX..." + BITMAP "....XXXXXXXXX..." + BITMAP ".....XXXXXXXX..." + BITMAP "....X..XXXXXX..." + BITMAP "..X....XXXXX...." + BITMAP ".X..X...XXXXX..." + BITMAP "X..XX....X...X.." + BITMAP "X...X....X...X.." + BITMAP "X...X.XXXXXXX..." + BITMAP ".XXXXX....XXX..." + BITMAP "...X...X.....X.." + BITMAP "...X...XX.....X." + BITMAP "...X....XXXXXX.." + + BITMAP "......XXXXXXXX.." + BITMAP ".....XXX.....X.." + BITMAP "......XX.....X.." + BITMAP ".....XX....X.X.." + BITMAP "......X..X...X.." + BITMAP ".....XXX.XXX.X.." + BITMAP ".....XXXX...X..." + BITMAP "....XXXXXXXX...." + BITMAP "....XXXXXXX....." + BITMAP "....XXXXXXXX...." + BITMAP "....XXXXXXXX...." + BITMAP "....XXXXXXX....." + BITMAP ".....XXXXXX....." + BITMAP ".....XXXX......." + BITMAP ".....XXXXXX....." + BITMAP ".....XXXXXXX...." + + BITMAP "......XXXXXXXX.." + BITMAP ".....XXXXXXXXX.." + BITMAP "......XXXXXXXX.." + BITMAP ".....XXXXXXXXX.." + BITMAP "......XXXXXXXX.." + BITMAP ".....X..XXXXXX.." + BITMAP ".....X..XXXXX..." + BITMAP "....X....XXX...." + BITMAP "....X.....X....." + BITMAP "....X..X...X...." + BITMAP "....X..X...X...." + BITMAP "....X...XXX....." + BITMAP ".....X....X....." + BITMAP ".....X..X......." + BITMAP ".....X....X....." + BITMAP ".....X.....X...." + + BITMAP "....X.X.X......." + BITMAP "...XXXXXXXX....." + BITMAP "...X.....XXX...." + BITMAP "...X.....XX....." + BITMAP "...X.X....XX...." + BITMAP "...X...X.XX....." + BITMAP "...X.XXX..XX...." + BITMAP "....X...XXXXXX.." + BITMAP ".....XXXXXXXXXX." + BITMAP "..XXXXXXXXXXXXXX" + BITMAP "..XXXXXXXXXXXXXX" + BITMAP "...XXX.XXXXXXXXX" + BITMAP "...XXXXXXXXXXXX." + BITMAP "..XXXXXXXXXXX..." + BITMAP ".XXXXXXXXXXXX..." + BITMAP "..XXXXXXXXXXX..." + + BITMAP "....X.X.X......." + BITMAP "...XXXXXXXX....." + BITMAP "...XXXXXXXXX...." + BITMAP "...XXXXXXXX....." + BITMAP "...XXXXXXXXX...." + BITMAP "...XXXXXXXX....." + BITMAP "...XXXXXXX.X...." + BITMAP "....XXXXX....X.." + BITMAP ".....XXX...X..X." + BITMAP "..X...X....XX..X" + BITMAP "..X...X....X...X" + BITMAP "...XXX.XXX.X...X" + BITMAP "...XXX....XXXXX." + BITMAP "..X.....X...X..." + BITMAP ".X.....XX...X..." + BITMAP "..XXXXXX....X..." + + BITMAP "..XXXXXXXX......" + BITMAP "..X.....XXX....." + BITMAP "..X.....XX......" + BITMAP "..X.X....XX....." + BITMAP "..X...X.XX......" + BITMAP "..X.XXX..XX....." + BITMAP "...X...XXXX....." + BITMAP "....XXXXXXXX...." + BITMAP ".....XXXXXXX...." + BITMAP "....XXXXXXXX...." + BITMAP "....XXXXXXXX...." + BITMAP ".....XXXXXXX...." + BITMAP ".....XXXXXX....." + BITMAP "......XXXXX....." + BITMAP ".....XXXXXX....." + BITMAP "....XXXXXXX....." + + BITMAP "..XXXXXXXX......" + BITMAP "..XXXXXXXXX....." + BITMAP "..XXXXXXXX......" + BITMAP "..XXXXXXXXX....." + BITMAP "..XXXXXXXX......" + BITMAP "..XXXXXXXXX....." + BITMAP "...XXXXX..X....." + BITMAP "....XXX....X...." + BITMAP ".....X.....X...." + BITMAP "....X...X..X...." + BITMAP "....X...X..X...." + BITMAP ".....XXX...X...." + BITMAP ".....X....X....." + BITMAP "......XX..X....." + BITMAP ".....X....X....." + BITMAP "....X.....X....." + + BITMAP "...XXXXXXXXX...." + BITMAP "....XXXXXXX....." + BITMAP "...XXXXXXXXX...." + BITMAP "...XXXXXXXXXXXX." + BITMAP "....XXXXXXXXXXXX" + BITMAP "....XXXXXXXXXXXX" + BITMAP ".....X...XXXXXX." + BITMAP "...XXXXXXXXXX..." + BITMAP ".XXXXXXXXXXX...." + BITMAP "XXXXX.XXXX......" + BITMAP "XXXXXXXXXXX....." + BITMAP ".XXX.XXXXXXXX..." + BITMAP "....XXXX.XXXXX.." + BITMAP "...XXXXX.XXXXXX." + BITMAP "..XXXXXX..XXXX.." + BITMAP ".XXXXXXX........" + + BITMAP "...XXXXXXXXX...." + BITMAP "....XXXXXXX....." + BITMAP "...XXXXXXXXX...." + BITMAP "...XXXXXXXXXXXX." + BITMAP "....XXXXXXXX...X" + BITMAP "....XXXXXXXX...X" + BITMAP ".....XXXXXX..XX." + BITMAP "...X..XXX...X..." + BITMAP ".XX..X....XX...." + BITMAP "X...X.XXXX......" + BITMAP "X...XX....X....." + BITMAP ".XXX.X.XX..XX..." + BITMAP "....X..X.X...X.." + BITMAP "...XX..X.X....X." + BITMAP "..X....X..XXXX.." + BITMAP ".X.....X........" + + BITMAP "....XXXXXXXXX..." + BITMAP ".....XXXXXXX...." + BITMAP "....XXXXXXXXX..." + BITMAP ".XXXXXXXXXXXX..." + BITMAP "XXXXXXXXXXXX...." + BITMAP "XXXXXXXXXXXX...." + BITMAP ".XXXXXX...XX...." + BITMAP "...XXXXXXXXXX..." + BITMAP "....XXXXXXXXXXX." + BITMAP "......XXXX.XXXXX" + BITMAP ".....XXXXXXXXXXX" + BITMAP "...XXXXXXXX.XXX." + BITMAP "..XXXXX.XXXX...." + BITMAP ".XXXXX..XXXXX..." + BITMAP "..XXX...XXXXXX.." + BITMAP "........XXXXXXX." + + BITMAP "....XXXXXXXXX..." + BITMAP ".....XXXXXXX...." + BITMAP "....XXXXXXXXX..." + BITMAP ".XXXXXXXXXXXX..." + BITMAP "X...XXXXXXXX...." + BITMAP "X...XXXXXXXX...." + BITMAP ".XX..XXXXXXX...." + BITMAP "...X...XXX..X..." + BITMAP "....XX....X..XX." + BITMAP "......XXXX.X...X" + BITMAP ".....X....XX...X" + BITMAP "...XX..XX.X.XXX." + BITMAP "..X...X.X..X...." + BITMAP ".X...X..X..XX..." + BITMAP "..XXX...X....X.." + BITMAP "........X.....X." + + BITMAP "..X..X.XX......." + BITMAP ".X.X..XXX......." + BITMAP ".X.X..XXX......." + BITMAP ".X..X.XX........" + BITMAP ".XX....XX......." + BITMAP "XX....X.XX......" + BITMAP "XXX..X..XX....X." + BITMAP "...XXX..XX...X.X" + BITMAP "...X...XX....X.X" + BITMAP "..X....XX...X.XX" + BITMAP ".X....XX....X.XX" + BITMAP ".X...XX.XX.X..XX" + BITMAP ".X...XXX..XX.XX." + BITMAP ".X.........X.XX." + BITMAP "..X..........XX." + BITMAP "...XXXXXXXXXXX.." + + BITMAP "..XXXXXXX......." + BITMAP ".XX.XX.XX......." + BITMAP ".XX.XX.XX......." + BITMAP ".XXXXXXX........" + BITMAP ".XXXXXXXX......." + BITMAP "X.XXXXXXXX......" + BITMAP ".XXXXXXXXX....X." + BITMAP "...XXXXXXX...XXX" + BITMAP "...XXXXXX....XXX" + BITMAP "..XXXXXXX...XXXX" + BITMAP ".XXXXXXX....XXXX" + BITMAP ".XXXXXX.XX.XXXXX" + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP "..XXXXXXXXXXXXX." + BITMAP "...XXXXXXXXXXX.." + + BITMAP "....XX.XX......." + BITMAP "...X..X.XX......" + BITMAP "..X.X..XXX......" + BITMAP "..X.X..XXX......" + BITMAP "..X..X.XX......." + BITMAP "...X....XX......" + BITMAP ".XX....X.XX....." + BITMAP "XXX...X..XX....." + BITMAP "XXXXXXX..XX..X.." + BITMAP ".XXX....XX..X.X." + BITMAP "..X....XXX.X.XX." + BITMAP "..X...XX.X.X.XX." + BITMAP "..X...XX.XX.XX.." + BITMAP "..X.........XX.." + BITMAP "...X.....X..XX.." + BITMAP "....XXXXXXXXX..." + + BITMAP "....XX.XX......." + BITMAP "...XXXXXXX......" + BITMAP "..XX.XX.XX......" + BITMAP "..XX.XX.XX......" + BITMAP "..XXXXXXX......." + BITMAP "...XXXXXXX......" + BITMAP ".XXXXXXXXXX....." + BITMAP "X.XXXXXXXXX....." + BITMAP "X..XXXXXXXX..X.." + BITMAP ".XXXXXXXXX..XXX." + BITMAP "..XXXXXXXX.XXXX." + BITMAP "..XXXXXXXX.XXXX." + BITMAP "..XXXXXXXXXXXX.." + BITMAP "..XXXXXXXXXXXX.." + BITMAP "...XXXXXXXXXXX.." + BITMAP "....XXXXXXXXX..." + + BITMAP ".......XX.X..X.." + BITMAP ".......XXX..X.X." + BITMAP ".......XXX..X.X." + BITMAP "........XX.X..X." + BITMAP ".......XX....XX." + BITMAP "......XX.X....XX" + BITMAP ".X....XX..X..XXX" + BITMAP "X.X...XX..XXX..." + BITMAP "X.X....XX...X..." + BITMAP "XX.X...XX....X.." + BITMAP "XX.X....XX....X." + BITMAP "XX..X.XX.XX...X." + BITMAP ".XX.XX..XXX...X." + BITMAP ".XX.X.........X." + BITMAP ".XX..........X.." + BITMAP "..XXXXXXXXXXX..." + + BITMAP ".......XXXXXXX.." + BITMAP ".......XX.XX.XX." + BITMAP ".......XX.XX.XX." + BITMAP "........XXXXXXX." + BITMAP ".......XXXXXXXX." + BITMAP "......XXXXXXXX.X" + BITMAP ".X....XXXXXXXXX." + BITMAP "XXX...XXXXXXX..." + BITMAP "XXX....XXXXXX..." + BITMAP "XXXX...XXXXXXX.." + BITMAP "XXXX....XXXXXXX." + BITMAP "XXXXX.XX.XXXXXX." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXXXXXXXXXXXXX." + BITMAP ".XXXXXXXXXXXXX.." + BITMAP "..XXXXXXXXXXX..." + + BITMAP ".......XX.XX...." + BITMAP "......XX.X..X..." + BITMAP "......XXX..X.X.." + BITMAP "......XXX..X.X.." + BITMAP ".......XX.X..X.." + BITMAP "......XX....X..." + BITMAP ".....XX.X....X.." + BITMAP ".....XX..X...XXX" + BITMAP "..X..XX..XXXXXXX" + BITMAP ".X.X..XX....X..." + BITMAP ".XX.X.XXX....X.." + BITMAP ".XX.XX..XX...X.." + BITMAP "..XX.X..XX...X.." + BITMAP "..XX.........X.." + BITMAP "..XX..X.....X..." + BITMAP "...XXXXXXXXX...." + + BITMAP ".......XX.XX...." + BITMAP "......XXXXXXX..." + BITMAP "......XX.XX.XX.." + BITMAP "......XX.XX.XX.." + BITMAP ".......XXXXXXX.." + BITMAP "......XXXXXXX..." + BITMAP ".....XXXXXXXXX.." + BITMAP ".....XXXXXXXXX.X" + BITMAP "..X..XXXXXXXX..X" + BITMAP ".XXX..XXXXXXX..." + BITMAP ".XXXX.XXXXXXXX.." + BITMAP ".XXXXXXXXXXXXX.." + BITMAP "..XXXXXXXXXXXX.." + BITMAP "..XXXXXXXXXXXX.." + BITMAP "..XXXXXXXXXXX..." + BITMAP "...XXXXXXXXX...." + +sprites_color: + DATA BYTE $06,$06,$06,$06,$06,$06,$06,$06 + DATA BYTE $06,$06,$06,$06,$06,$06,$06,$06 + DATA BYTE $49,$49,$49,$49,$49,$49,$49,$49 + DATA BYTE $49,$49,$49,$49,$49,$49,$49,$49 + DATA BYTE $0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d + DATA BYTE $0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d + DATA BYTE $4e,$4e,$4e,$4e,$4e,$4e,$4e,$4e + DATA BYTE $4e,$4e,$4e,$4e,$4e,$4e,$4e,$4e + +start_song: PROCEDURE + tick_note = 8 + song_note = 47 + END + +play_song: PROCEDURE + tick_note = tick_note + 1. + IF tick_note = 16. THEN + tick_note = 0. + song_note = song_note + 1. + IF song_note = 48. THEN song_note = 0. + note = song_notes(song_note) + SOUND 5, #note_freq(note - 1) + END IF + SOUND 5, , volume_effect(tick_note) + END + +sound_off: PROCEDURE + SOUND 5,,0 + SOUND 6,,0 + SOUND 7,,0 + SOUND 9,,$38 + END + +volume_effect: + DATA BYTE 11,12,13,12,12,11,11,10 + DATA BYTE 10,9,9,10,10,9,9,8 + +song_notes: + DATA BYTE 1,2,3,4,5,4,3,2 + DATA BYTE 1,2,3,4,5,4,3,2 + DATA BYTE 6,4,7,8,9,8,7,4 + DATA BYTE 6,4,7,8,9,8,7,4 + DATA BYTE 3,12,8,10,11,10,8,12 + DATA BYTE 6,4,7,8,9,8,7,4 + +#note_freq: + DATA $01AC + DATA $0153 + DATA $011D + DATA $00FE + DATA $00F0 + DATA $0140 + DATA $00D6 + DATA $00BE + DATA $00B4 + DATA $00AA + DATA $00A0 + DATA $00E2 From 782951db9111acd4ff1c347ccab2abf3bf96d4ff Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 18:03:54 -0600 Subject: [PATCH 099/155] MSX2: Updated README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 80b519c..84d73e1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CVBasic compiler v0.9.1 +# CVBasic compiler v0.9.2 *(c) Copyright 2024-2025 Óscar Toledo Gutiérrez* *https://nanochess.org/* @@ -95,6 +95,7 @@ The following files compose the compiler: examples/vgm.bas VGM audio player for SN76489. examples/vgm_ay.bas VGM audio player for AY-3-8910. examples/viboritas.bas Game example. + examples/viboritas_msx2.bas Game example (MSX2) examples/viboritas_nes.bas Game example (NES/Famicom) examples/viboritas_sms.bas Game example (Sega Master System) examples/vramcopy.bas VRAM copy example. From e8bdae16d8e9d771346c8cab6caef4db36cac2e4 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 18:21:16 -0600 Subject: [PATCH 100/155] MSX2: Added comments on OR'ed sprites --- examples/viboritas_msx2.bas | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/viboritas_msx2.bas b/examples/viboritas_msx2.bas index b7d4696..b37e591 100644 --- a/examples/viboritas_msx2.bas +++ b/examples/viboritas_msx2.bas @@ -853,6 +853,17 @@ game_sprites: BITMAP "..XXXXXXXXXXX..." BITMAP "...XXXXXXXXX...." + ' + ' This is the color table used for sprites on the screen. + ' + ' The player is composed by colors 6 and 9. The color 9 has the bit 6 set + ' so it is OR'ed with the sprite below, and when both pixels are set it + ' creates color 15 (6 OR 9 = 15) + ' + ' The snakes are composed by colors 13 and 14. The color 14 has the bit 6 set + ' so it is OR'ed with the sprite below, and when both pixels are set it + ' creates color 15 (13 OR 14 = 15) + ' sprites_color: DATA BYTE $06,$06,$06,$06,$06,$06,$06,$06 DATA BYTE $06,$06,$06,$06,$06,$06,$06,$06 From 2fd45a1190e292b6cc6d12dddd17ab5b22d3b8f2 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 10 Feb 2026 23:02:19 -0600 Subject: [PATCH 101/155] Added new example cube.bas --- contrib/cube.bas | 170 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 contrib/cube.bas diff --git a/contrib/cube.bas b/contrib/cube.bas new file mode 100644 index 0000000..8e4e6cc --- /dev/null +++ b/contrib/cube.bas @@ -0,0 +1,170 @@ +' -------------------------------------------------- +' Vector Cube Demo - XOR rotate Engine (CVBasic-clean) +' -------------------------------------------------- +' Matthew Eggleston. Feb/10/2026 + +MODE 1 + +' -------------------------------------------------- +' Animation variables +' -------------------------------------------------- +#ANGLE = 0 +#SIN_VAL = 0 + +CUBE_SIZE = 24 +DEPTH = 12 +CENTER_X = 80 +CENTER_Y = 88 ' <-- moved further UP + +' -------------------------------------------------- +' Main loop +' -------------------------------------------------- +WHILE 1 + GOSUB DrawCube + + WAIT + WAIT + + GOSUB DrawCube + + #ANGLE = #ANGLE + 6 + IF #ANGLE >= 360 THEN #ANGLE = 0 + + FOR I = 1 TO 16 + NEXT I +WEND + +' -------------------------------------------------- +' Draw cube routine +' -------------------------------------------------- +DrawCube: PROCEDURE + +GOSUB CalcSIN +#ROT = #SIN_VAL + +' Front square +FX1 = CENTER_X - CUBE_SIZE +FY1 = CENTER_Y - CUBE_SIZE +FX2 = CENTER_X + CUBE_SIZE +FY2 = CENTER_Y - CUBE_SIZE +FX3 = CENTER_X + CUBE_SIZE +FY3 = CENTER_Y + CUBE_SIZE +FX4 = CENTER_X - CUBE_SIZE +FY4 = CENTER_Y + CUBE_SIZE + +' Rotate front square +DX = #ROT / 3 +DY = #ROT / 4 +FX1 = FX1 + DX: FY1 = FY1 - DY +FX2 = FX2 + DY: FY2 = FY2 + DX +FX3 = FX3 - DX: FY3 = FY3 + DY +FX4 = FX4 - DY: FY4 = FY4 - DX + +' Back square +BX1 = FX1 + DEPTH +BY1 = FY1 - DEPTH +BX2 = FX2 + DEPTH +BY2 = FY2 - DEPTH +BX3 = FX3 + DEPTH +BY3 = FY3 - DEPTH +BX4 = FX4 + DEPTH +BY4 = FY4 - DEPTH + +' Draw edges +AX = FX1: AY = FY1: BX = FX2: BY = FY2: GOSUB Draw_Line_Sub +AX = FX2: AY = FY2: BX = FX3: BY = FY3: GOSUB Draw_Line_Sub +AX = FX3: AY = FY3: BX = FX4: BY = FY4: GOSUB Draw_Line_Sub +AX = FX4: AY = FY4: BX = FX1: BY = FY1: GOSUB Draw_Line_Sub + +AX = BX1: AY = BY1: BX = BX2: BY = BY2: GOSUB Draw_Line_Sub +AX = BX2: AY = BY2: BX = BX3: BY = BY3: GOSUB Draw_Line_Sub +AX = BX3: AY = BY3: BX = BX4: BY = BY4: GOSUB Draw_Line_Sub +AX = BX4: AY = BY4: BX = BX1: BY = BY1: GOSUB Draw_Line_Sub + +AX = FX1: AY = FY1: BX = BX1: BY = BY1: GOSUB Draw_Line_Sub +AX = FX2: AY = FY2: BX = BX2: BY = BY2: GOSUB Draw_Line_Sub +AX = FX3: AY = FY3: BX = BX3: BY = BY3: GOSUB Draw_Line_Sub +AX = FX4: AY = FY4: BX = BX4: BY = BY4: GOSUB Draw_Line_Sub + +RETURN +END + +' -------------------------------------------------- +' Integer SIN approximation +' -------------------------------------------------- +CalcSIN: PROCEDURE +#A = #ANGLE +IF #A < 90 THEN + #SIN_VAL = #A +ELSEIF #A < 180 THEN + #SIN_VAL = 180 - #A +ELSEIF #A < 270 THEN + #SIN_VAL = -(#A - 180) +ELSE + #SIN_VAL = -(360 - #A) +END IF +RETURN +END + +' -------------------------------------------------- +' Bresenham line (XOR) +' -------------------------------------------------- +SIGNED #ERR + +Draw_Line_Sub: PROCEDURE +IF BX < AX THEN + #DX = AX - BX : SX = -1 +ELSE + #DX = BX - AX : SX = 1 +END IF + +IF BY < AY THEN + #DY = AY - BY : SY = -1 +ELSE + #DY = BY - AY : SY = 1 +END IF + +IF #DX > #DY THEN + #ERR = 2 * #DY - #DX + WHILE 1 + GOSUB PSET_Sub + IF AX = BX THEN RETURN + IF #ERR < 0 THEN + #ERR = #ERR + 2 * #DY + ELSE + #ERR = #ERR + 2 * (#DY - #DX) + AY = AY + SY + END IF + AX = AX + SX + WEND +ELSE + #ERR = 2 * #DX - #DY + WHILE 1 + GOSUB PSET_Sub + IF AY = BY THEN RETURN + IF #ERR < 0 THEN + #ERR = #ERR + 2 * #DX + ELSE + #ERR = #ERR + 2 * (#DX - #DY) + AX = AX + SX + END IF + AY = AY + SY + WEND +END IF +RETURN +END + +' -------------------------------------------------- +' XOR pixel plot +' -------------------------------------------------- +PSET_Sub: PROCEDURE +#C = ((AX) AND $F8) + ((192-AY)/8*256) + ((192-AY) AND 7) +VPOKE #C, VPEEK(#C) XOR BIT_TABLE(AX AND 7) +RETURN +END + +' -------------------------------------------------- +' Bit table for XOR pixels +' -------------------------------------------------- +BIT_TABLE: +DATA BYTE $80,$40,$20,$10,$08,$04,$02,$01 From 9d07e2b9d205cabe06f267fc28cd0c8e18d76735 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 12 Feb 2026 20:23:05 +0100 Subject: [PATCH 102/155] Add MSX2 target to check rule in Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index bf4991a..4a4d37b 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ check: cvbasic @./$< examples/viboritas.bas /tmp/viboritas.asm @./$< --sms examples/viboritas_sms.bas /tmp/viboritas_sms.asm @./$< --nes examples/viboritas_nes.bas /tmp/viboritas_nes.asm + @./$< --msx2 examples/viboritas_msx2.bas /tmp/viboritas_msx2.asm clean: @rm cvbasic cvbasic.o node.o driver.o cpuz80.o cpu6502.o cpu9900.o From 24b8e0919a49ec10fb307bb2f8c4c38170301959 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 12 Feb 2026 20:26:32 +0100 Subject: [PATCH 103/155] Fix typo in error message for expression syntax --- cvbasic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic.c b/cvbasic.c index c3457bf..6d32fb3 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -1894,7 +1894,7 @@ struct node *evaluate_level_7(int *type) *type = TYPE_16; return node_create(N_NUM16, temp & 0xffff, NULL, NULL); } - emit_error("bad syntax por expression"); + emit_error("bad syntax for expression"); *type = TYPE_16; return node_create(N_NUM16, 0, NULL, NULL); } From 91cb3854bcc6b1aea995e781f578d9b063ce8d14 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 16 Feb 2026 22:27:11 -0600 Subject: [PATCH 104/155] NES: Solved bug in array memory allocation, and crash of PPU buffer with variable memory --- cvbasic.c | 11 ++++++++--- cvbasic_nes_prologue.asm | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 6d32fb3..002c5ce 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.2 Feb/09/2026" +#define VERSION "v0.9.2 Feb/16/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -6566,8 +6566,13 @@ int process_variables(void) size = 1; size *= label->length; if (target == CPU_6502) { - if (address < 0x0200 && address + size > 0x0140) - address = 0x0200; + if (machine == NES) { + if (address < 0x0300 && address + size > 0x0140) + address = 0x0300; + } else { + if (address < 0x0200 && address + size > 0x0140) + address = 0x0200; + } sprintf(temp, ARRAY_PREFIX "%s:\tequ $%04x", label->name, address); address += size; fprintf(output, "%s\n", temp); diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 0f4b778..a63c84e 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -11,6 +11,7 @@ ; Added music player. ; Revision date: Aug/25/2025. Added support for 256K and 512K ROM. ; Revision date: Aug/26/2025. Added support for CHRRAM selection. + ; Revision date: Feb/16/2026. Relocated PPUBUF. ; CPU 6502 @@ -86,7 +87,8 @@ music_mode: EQU $4e ENDIF SPRITE_PAGE: EQU $02 -PPUBUF: EQU $0100 +PPUBUF: EQU $0140 +PPUSIZE: EQU $40 BANKSEL: EQU $C000 FORG $0000 @@ -150,7 +152,7 @@ WRTVRM: INX INX STX ppu_pointer - CPX #$40 + CPX #PPUSIZE BCS .1 RTS .1: @@ -195,7 +197,7 @@ LDIRVM: CLC ADC #5 STA ppu_pointer - CMP #$40 + CMP #PPUSIZE BCS .1 RTS .1: @@ -967,7 +969,11 @@ print_string: BCC .1 INC cursor+1 .1: + CPX #PPUSIZE-5 + BCS .3 RTS +.3: + JMP wait print_number: LDX #0 From 86cd4a60a66e26325e35f25fa85dd319db95b1bf Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 16 Feb 2026 22:30:59 -0600 Subject: [PATCH 105/155] Updated credits --- README.md | 2 +- cvbasic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 84d73e1..22ea581 100644 --- a/README.md +++ b/README.md @@ -327,4 +327,4 @@ All the games in the book will compile for **all** the platforms, except Sega Ma ### Acknowledgments -Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, Atarius Maximus, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. +Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, Atarius Maximus, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, Revontuli, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. diff --git a/cvbasic.c b/cvbasic.c index 002c5ce..7fc329e 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -6654,7 +6654,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " successful, or non-zero otherwise.\n\n"); fprintf(stderr, "Many thanks to acadiel, Albert, abeker, aotta, artrag, atari2600land,\n"); fprintf(stderr, "carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan,\n"); - fprintf(stderr, "Kamshaft, Kiwi, MADrigal, pixelboy, SiRioKD, Tarzilla,\n"); + fprintf(stderr, "Kamshaft, Kiwi, MADrigal, pixelboy, Revontuli, SiRioKD, Tarzilla,\n"); fprintf(stderr, "Tony Cruise, tursilion, visrealm, wavemotion, and youki.\n"); fprintf(stderr, "\n"); exit(1); From a30c4314babecea826b9acd37b4ecdabbe19d1a4 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 17 Feb 2026 17:39:12 -0600 Subject: [PATCH 106/155] MSX2/SMS: Added PALETTE DEFAULT --- cvbasic.c | 5 +++++ cvbasic_prologue.asm | 37 ++++++++++++++++++++++++++++--------- manual.txt | 5 +++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 7fc329e..251a0da 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5014,6 +5014,11 @@ void compile_statement(int check_for_else) } get_lex(); } + } else if (lex == C_NAME && strcmp(name, "DEFAULT") == 0) { + get_lex(); + if (machine != MSX2 && machine != SMS) + emit_error("PALETTE DEFAULT is only available in MSX2/SMS"); + generic_call("palette_default"); } else { type = evaluate_expression(1, TYPE_8, 0); if (machine == SMS) { diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 4c6f93b..12a7872 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1248,6 +1248,8 @@ font_bitmaps: endif if MSX&2 +palette_default: + ld hl,msx2_default_palette palette_load: push hl di @@ -1260,6 +1262,10 @@ palette_load: ei ret +msx2_default_palette: + dw $000,$000,$611,$733,$117,$327,$151,$627 + dw $171,$373,$661,$664,$411,$265,$555,$777 + define_sprite_color: ex de,hl ld l,a @@ -1302,6 +1308,16 @@ update_sprite2: ldir ret + ; + ; Register that must be set for V9938 (MSX2) because larger VRAM: + ; Reg. 2 = 0 A16 A15 A14 A13 A12 A11 A10 Pattern name table. + ; Reg. 3 = A13 1 1 1 1 1 1 1 Color table (reg. D) + ; Reg. 10= 0 0 0 0 0 A16 A15 A14 Color table high bits. + ; Reg. 4 = 0 0 A16 A15 A14 A13 1 1 Bitmap table (reg. E) + ; Reg. 5 = A14 A13 A12 A11 A10 A9 A8 A7 Sprite attribute table... + ; Reg. 11= 0 0 0 0 0 0 A16 A15 ...and high bits. + ; Reg. 6 = 0 0 A16 A15 A14 A13 A12 A11 Sprite pattern generator + ; mode_4: ld hl,mode res 3,(hl) @@ -1309,9 +1325,11 @@ mode_4: ld bc,$0400 ; Normal mode but with enhanced sprites enabled. ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode + ld bc,$000a ; Reg. 10 + call WRTVDP ld bc,$8405 ; $4200 for sprite attribute table... call WRTVDP ; ...so sprite colors appear at $4000-$41ff. - ld bc,$000b + ld bc,$000b ; Reg. 11 call WRTVDP ld hl,($0004) inc h @@ -1330,6 +1348,8 @@ mode_4: endif if SMS +palette_default: + ld hl,sms_default_palette palette_load: push hl di @@ -1342,6 +1362,11 @@ palette_load: ei ret + ; TMS9118-alike palette +sms_default_palette: + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + mode_4: di ld bc,$0400 @@ -1394,15 +1419,9 @@ mode_4: ld (hl),$e0 ldir ei - ld hl,.3 - call palette_load + call palette_default jp ENASCR - ; TMS9118-alike palette -.3: - db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f - db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f - else vdp_generic_mode: call nmi_off @@ -1415,7 +1434,7 @@ vdp_generic_mode: ld c,$03 ; for color table. call WRTVDP ld b,e - ld c,$04 ; for bitmap table. + ld c,$04 ; for bitmap table call WRTVDP ld bc,$3605 ; $1b00 for sprite attribute table. call WRTVDP diff --git a/manual.txt b/manual.txt index 79dda1f..895dbb5 100644 --- a/manual.txt +++ b/manual.txt @@ -923,6 +923,7 @@ The following statements are available: PALETTE register, color PALETTE LOAD array_data_byte PALETTE LOAD VARPTR array_data_byte(0) + PALETTE DEFAULT For MSX2: @@ -933,6 +934,8 @@ The following statements are available: Alternatively, you can load a full 16 entries palette using PALETTE LOAD. The array should be specified with DATA. + You can restore the palette to TMS9118 colors by using PALETTE DEFAULT. + For the Sega Master System: Sets a single palette register (0-31) to the color (0-63). Color bits are @@ -945,6 +948,8 @@ The following statements are available: Alternatively, you can load a full 32 entries palette using PALETTE LOAD. The array should be specified with DATA BYTE. + You can restore the palette to TMS9118 colors by using PALETTE DEFAULT. + For the NES/Famicom: Registers From fc2c83def87a609fad482252e95ea130775dedc0 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 17 Feb 2026 17:47:01 -0600 Subject: [PATCH 107/155] Updated version number --- README.md | 2 +- cvbasic.c | 2 +- manual.txt | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 22ea581..43ca04e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CVBasic compiler v0.9.2 +# CVBasic compiler v0.9.1 *(c) Copyright 2024-2025 Óscar Toledo Gutiérrez* *https://nanochess.org/* diff --git a/cvbasic.c b/cvbasic.c index 251a0da..816e869 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.2 Feb/16/2026" +#define VERSION "v0.9.1 Feb/17/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" diff --git a/manual.txt b/manual.txt index 895dbb5..f82baf5 100644 --- a/manual.txt +++ b/manual.txt @@ -22,14 +22,18 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.2 Feb/09/2026 o Added support for MSX2 using --msx2 +v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. o MSX2: It supports MODE 4, extended sprites, and DEFINE SPRITE COLOR. + o MSX2/SMS: Added PALETTE DEFAULT. o Added note about support of Blue and Purple buttons (Super Action Controllers for Colecovision) o Added support for spinners and roller controller using CONT1.SPINNER and CONT2.SPINNER (Colecovision) + o NES: Solved important bug where VPOKE/PRINT would + corrupt some variables, and arrays could be + allocated to a wrong address. v0.9.0 Aug/26/2025 o Added support for NES/Famicom using --nes o MSX: Added support for Konami mapper using -konami From d271f1f8cd994279aec74e939743e4b93250ea78 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 17 Feb 2026 18:02:35 -0600 Subject: [PATCH 108/155] MSX2: Optimization of VDP data writing --- README.md | 2 +- cvbasic_prologue.asm | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43ca04e..df1024d 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ Untested: * DEFINE VRAM READ is only tested for Colecovision/MSX, please test in your real hardware to check that the timing is right. -MSX controller support only handles the two joysticks and keyboard arrows (plus Space and M for buttons). The keys 0-9, Backspace and Return emulate the Colecovision keypad (CONT1.KEY only). +MSX/MSX2 controller support only handles the two joysticks and keyboard arrows (plus Space and M for buttons). The keys 0-9, Backspace and Return emulate the Colecovision keypad (CONT1.KEY only). The Sega SG1000 and Sega Master System doesn't have any keypad, so CONT1.KEY and CONT2.KEY aren't operative, but the support includes compatibility with Sega SC3000 computer, and the keyboard can be used as first controller (code contributed by SiRioKD) and for CONT1.KEY using the keys 0-9, Delete and CR. diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 12a7872..24b61cb 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -502,6 +502,9 @@ LDIRVM: inc a ld c,VDP .1: + if MSX&2 + otir ; 23 cycles per byte. + else if SORD+SMS nop endif @@ -509,8 +512,9 @@ LDIRVM: nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. nop endif - outi - jp nz,.1 + outi ; 18 + jp nz,.1 ; 11 + endif dec a jp nz,.1 ret @@ -1257,8 +1261,7 @@ palette_load: call WRTVDP pop hl ld bc,32*256+VDP+2 - outi - jp nz,$-2 + otir ei ret @@ -1710,6 +1713,13 @@ nmi_handler: call SETWRT ld hl,sprites .7: + if MSX&2 + outi + outi + outi + outi + jp nz,.7 + else if PV2000 ld a,(hl) ld (VDP),a @@ -1723,12 +1733,13 @@ nmi_handler: outi jp nz,.7 endif + endif jr .5 .4: bit 4,(hl) ld hl,$1b00 - jr nz,.10 ; No flicker sprites in MSX2 mode. + jr nz,.10 ; No flicker sprites in MSX2 (MODE 4) call SETWRT ld a,(flicker) add a,$04 From 41c74cbc62cb6b58aed9381789aaeaae1683ed93 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 17 Feb 2026 18:37:35 -0600 Subject: [PATCH 109/155] MSX2: Added support for BORDER flags and SCROLL --- cvbasic.c | 42 +++++++++++++++++++++++++++++++++++++----- manual.txt | 12 ++++++++++-- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 816e869..91368fb 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -4915,8 +4915,8 @@ void compile_statement(int check_for_else) if (lex == C_COMMA) { get_lex(); type = evaluate_expression(1, TYPE_8, 0); - if (machine != SMS && machine != NES) { - emit_error("The 2nd BORDER argument only available on Sega Master System or NES/Famicom"); + if (machine != SMS && machine != NES && machine != MSX2) { + emit_error("The 2nd BORDER argument only available for MSX2/SMS/NES/Famicom"); } else if (machine == SMS) { cpuz80_1op("AND", "$07"); cpuz80_1op("OR", "$20"); @@ -4928,6 +4928,13 @@ void compile_statement(int check_for_else) generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); generic_interrupt_enable(); + } else if (machine == MSX2) { + cpuz80_1op("AND", "$03"); + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "25"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + generic_interrupt_enable(); } else if (machine == NES) { cpu6502_1op("ASL", "A"); cpu6502_1op("AND", "#$06"); @@ -4940,12 +4947,12 @@ void compile_statement(int check_for_else) cpu6502_1op("STA", "ppu_mask"); } } - } else if (strcmp(name, "SCROLL") == 0) { /* Sega Master System / NES/Famicom */ + } else if (strcmp(name, "SCROLL") == 0) { /* Sega Master System / MSX2 / NES/Famicom */ int type; get_lex(); - if (machine != SMS && machine != NES) - emit_error("SCROLL is only available on Sega Master System or NES/Famicom"); + if (machine != SMS && machine != NES && machine != MSX2) + emit_error("SCROLL is only available for MSX2/SMS/NES/Famicom"); if (lex != C_COMMA) { if (machine == SMS) { type = evaluate_expression(1, TYPE_8, 0); @@ -4954,6 +4961,24 @@ void compile_statement(int check_for_else) generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); generic_interrupt_enable(); + } else if (machine == MSX2) { + type = evaluate_expression(1, TYPE_16, 0); + cpuz80_2op("LD", "A", "L"); + cpuz80_1op("AND", "7"); + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "27"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + cpuz80_2op("LD", "A", "L"); + cpuz80_1op("SRL", "H"); + cpuz80_noop("RRA"); + cpuz80_noop("RRA"); + cpuz80_noop("RRA"); + cpuz80_1op("AND", "63"); + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "26"); + cpuz80_1op("CALL", "WRTVDP"); + generic_interrupt_enable(); } else { type = evaluate_expression(1, TYPE_16, 0); cpu6502_1op("STA", "scroll_x"); @@ -4969,6 +4994,13 @@ void compile_statement(int check_for_else) generic_interrupt_disable(); cpuz80_1op("CALL", "WRTVDP"); generic_interrupt_enable(); + } else if (machine == MSX2) { + type = evaluate_expression(1, TYPE_8, 0); + cpuz80_2op("LD", "B", "A"); + cpuz80_2op("LD", "C", "23"); + generic_interrupt_disable(); + cpuz80_1op("CALL", "WRTVDP"); + generic_interrupt_enable(); } else { type = evaluate_expression(1, TYPE_16, 0); cpu6502_1op("STA", "scroll_y"); diff --git a/manual.txt b/manual.txt index f82baf5..0fadc0b 100644 --- a/manual.txt +++ b/manual.txt @@ -24,8 +24,8 @@ All trademarks are property of their respective owners. v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. - o MSX2: It supports MODE 4, extended sprites, and - DEFINE SPRITE COLOR. + o MSX2: It supports MODE 4, extended sprites, + DEFINE SPRITE COLOR, BORDER, and SCROLL. o MSX2/SMS: Added PALETTE DEFAULT. o Added note about support of Blue and Purple buttons (Super Action Controllers for Colecovision) @@ -846,6 +846,8 @@ The following statements are available: borders, overlapping sprites in different depths, or using the SPRITE 0,$d0,0,0,0 trick. + Sprite flicker doesn't work when using MODE 4 in MSX2. + OUT port,data It outputs "data" in the hardware port "port". Not available in 6502 targets. @@ -918,12 +920,18 @@ The following statements are available: bit 0 = Background clipping (0 = hide left 8-pixel column, 1 = no clipping) bit 1 = Sprite clipping (0 = hide left 8-pixel column, 1 = no clipping) + The flags argument for MSX2+ (not MSX2) + bit 0 = Extend screen internal width to 64 characters. + bit 1 = Hide column 0. + SCROLL x, y Sets the pixel scrolling for Sega Master System background. Sets the pixel scrolling for NES/Famicom background. + Sets the pixel scrolling for MSX2 (the x-coordinate only in MSX2+) + PALETTE register, color PALETTE LOAD array_data_byte PALETTE LOAD VARPTR array_data_byte(0) From abc5a7fdece3387fa5ef586e3de4dbf286b3e477 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 17 Feb 2026 19:09:55 -0600 Subject: [PATCH 110/155] Z80: PRINT now uses JR to save space --- cpuz80.c | 3 ++- cvbasic.c | 5 ++++- driver.c | 17 +++++++++++++++++ driver.h | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cpuz80.c b/cpuz80.c index e94c797..618e823 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -165,7 +165,8 @@ void cpuz80_1op(char *mnemonic, char *operand) z80_hl_content[0] = '\0'; } } else if (strcmp(mnemonic, "CALL") == 0 || - strcmp(mnemonic, "JP") == 0) { + strcmp(mnemonic, "JP") == 0 || + strcmp(mnemonic, "JR") == 0) { z80_a_content[0] = '\0'; z80_hl_content[0] = '\0'; z80_flag_z_valid = 0; diff --git a/cvbasic.c b/cvbasic.c index 91368fb..be13429 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3914,7 +3914,10 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "A", temp); generic_call("print_string"); sprintf(temp, INTERNAL_PREFIX "%d", label2); - generic_jump(temp); + if (name_size < 126) + generic_jump_short(temp); + else + generic_jump(temp); sprintf(temp, INTERNAL_PREFIX "%d", label); generic_label(temp); generic_dump(); diff --git a/driver.c b/driver.c index 6b4bf59..c61ab04 100644 --- a/driver.c +++ b/driver.c @@ -116,6 +116,23 @@ void generic_jump(char *label) cpuz80_1op("JP", label); } +/* + ** Jump + */ +void generic_jump_short(char *label) +{ + if (target == CPU_6502) + cpu6502_1op("JMP", label); + if (target == CPU_9900) { + char temp[256]; + + sprintf(temp, "@%s", label); + cpu9900_1op("b", temp); + } + if (target == CPU_Z80) + cpuz80_1op("JR", label); +} + /* ** Jump if zero */ diff --git a/driver.h b/driver.h index 54a3ae2..4d16252 100644 --- a/driver.h +++ b/driver.h @@ -13,6 +13,7 @@ extern void generic_label(char *); extern void generic_call(char *); extern void generic_return(void); extern void generic_jump(char *); +extern void generic_jump_short(char *); extern void generic_jump_zero(char *); extern void generic_comparison_8bit(int, int, char *); extern void generic_comparison_16bit(int, int, char *); From 20b0e4b7a31bea9755a8c7a32a26e29d9265259e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 22 Feb 2026 12:12:19 -0600 Subject: [PATCH 111/155] MSX2: Patch for wrong value in R5 --- cvbasic_prologue.asm | 29 +++++++++++++++-------------- manual.txt | 3 ++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 24b61cb..0a0e86d 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1255,11 +1255,9 @@ font_bitmaps: palette_default: ld hl,msx2_default_palette palette_load: - push hl di ld bc,$0010 call WRTVDP - pop hl ld bc,32*256+VDP+2 otir ei @@ -1271,14 +1269,13 @@ msx2_default_palette: define_sprite_color: ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - add hl,hl ; x16 - ld c,l - ld b,h + add a,a ; x2 + add a,a ; x4 + add a,a ; x8 + add a,a ; x16 + ld c,a + ld b,0 + rl b pop af pop hl push af @@ -1317,7 +1314,7 @@ update_sprite2: ; Reg. 3 = A13 1 1 1 1 1 1 1 Color table (reg. D) ; Reg. 10= 0 0 0 0 0 A16 A15 A14 Color table high bits. ; Reg. 4 = 0 0 A16 A15 A14 A13 1 1 Bitmap table (reg. E) - ; Reg. 5 = A14 A13 A12 A11 A10 A9 A8 A7 Sprite attribute table... + ; Reg. 5 = A14 A13 A12 A11 A10 A9 1 1 Sprite attribute table... ; Reg. 11= 0 0 0 0 0 0 A16 A15 ...and high bits. ; Reg. 6 = 0 0 A16 A15 A14 A13 A12 A11 Sprite pattern generator ; @@ -1328,11 +1325,15 @@ mode_4: ld bc,$0400 ; Normal mode but with enhanced sprites enabled. ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode - ld bc,$000a ; Reg. 10 + ld bc,$000a ; Reg. 10 (high bits of color table) call WRTVDP - ld bc,$8405 ; $4200 for sprite attribute table... + ; The value $84 seems logical but it makes colors + ; for sprites 0-7 replicate in sprites 8-15, + ; 16-23, and 24-31. Not described in Yamaha docs, + ; but emulated by OpenMSX and BlueMSX. + ld bc,$8705 ; $4200 for sprite attribute table... call WRTVDP ; ...so sprite colors appear at $4000-$41ff. - ld bc,$000b ; Reg. 11 + ld bc,$000b ; Reg. 11 (high bits of sprite attribute table) call WRTVDP ld hl,($0004) inc h diff --git a/manual.txt b/manual.txt index 0fadc0b..1649fb1 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Feb/10/2026 +Last revision: Feb/17/2026 >>>>>>>>>>>>>> Legal notice @@ -27,6 +27,7 @@ v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports MODE 4, extended sprites, DEFINE SPRITE COLOR, BORDER, and SCROLL. o MSX2/SMS: Added PALETTE DEFAULT. + o MSX2: Access to 64K of VRAM using VPOKE/VPEEK. o Added note about support of Blue and Purple buttons (Super Action Controllers for Colecovision) o Added support for spinners and roller controller From f403b169076b32fb5839f9acc3eeb1a869c565bc Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 22 Feb 2026 14:57:05 -0600 Subject: [PATCH 112/155] MSX2: Optimized SETWRT per ARTRAG comment --- cvbasic_prologue.asm | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 0a0e86d..e15a013 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -385,22 +385,26 @@ SETWRT: di endif if MSX&2 - xor a - rlc h - rla - rlc h - rla - srl h - srl h + ld a,h + rlca + rlca + and 3 out (VDP+1),a ld a,$8e out (VDP+1),a - endif ld a,l out (VDP+1),a ld a,h + and $3f or $40 out (VDP+1),a + else + ld a,l + out (VDP+1),a + ld a,h + or $40 + out (VDP+1),a + endif if COLECO_SPINNER ei endif From 4f2ed95bca8a27501f2b57e513776dd287f908bd Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 22 Feb 2026 17:24:23 -0600 Subject: [PATCH 113/155] MSX2: More optimization. Updated copyright year --- README.md | 2 +- cvbasic.c | 2 +- cvbasic_prologue.asm | 33 +++++++++++++++++---------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index df1024d..f8f6239 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # CVBasic compiler v0.9.1 -*(c) Copyright 2024-2025 Óscar Toledo Gutiérrez* +*(c) Copyright 2024-2026 Óscar Toledo Gutiérrez* *https://nanochess.org/* CVBasic is a BASIC language cross-compiler with a syntax alike to QBasic originally written for the Colecovision video game console. diff --git a/cvbasic.c b/cvbasic.c index be13429..d1c1e68 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -6665,7 +6665,7 @@ int main(int argc, char *argv[]) date = localtime(&actual); fprintf(stderr, "\nCVBasic compiler " VERSION "\n"); - fprintf(stderr, "(c) 2024-2025 Oscar Toledo G. https://nanochess.org/\n\n"); + fprintf(stderr, "(c) 2024-2026 Oscar Toledo G. https://nanochess.org/\n\n"); if (argc < 3) { fprintf(stderr, "Usage:\n"); diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index e15a013..eb98e5c 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -415,13 +415,10 @@ SETRD: di endif if MSX&2 - xor a - rlc h - rla - rlc h - rla - srl h - srl h + ld a,h + rlca + rlca + and 3 out (VDP+1),a ld a,$8e out (VDP+1),a @@ -890,7 +887,7 @@ update_sprite: pop af ; A = Sprite number push bc - ld de,sprites + ld d,sprites>>8 add a,a add a,a if SORD @@ -898,8 +895,10 @@ update_sprite: endif ld e,a ld hl,sprite_data - ld bc,4 - ldir + ldi + ldi + ldi + ldi endif ret @@ -1259,8 +1258,8 @@ font_bitmaps: palette_default: ld hl,msx2_default_palette palette_load: - di ld bc,$0010 + di call WRTVDP ld bc,32*256+VDP+2 otir @@ -1289,9 +1288,10 @@ define_sprite_color: ld h,$40/2 add hl,hl ; x16 ex de,hl - call nmi_off + di call LDIRVM - jp nmi_on + ei + ret update_sprite2: pop bc @@ -1303,13 +1303,14 @@ update_sprite2: pop af ; A = Sprite number push bc - ld de,sprites + ld d,sprites>>8 add a,a add a,a ld e,a ld hl,sprite_data - ld bc,3 - ldir + ldi + ldi + ldi ret ; From 72fb7433f4d0b8e86cb54f669aaa812ba01bd83f Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 26 Feb 2026 11:14:15 -0600 Subject: [PATCH 114/155] Z80: Speed up of CPYBLK, LDIRVM3, and FILVRM --- cvbasic_prologue.asm | 54 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index eb98e5c..de66a6f 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -44,13 +44,33 @@ ; Revision date: Feb/09/2026. Added support for palette in MSX2. ; Revision date: Feb/10/2026. Added support for sprites in MSX2 and 64K VRAM ; access. + ; Revision date: Feb/26/2026. Faster CPYBLK, LDIRVM3, and FILVRM. ; + ; + ; Resources: + ; * Z80 instructions timing: https://map.grauw.nl/resources/z80instr.php + ; * Use the Timing Z80+M1 for MSX and Colecovision (both insert one + ; wait state in each M1 cycle) + ; + ; Technical requirements: + ; * Minimum of 28 cycles between VDP writes for 3.58 mhz. systems. + ; * Minimum of 31 cycles between VDP writes for 4.00 mhz. systems. + ; * For SMS minimum of 28 cycles between VDP writes (3.58 mhz) + ; * For MSX2 (V9938) minimum of 23 cycles between VDP writes (3.58 mhz) + ; + ; Dependances: + ; * LDIRVM, assumed to keep DE unchanged (target VRAM address) + ; * For speed. Required by CPYBLK and LDIRVM3. + ; + + if COLECO+SG1000+SMS JOYSEL: equ $c0 KEYSEL: equ $80 JOY1: equ $fc-$20*(SG1000+SMS) JOY2: equ $ff-$22*(SG1000+SMS) + endif if COLECO org $8000 @@ -323,12 +343,14 @@ FILVRM: call SETWRT pop af dec bc ; T-states (normal / M1) + inc c + inc b .1: ld (VDP),a ; 13 14 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 + dec c ; 4 5 + jr nz,.1 ; 12 13 ; -- -- - ; 37 42 + ; 29 32 + djnz .1 ret LDIRMV: @@ -462,12 +484,23 @@ FILVRM: call SETWRT pop af dec bc ; T-states (normal / M1) + inc c + inc b + if MSX+COLECO +.1: out (VDP),a ; 12 + dec c ; 5 + jp nz,.1 ; 11 + ; -- + ; 28 + else .1: out (VDP),a ; 11 12 - dec bc ; 6 7 - bit 7,b ; 8 10 - jp z,.1 ; 10 11 + nop ; 4 5 + dec c ; 4 5 + jr nz,.1 ; 12 13 ; -- -- - ; 35 40 + ; 31 35 + endif + djnz .1 ret LDIRMV: @@ -527,11 +560,9 @@ LDIRVM3: call .1 call .1 .1: push hl - push de push bc call LDIRVM pop bc - pop de ld a,d add a,8 ld d,a @@ -563,10 +594,9 @@ CPYBLK: call nmi_off .1: push bc push hl - push de ld b,0 call LDIRVM - pop hl + ex de,hl if SMS ld bc,$0040 else From ccf867b8c0c1d98a6decaf468c76ff42897442f1 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 26 Feb 2026 23:27:35 -0600 Subject: [PATCH 115/155] Updated README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f8f6239..5f36882 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,9 @@ *(c) Copyright 2024-2026 Óscar Toledo Gutiérrez* *https://nanochess.org/* -CVBasic is a BASIC language cross-compiler with a syntax alike to QBasic originally written for the Colecovision video game console. - -The CVBasic compiler can create programs up to 1 MB using the BANK statements (using 16K bank switching on most platforms, 8k on TI-99/4A). - -It has been extended to support the following platforms: +CVBasic is a BASIC language cross-compiler with a syntax alike to QBasic. It supports the following platforms: +* Colecovision (supporting bank switching with Megacart mapper) * Sega SG-1000 / SC-3000 (supporting bank switching with Sega mapper) * MSX 1 and MSX 2 (supporting bank switching with ASCII16 mapper) * Texas Instruments TI-99/4A (courtesy of @tursilion, supporting bank switching) @@ -22,9 +19,13 @@ It has been extended to support the following platforms: * Sega Master System (supporting bank switching with Sega mapper) * NES/Famicom (supporting bank switching using mapper 30 - UNROM 512) +The CVBasic compiler can create programs up to 1 MB using the BANK statements (using 16K bank switching on most platforms, 8k on TI-99/4A). + One of the advantages of using CVBasic is that all the programs can be compiled for all the platforms with mostly no modifications at all. Although the compiler started supporting only Z80, now this includes the 6502 based Creativision, and TMS9900 based TI-99/4A. This way it achieves a truly portable BASIC across the common theme: the video processor Texas Instruments TMS9128/9129. -Currently, Sega Master System and NES/Famicom are different in video terms, although the compiler shares the core, the sprites are 8x16 and each pixel can have a different color, so the games aren't directly portable, but very easily translated. The examples include SMS and NES/Famicom versions for every game so you can see the required changes. +Porting to MSX2 is relatively easy. You only need to use MODE 4 for enabling the extended video mode, and create 16-byte color tables for sprites, and use these with DEFINE SPRITE COLOR. + +Currently, Sega Master System and NES/Famicom are the most different in video terms, although the compiler shares the core, the sprites are 8x16 and each pixel can have a different color, so the games aren't directly portable, but very easily translated. The examples include SMS and NES/Famicom versions for every game so you can see the required changes. The following files compose the compiler: From 93c227e780958335c6cdd95350fda80e6cc0102f Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 27 Feb 2026 09:45:23 +0100 Subject: [PATCH 116/155] More portable error codes Why? Because AmigaOS says 0, 1, 2, 3, 4 is success. --- cvbasic.c | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index d1c1e68..ceeb772 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -412,7 +412,7 @@ int process_variables(void); void emit_error(char *string) { fprintf(stderr, "ERROR: %s at line %d (%s)\n", string, current_line, current_file); - err_code = 1; + err_code = EXIT_FAILURE; } /* @@ -540,7 +540,7 @@ struct label *function_add(char *name) new_one = malloc(sizeof(struct label) + strlen(name)); if (new_one == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_one->used = 0; new_one->length = 0; @@ -578,7 +578,7 @@ struct signedness *signed_add(char *name) new_one = malloc(sizeof(struct signedness) + strlen(name)); if (new_one == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_one->sign = 0; strcpy(new_one->name, name); @@ -615,7 +615,7 @@ struct constant *constant_add(char *name) new_one = malloc(sizeof(struct constant) + strlen(name)); if (new_one == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_one->value = 0; strcpy(new_one->name, name); @@ -652,7 +652,7 @@ struct label *label_add(char *name) new_one = malloc(sizeof(struct label) + strlen(name)); if (new_one == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_one->used = 0; strcpy(new_one->name, name); @@ -690,7 +690,7 @@ struct label *array_add(char *name) new_one = malloc(sizeof(struct label) + strlen(name)); if (new_one == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_one->used = 0; strcpy(new_one->name, name); @@ -727,7 +727,7 @@ struct macro *macro_add(char *name) new_one = malloc(sizeof(struct macro) + strlen(name)); if (new_one == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_one->total_arguments = 0; new_one->in_use = 0; @@ -1966,7 +1966,7 @@ void accumulated_push(enum lexical_component lex, int value, char *name) accumulated.definition = realloc(accumulated.definition, (accumulated.max_length + 1) * 2 * sizeof(struct macro_def)); if (accumulated.definition == NULL) { emit_error("out of memory in accumulated_push"); - exit(1); + exit(EXIT_FAILURE); } accumulated.max_length = (accumulated.max_length + 1) * 2; } @@ -1978,7 +1978,7 @@ void accumulated_push(enum lexical_component lex, int value, char *name) accumulated.definition[accumulated.length].name = malloc(strlen(name) + 1); if (accumulated.definition[accumulated.length].name == NULL) { emit_error("out of memory in accumulated_push"); - exit(1); + exit(EXIT_FAILURE); } if (lex == C_STRING) { if (value > 0) @@ -2308,7 +2308,7 @@ void compile_statement(int check_for_else) new_loop = malloc(sizeof(struct loop)); if (new_loop == NULL) { fprintf(stderr, "out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_loop->type = NESTED_IF; new_loop->step = NULL; @@ -2462,7 +2462,7 @@ void compile_statement(int check_for_else) new_loop = malloc(sizeof(struct loop) + strlen(assigned) + 1); if (new_loop == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } strcpy(new_loop->var, assigned); if (assigned[0] == '#') @@ -2617,7 +2617,7 @@ void compile_statement(int check_for_else) new_loop = malloc(sizeof(struct loop)); if (new_loop == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_loop->type = NESTED_WHILE; new_loop->step = NULL; @@ -2658,7 +2658,7 @@ void compile_statement(int check_for_else) new_loop = malloc(sizeof(struct loop)); if (new_loop == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } if (lex == C_NAME && strcmp(name, "WHILE") == 0) { get_lex(); @@ -2741,7 +2741,7 @@ void compile_statement(int check_for_else) new_loop = malloc(sizeof(struct loop)); if (new_loop == NULL) { fprintf(stderr, "Out of memory\n"); - exit(1); + exit(EXIT_FAILURE); } new_loop->type = NESTED_SELECT; if (lex == C_NAME && strcmp(name, "CASE") == 0) { @@ -6513,11 +6513,11 @@ int process_variables(void) while (label != NULL) { if ((label->used & (LABEL_CALLED_BY_GOTO & LABEL_IS_PROCEDURE)) == (LABEL_CALLED_BY_GOTO | LABEL_IS_PROCEDURE)) { fprintf(stderr, "Error: PROCEDURE '%s' jumped in by GOTO\n", label->name); - err_code = 1; + err_code = EXIT_FAILURE; } if ((label->used & (LABEL_CALLED_BY_GOSUB & LABEL_IS_PROCEDURE)) == LABEL_CALLED_BY_GOSUB) { fprintf(stderr, "Error: Common label '%s' jumped in by GOSUB\n", label->name); - err_code = 1; + err_code = EXIT_FAILURE; } if (label->used & LABEL_IS_VARIABLE) { if (target == CPU_6502) { @@ -6697,7 +6697,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "Kamshaft, Kiwi, MADrigal, pixelboy, Revontuli, SiRioKD, Tarzilla,\n"); fprintf(stderr, "Tony Cruise, tursilion, visrealm, wavemotion, and youki.\n"); fprintf(stderr, "\n"); - exit(1); + exit(EXIT_FAILURE); } /* @@ -6719,7 +6719,7 @@ int main(int argc, char *argv[]) } if (machine == TOTAL_TARGETS) { fprintf(stderr, "Unknown target: %s\n", argv[c]); - exit(1); + exit(EXIT_FAILURE); } target = consoles[machine].target; c++; @@ -6748,7 +6748,7 @@ int main(int argc, char *argv[]) extra_ram = 8192; } else { fprintf(stderr, "-ram16 option only applies to MSX/MSX2.\n"); - exit(2); + exit(EXIT_FAILURE+1); } } bank_konami = 0; @@ -6760,7 +6760,7 @@ int main(int argc, char *argv[]) bank_konami = 1; } else { fprintf(stderr, "-konami option only applies to MSX/MSX2.\n"); - exit(2); + exit(EXIT_FAILURE+1); } } cpm_option = 0; @@ -6773,7 +6773,7 @@ int main(int argc, char *argv[]) cpm_option = 1; } else { fprintf(stderr, "-cpm option only applies to Memotech or NABU.\n"); - exit(2); + exit(EXIT_FAILURE+1); } } small_rom = 0; @@ -6785,7 +6785,7 @@ int main(int argc, char *argv[]) small_rom = 1; } else { fprintf(stderr, "-rom16 option only applies to Creativision.\n"); - exit(2); + exit(EXIT_FAILURE+1); } } @@ -6804,7 +6804,7 @@ int main(int argc, char *argv[]) break; if (!isalnum(ch) && ch != '_' && ch != '#' && ch != '=') { fprintf(stderr, "%s name includes invalid characters.\n", argv[c]); - exit(2); + exit(EXIT_FAILURE+1); } if (ch == '=') { *p = '\0'; @@ -6823,7 +6823,7 @@ int main(int argc, char *argv[]) } if (d == NULL) { fprintf(stderr, "%s missing assignment. Syntax: -DCONST=123 -D#BIGCONST=12345\n", argv[c]); - exit(2); + exit(EXIT_FAILURE+1); } c++; } @@ -6832,18 +6832,18 @@ int main(int argc, char *argv[]) ** Here is compiled the source code and generates a temporary assembler file. */ strcpy(current_file, argv[c]); - err_code = 0; + err_code = EXIT_SUCCESS; input = fopen(current_file, "r"); if (input == NULL) { fprintf(stderr, "Couldn't open '%s' source file.\n", current_file); - exit(2); + exit(EXIT_FAILURE+1); } c++; output = fopen(TEMPORARY_ASSEMBLER, "w"); if (output == NULL) { fprintf(stderr, "Couldn't open '%s' temporary file.\n", TEMPORARY_ASSEMBLER); - exit(2); + exit(EXIT_FAILURE+1); } bank_switching = 0; option_explicit = 0; @@ -6878,7 +6878,7 @@ int main(int argc, char *argv[]) output = fopen(argv[c], "w"); if (output == NULL) { fprintf(stderr, "Couldn't open '%s' output file.\n", argv[2]); - exit(2); + exit(EXIT_FAILURE+1); } c++; @@ -6989,7 +6989,7 @@ int main(int argc, char *argv[]) prologue = fopen(path, "r"); if (prologue == NULL) { fprintf(stderr, "Unable to open '%s'.\n", path); - exit(2); + exit(EXIT_FAILURE+1); } while (fgets(line, sizeof(line) - 1, prologue)) { p = line; @@ -7031,7 +7031,7 @@ int main(int argc, char *argv[]) input = fopen(TEMPORARY_ASSEMBLER, "r"); if (input == NULL) { fprintf(stderr, "Unable to reopen '%s'.\n", TEMPORARY_ASSEMBLER); - exit(2); + exit(EXIT_FAILURE+1); } while (fgets(line, sizeof(line) - 1, input)) { fputs(line, output); @@ -7051,7 +7051,7 @@ int main(int argc, char *argv[]) prologue = fopen(path, "r"); if (prologue == NULL) { fprintf(stderr, "Unable to open '%s'.\n", path); - exit(2); + exit(EXIT_FAILURE+1); } while (fgets(line, sizeof(line) - 1, prologue)) { fputs(line, output); @@ -7104,7 +7104,7 @@ int main(int argc, char *argv[]) 146; /* Support variables */ if (bytes_used > available_bytes) { fprintf(stderr, "ERROR: "); - err_code = 1; + err_code = EXIT_FAILURE; } fprintf(stderr, "%d RAM bytes used of %d bytes available.\n", bytes_used, available_bytes); } From 3b416a295f4ad56f9565b896f250c58cd45725aa Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 1 Mar 2026 18:47:05 -0600 Subject: [PATCH 117/155] Z80: Optimization IF with 8-bit AND, also multiplication by 128 --- cpuz80.c | 14 +++++++++++--- cvbasic.c | 8 ++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/cpuz80.c b/cpuz80.c index 618e823..902bd74 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -1520,9 +1520,17 @@ void cpuz80_node_generate(struct node *node, int decision) } else { cpuz80_node_generate(node, 0); } - while (c > 1) { - cpuz80_2op("ADD", "HL", "HL"); - c /= 2; + if (c == 128) { + cpuz80_1op("SRL", "H"); + cpuz80_2op("LD", "H", "L"); + cpuz80_1op("RR", "H"); + cpuz80_2op("LD", "L", "0"); + cpuz80_1op("RR", "L"); + } else { + while (c > 1) { + cpuz80_2op("ADD", "HL", "HL"); + c /= 2; + } } } break; diff --git a/cvbasic.c b/cvbasic.c index ceeb772..acfe44c 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -1116,6 +1116,14 @@ int evaluate_expression(int cast, int to_type, int label) tree->right->type = N_NUM8; tree->type = N_AND8; type = TYPE_8; + } else if (tree->type == N_EXTEND8 && tree->left->type == N_AND8) { + struct node *temp; + + temp = tree; + tree = temp->left; + temp->left = NULL; + node_delete(temp); + type = TYPE_8; } } if (label != 0 && (tree->type == N_NUM8 || tree->type == N_NUM16)) { From 1a7b31fff63750e26cfd2d84a3494b33e19826bc Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 1 Mar 2026 21:48:32 -0600 Subject: [PATCH 118/155] Z80: Allows to remove further constant reload --- cpuz80.c | 146 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 98 insertions(+), 48 deletions(-) diff --git a/cpuz80.c b/cpuz80.c index 902bd74..b9519c5 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -22,8 +22,10 @@ static char z80_line_1[MAX_LINE_SIZE]; static char z80_line_2[MAX_LINE_SIZE]; static char z80_line_3[MAX_LINE_SIZE]; -static char z80_a_content[MAX_LINE_SIZE]; -static char z80_hl_content[MAX_LINE_SIZE]; +static char z80_a_value[MAX_LINE_SIZE]; +static char z80_a_alias[MAX_LINE_SIZE]; +static char z80_hl_value[MAX_LINE_SIZE]; +static char z80_hl_alias[MAX_LINE_SIZE]; static int z80_flag_z_valid; static void z80_emit_line(void); @@ -93,8 +95,10 @@ void cpuz80_label(char *label) { sprintf(z80_line, "%s:\n", label); z80_emit_line(); - z80_a_content[0] = '\0'; - z80_hl_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; z80_flag_z_valid = 0; } @@ -103,7 +107,8 @@ void cpuz80_label(char *label) */ void cpuz80_empty(void) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; } @@ -114,7 +119,8 @@ void cpuz80_noop(char *mnemonic) { sprintf(z80_line, "\t%s\n", mnemonic); z80_emit_line(); - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; if (strcmp(mnemonic, "NEG") == 0) z80_flag_z_valid = 1; else @@ -131,7 +137,7 @@ void cpuz80_1op(char *mnemonic, char *operand) */ if (strcmp(mnemonic, "SUB") == 0) { if (strcmp(operand, "A") == 0) { - if (strcmp(z80_a_content, "0") == 0) + if (strcmp(z80_a_value, "0") == 0) return; } } @@ -159,61 +165,77 @@ void cpuz80_1op(char *mnemonic, char *operand) z80_flag_z_valid = 0; } else if (strcmp(mnemonic, "POP") == 0) { if (strcmp(operand, "AF") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; } else if (strcmp(operand, "HL") == 0) { - z80_hl_content[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; } } else if (strcmp(mnemonic, "CALL") == 0 || strcmp(mnemonic, "JP") == 0 || strcmp(mnemonic, "JR") == 0) { - z80_a_content[0] = '\0'; - z80_hl_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; z80_flag_z_valid = 0; } else if (strcmp(mnemonic, "SUB") == 0) { if (strcmp(operand, "A") == 0) - strcpy(z80_a_content, "0"); + strcpy(z80_a_value, "0"); else - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 1; } else if (strcmp(mnemonic, "OR") == 0 || strcmp(mnemonic, "XOR") == 0 || strcmp(mnemonic, "AND") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 1; } else if (strcmp(mnemonic, "SRL") == 0) { - if (strcmp(operand, "H") == 0) - z80_hl_content[0] = '\0'; - else if (strcmp(operand, "A") == 0) + if (strcmp(operand, "H") == 0) { + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; + } else if (strcmp(operand, "A") == 0) { z80_flag_z_valid = 1; + } } else if (strcmp(mnemonic, "RR") == 0) { - if (strcmp(operand, "L") == 0) - z80_hl_content[0] = '\0'; + if (strcmp(operand, "L") == 0) { + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; + } z80_flag_z_valid = 0; } else if (strcmp(mnemonic, "INC") == 0) { if (strcmp(operand, "H") == 0 || strcmp(operand, "L") == 0 || strcmp(operand, "HL") == 0) { - z80_hl_content[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; z80_flag_z_valid = 0; } else if (strcmp(operand, "A") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 1; } else if (strcmp(operand, "(HL)") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; } } else if (strcmp(mnemonic, "DEC") == 0) { if (strcmp(operand, "H") == 0 || strcmp(operand, "L") == 0 || strcmp(operand, "HL") == 0) { - z80_hl_content[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; z80_flag_z_valid = 0; } else if (strcmp(operand, "A") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 1; } else if (strcmp(operand, "(HL)") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; } } else if (strcmp(mnemonic, "DW") == 0 || strcmp(mnemonic, "ORG") == 0 || strcmp(mnemonic, "FORG") == 0) { @@ -236,26 +258,28 @@ void cpuz80_2op(char *mnemonic, char *operand1, char *operand2) special = 0; if (strcmp(mnemonic, "LD") == 0) { if (strcmp(operand1, "A") == 0) { - if (strcmp(operand2, z80_a_content) == 0) + if (strcmp(operand2, z80_a_alias) == 0 || strcmp(operand2, z80_a_value) == 0) return; - if (strcmp(operand2, z80_hl_content) == 0) { + if (strcmp(operand2, z80_hl_alias) == 0 || strcmp(operand2, z80_hl_value) == 0) { operand2 = "L"; /* Reading from memory address, and HL already has the address */ - } else if (operand2[0] == '(' && operand2[strlen(operand2) - 1] == ')' && memcmp(&operand2[1], z80_hl_content, strlen(operand2) - 2) == 0 && z80_hl_content[strlen(operand2) - 2] == '\0') { + } else if (operand2[0] == '(' && operand2[strlen(operand2) - 1] == ')' && memcmp(&operand2[1], z80_hl_alias, strlen(operand2) - 2) == 0 && z80_hl_alias[strlen(operand2) - 2] == '\0') { /* Generate subexpression info and mark as previously processed */ z80_flag_z_valid = 0; - strcpy(z80_a_content, operand2); + z80_a_value[0] = '\0'; + strcpy(z80_a_alias, operand2); special = 1; /* Mark as processed */ operand2 = "(HL)"; } } else if (strcmp(operand1, "HL") == 0) { - if (strcmp(operand2, z80_hl_content) == 0) + if (strcmp(operand2, z80_hl_alias) == 0 || strcmp(operand2, z80_hl_value) == 0) return; } else if (strcmp(operand2, "A") == 0) { /* Writing to memory address, and HL already has the address */ - if (operand1[0] == '(' && operand1[strlen(operand1) - 1] == ')' && memcmp(&operand1[1], z80_hl_content, strlen(operand1) - 2) == 0 && z80_hl_content[strlen(operand1) - 2] == '\0') { + if (operand1[0] == '(' && operand1[strlen(operand1) - 1] == ')' && memcmp(&operand1[1], z80_hl_alias, strlen(operand1) - 2) == 0 && z80_hl_alias[strlen(operand1) - 2] == '\0') { /* Generate subexpression info and mark as previously processed */ - strcpy(z80_a_content, operand1); + strcpy(z80_a_alias, operand1); + /* It doesn't erase z80_a_value as any value is still valid */ special = 1; /* Mark as processed */ operand1 = "(HL)"; } @@ -272,16 +296,20 @@ void cpuz80_2op(char *mnemonic, char *operand1, char *operand2) strcmp(mnemonic, "SET") == 0) { /* No affected registers or flags */ } else if (strcmp(mnemonic, "EX") == 0) { - z80_hl_content[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; } else if (strcmp(mnemonic, "IN") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; } else if (strcmp(mnemonic, "ADD") == 0 || strcmp(mnemonic, "ADC") == 0 || strcmp(mnemonic, "SBC") == 0) { if (strcmp(operand1, "A") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; z80_flag_z_valid = 1; } else { - z80_hl_content[0] = '\0'; + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; z80_flag_z_valid = 0; } } else if (strcmp(mnemonic, "LD") == 0) { @@ -289,23 +317,45 @@ void cpuz80_2op(char *mnemonic, char *operand1, char *operand2) return; if (strcmp(operand1, "A") == 0) /* Read value into accumulator */ z80_flag_z_valid = 0; /* Z status isn't valid */ - if (strcmp(operand1, "L") == 0 || strcmp(operand1, "H") == 0) - z80_hl_content[0] = '\0'; - if (strcmp(operand1, "HL") == 0) - strcpy(z80_hl_content, operand2); - else if (strcmp(operand2, "HL") == 0) - strcpy(z80_hl_content, operand1); + if (strcmp(operand1, "L") == 0 || strcmp(operand1, "H") == 0) { + z80_hl_value[0] = '\0'; + z80_hl_alias[0] = '\0'; + } + if (strcmp(operand1, "HL") == 0) { + if (isdigit(operand2[0])) { + /* Loading a value destroys any previous alias */ + strcpy(z80_hl_value, operand2); + z80_hl_alias[0] = '\0'; + } else { + /* Loading from an address destroy any previous value */ + strcpy(z80_hl_alias, operand2); + z80_hl_value[0] = '\0'; + } + } else if (strcmp(operand2, "HL") == 0) { + /* Saving to an address makes HL an alias AND PRESERVES the value */ + strcpy(z80_hl_alias, operand1); + } if (strcmp(operand1, "A") == 0 && strcmp(operand2, "(HL)") == 0) { - z80_a_content[0] = '\0'; + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; } else if (strcmp(operand1, "(HL)") == 0 && strcmp(operand2, "A") == 0) { /* A keeps its value */ } else if (strcmp(operand1, "A") == 0) { - if (isdigit(operand2[0]) || operand2[0] == '(') - strcpy(z80_a_content, operand2); - else - z80_a_content[0] = '\0'; + if (isdigit(operand2[0])) { + /* Loading a value destroys any previous alias */ + strcpy(z80_a_value, operand2); + z80_a_alias[0] = '\0'; + } else if (operand2[0] == '(') { + /* Loading from an address destroy any previous value */ + z80_a_value[0] = '\0'; + strcpy(z80_a_alias, operand2); + } else { + z80_a_value[0] = '\0'; + z80_a_alias[0] = '\0'; + } } else if (strcmp(operand2, "A") == 0 && operand1[0] == '(') { - strcpy(z80_a_content, operand1); + /* Saving to an address makes A an alias AND PRESERVES the value */ + strcpy(z80_a_alias, operand1); } } else { fprintf(stderr, "z80_2op: not found mnemonic %s\n", mnemonic); From 63626c2ccbe4a0801d7ee01199a6c7b794720128 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 5 Mar 2026 15:01:57 -0600 Subject: [PATCH 119/155] SMS: Added note about PALETTE --- manual.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/manual.txt b/manual.txt index 1649fb1..b32ae15 100644 --- a/manual.txt +++ b/manual.txt @@ -963,6 +963,9 @@ The following statements are available: You can restore the palette to TMS9118 colors by using PALETTE DEFAULT. + It is recommended to update the palette only in the vertical blanking + to avoid glitches on the display. + For the NES/Famicom: Registers From a60149b68eec85127a3535c7786ded3de7d87ed3 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 6 Mar 2026 19:12:24 -0600 Subject: [PATCH 120/155] Z80: Keeps array[index] expression to reuse them --- cpuz80.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- cvbasic.c | 2 +- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/cpuz80.c b/cpuz80.c index b9519c5..1e126d4 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -16,6 +16,12 @@ #define REG_ALL (REG_AF | REG_BC | REG_DE | REG_HL) +/* + ** Character used internally to mark precalculated array[index] addresses + */ +#define INDEX_ADD '[' +#define INDEX_ADD_STRING "[" + static char z80_line[MAX_LINE_SIZE]; static char z80_line_1[MAX_LINE_SIZE]; @@ -221,6 +227,8 @@ void cpuz80_1op(char *mnemonic, char *operand) z80_a_value[0] = '\0'; z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; + if (strchr(z80_hl_alias, INDEX_ADD) != NULL) + z80_hl_alias[0] = '\0'; } } else if (strcmp(mnemonic, "DEC") == 0) { if (strcmp(operand, "H") == 0 || @@ -237,6 +245,8 @@ void cpuz80_1op(char *mnemonic, char *operand) z80_a_value[0] = '\0'; z80_a_alias[0] = '\0'; z80_flag_z_valid = 0; + if (strchr(z80_hl_alias, INDEX_ADD) != NULL) + z80_hl_alias[0] = '\0'; } } else if (strcmp(mnemonic, "DW") == 0 || strcmp(mnemonic, "ORG") == 0 || strcmp(mnemonic, "FORG") == 0) { /* Nothing to do */ @@ -353,9 +363,11 @@ void cpuz80_2op(char *mnemonic, char *operand1, char *operand2) z80_a_value[0] = '\0'; z80_a_alias[0] = '\0'; } - } else if (strcmp(operand2, "A") == 0 && operand1[0] == '(') { + } else if (operand1[0] == '(' && strcmp(operand2, "A") == 0) { /* Saving to an address makes A an alias AND PRESERVES the value */ strcpy(z80_a_alias, operand1); + if (strchr(z80_hl_alias, INDEX_ADD) != NULL) + z80_hl_alias[0] = '\0'; } } else { fprintf(stderr, "z80_2op: not found mnemonic %s\n", mnemonic); @@ -1368,8 +1380,8 @@ void cpuz80_node_generate(struct node *node, int decision) } /* Optimization of address plus/minus constant */ if (node->type == N_PLUS16 || node->type == N_MINUS16) { - if (node->left->type == N_ADDR) { - if (node->right->type == N_NUM16) { + if (node->left->type == N_ADDR) { /* addr + : addr - */ + if (node->right->type == N_NUM16) { /* addr + const : addr - const */ node_get_label(node->left, 0); if (node->type == N_PLUS16) strcat(temp, "+"); @@ -1386,10 +1398,45 @@ void cpuz80_node_generate(struct node *node, int decision) } if (node->type == N_PLUS16) { if (node->left->type == N_ADDR) { + if (node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { /* addr + var : addr - var */ + char *p; + + if ((p = strchr(z80_hl_alias, INDEX_ADD)) != NULL) { /* If there is an index saved... */ + node_get_label(node->right->left, 0); + if (strcmp(temp, p + 1) == 0) { /* ...and it is the same index */ + *p = '\0'; + node_get_label(node->left, 0); + if (strcmp(z80_hl_alias, temp) != 0) { /* Add difference between the two arrays position, or none if same array */ + strcat(temp, "-"); + strcat(temp, z80_hl_alias); + cpuz80_2op("LD", "DE", temp); + cpuz80_2op("ADD", "HL", "DE"); + } + node_get_label(node->left, 0); + strcpy(z80_hl_alias, temp); + strcat(z80_hl_alias, INDEX_ADD_STRING); + node_get_label(node->right->left, 0); + strcat(z80_hl_alias, temp); + break; + } + } + } cpuz80_node_generate(node->right, 0); node_get_label(node->left, 0); cpuz80_2op("LD", "DE", temp); cpuz80_2op("ADD", "HL", "DE"); + + /* + ** Higher-level optimization + ** z80_hl_alias indicates it contains address for array[var] + */ + if (node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { /* addr + var : addr - var */ + node_get_label(node->left, 0); + strcpy(z80_hl_alias, temp); + strcat(z80_hl_alias, INDEX_ADD_STRING); + node_get_label(node->right->left, 0); + strcat(z80_hl_alias, temp); + } break; } if (node->left->type == N_NUM16 || node->right->type == N_NUM16) { diff --git a/cvbasic.c b/cvbasic.c index acfe44c..9007a66 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.1 Feb/17/2026" +#define VERSION "v0.9.2 Mar/06/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" From 3409247a589b9a816122e02ffe24bbae7e132271 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 6 Mar 2026 20:04:36 -0600 Subject: [PATCH 121/155] Z80: Optimizes 8-bit operations to use (HL) operand, like ADD A,(HL) --- cpuz80.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpuz80.c b/cpuz80.c index 1e126d4..f5d75ec 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -566,7 +566,9 @@ void cpuz80_node_label(struct node *node) } else { cpuz80_node_label(node->right); cpuz80_node_label(node->left); - if (node->left->regs == REG_A) { + if ((node->type == N_PLUS8 || node->type == N_MINUS8 || node->type == N_OR8 || node->type == N_AND8 || node->type == N_XOR8) && node->right->type == N_PEEK8 && (node->right->left->regs & REG_A) == 0) { + node->regs = node->left->regs | node->right->left->regs; + } else if (node->left->regs == REG_A) { node->regs = REG_A | REG_B; } else { node->regs = node->left->regs | node->right->regs | REG_BC; @@ -1111,6 +1113,10 @@ void cpuz80_node_generate(struct node *node, int decision) break; } sprintf(temp, "%d", c); + } else if ((node->type == N_PLUS8 || node->type == N_MINUS8 || node->type == N_OR8 || node->type == N_AND8 || node->type == N_XOR8) && node->right->type == N_PEEK8 && (node->right->left->regs & REG_A) == 0) { + cpuz80_node_generate(node->left, 0); + cpuz80_node_generate(node->right->left, 0); + strcpy(temp, "(HL)"); } else { if ((node->left->regs & REG_B) == 0) { cpuz80_node_generate(node->right, 0); From 372385dcab57875a818b2b725e6c31c342839f65 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 6 Mar 2026 20:28:16 -0600 Subject: [PATCH 122/155] 6502: Added alias optimization to avoid reloading variables --- cpu6502.c | 175 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 111 insertions(+), 64 deletions(-) diff --git a/cpu6502.c b/cpu6502.c index 1f85eda..0217f23 100644 --- a/cpu6502.c +++ b/cpu6502.c @@ -21,9 +21,12 @@ static char temp2[MAX_LINE_SIZE]; static char cpu6502_line[MAX_LINE_SIZE]; -static char cpu6502_a[MAX_LINE_SIZE]; -static char cpu6502_x[MAX_LINE_SIZE]; -static char cpu6502_y[MAX_LINE_SIZE]; +static char cpu6502_a_value[MAX_LINE_SIZE]; +static char cpu6502_a_alias[MAX_LINE_SIZE]; +static char cpu6502_x_value[MAX_LINE_SIZE]; +static char cpu6502_x_alias[MAX_LINE_SIZE]; +static char cpu6502_y_value[MAX_LINE_SIZE]; +static char cpu6502_y_alias[MAX_LINE_SIZE]; static int cpu6502_flag_z_valid; static void cpu6502_emit_line(void); @@ -44,9 +47,11 @@ void cpu6502_label(char *label) { sprintf(cpu6502_line, "%s:\n", label); cpu6502_emit_line(); - cpu6502_a[0] = '\0'; - cpu6502_x[0] = '\0'; - cpu6502_y[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + cpu6502_x_value[0] = '\0'; + cpu6502_y_value[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } @@ -55,9 +60,11 @@ void cpu6502_label(char *label) */ void cpu6502_empty(void) { - cpu6502_a[0] = '\0'; - cpu6502_x[0] = '\0'; - cpu6502_y[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + cpu6502_x_value[0] = '\0'; + cpu6502_y_value[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } @@ -84,30 +91,36 @@ void cpu6502_noop(char *mnemonic) if (strcmp(mnemonic, "PHA") == 0 || strcmp(mnemonic, "SEI") == 0 || strcmp(mnemonic, "CLI") == 0 || strcmp(mnemonic, "SEC") == 0 || strcmp(mnemonic, "CLC") == 0) { /* Nothing to do */ } else if (strcmp(mnemonic, "PLA") == 0) { - cpu6502_a[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "TAX") == 0) { - strcpy(cpu6502_x, cpu6502_a); + strcpy(cpu6502_x_value, cpu6502_a_value); cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "TAY") == 0) { - strcpy(cpu6502_y, cpu6502_a); + strcpy(cpu6502_y_value, cpu6502_a_value); cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "TXA") == 0) { - strcpy(cpu6502_a, cpu6502_x); + strcpy(cpu6502_a_value, cpu6502_x_value); cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "TYA") == 0) { - strcpy(cpu6502_a, cpu6502_y); + strcpy(cpu6502_a_value, cpu6502_y_value); cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "INX") == 0 || strcmp(mnemonic, "DEX") == 0) { - cpu6502_x[0] = '\0'; + cpu6502_x_value[0] = '\0'; + cpu6502_x_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "INY") == 0 || strcmp(mnemonic, "DEY") == 0) { - cpu6502_y[0] = '\0'; + cpu6502_y_value[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "RTS") == 0) { - cpu6502_a[0] = '\0'; - cpu6502_x[0] = '\0'; - cpu6502_y[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + cpu6502_x_value[0] = '\0'; + cpu6502_x_alias[0] = '\0'; + cpu6502_y_value[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } else { fprintf(stderr, "cpu6502_noop: not found mnemonic %s\n", mnemonic); @@ -131,94 +144,128 @@ void cpu6502_1op(char *mnemonic, char *operand) ** copy into registers using a single byte instruction. */ if (strcmp(mnemonic, "LDA") == 0) { - if (strcmp(operand, cpu6502_x) == 0) { + if (strcmp(operand, cpu6502_a_value) == 0 || strcmp(operand, cpu6502_a_alias) == 0) + return; + if (strcmp(operand, cpu6502_x_value) == 0 || strcmp(operand, cpu6502_x_alias) == 0) { cpu6502_noop("TXA"); + strcpy(cpu6502_a_value, cpu6502_x_value); + strcpy(cpu6502_a_alias, cpu6502_x_alias); return; } - if (strcmp(operand, cpu6502_y) == 0) { + if (strcmp(operand, cpu6502_y_value) == 0 || strcmp(operand, cpu6502_y_alias) == 0) { cpu6502_noop("TYA"); + strcpy(cpu6502_a_value, cpu6502_y_value); + strcpy(cpu6502_a_alias, cpu6502_y_alias); return; } } if (strcmp(mnemonic, "LDX") == 0) { - if (strcmp(operand, cpu6502_a) == 0) { + if (strcmp(operand, cpu6502_x_value) == 0 || strcmp(operand, cpu6502_x_alias) == 0) + return; + if (strcmp(operand, cpu6502_a_value) == 0 || strcmp(operand, cpu6502_a_alias) == 0) { cpu6502_noop("TAX"); + strcpy(cpu6502_x_value, cpu6502_a_value); + strcpy(cpu6502_x_alias, cpu6502_a_alias); return; } } if (strcmp(mnemonic, "LDY") == 0) { - if (strcmp(operand, cpu6502_a) == 0) { + if (strcmp(operand, cpu6502_y_value) == 0 || strcmp(operand, cpu6502_y_alias) == 0) + return; + if (strcmp(operand, cpu6502_a_value) == 0 || strcmp(operand, cpu6502_a_alias) == 0) { cpu6502_noop("TAY"); + strcpy(cpu6502_y_value, cpu6502_a_value); + strcpy(cpu6502_y_alias, cpu6502_a_alias); return; } } sprintf(cpu6502_line, "\t%s %s\n", mnemonic, operand); cpu6502_emit_line(); if (strcmp(mnemonic, "LDA") == 0) { - if (strchr(operand, ',') != NULL) - cpu6502_a[0] = '\0'; - else - strcpy(cpu6502_a, operand); + if (strchr(operand, ',') != NULL) { + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + } else if (operand[0] == '#') { + strcpy(cpu6502_a_value, operand); + cpu6502_a_alias[0] = '\0'; + } else { + cpu6502_a_value[0] = '\0'; + strcpy(cpu6502_a_alias, operand); + } cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "LDX") == 0) { - if (strchr(operand, ',') != NULL) - cpu6502_x[0] = '\0'; - else - strcpy(cpu6502_x, operand); + if (strchr(operand, ',') != NULL) { + cpu6502_x_value[0] = '\0'; + cpu6502_x_alias[0] = '\0'; + } else if (operand[0] == '#') { + strcpy(cpu6502_x_value, operand); + cpu6502_x_alias[0] = '\0'; + } else { + cpu6502_x_value[0] = '\0'; + strcpy(cpu6502_x_alias, operand); + } cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "LDY") == 0) { - if (strchr(operand, ',') != NULL) - cpu6502_y[0] = '\0'; - else - strcpy(cpu6502_y, operand); + if (strchr(operand, ',') != NULL) { + cpu6502_y_value[0] = '\0'; + cpu6502_y_alias[0] = '\0'; + } else if (operand[0] == '#') { + strcpy(cpu6502_y_value, operand); + cpu6502_y_alias[0] = '\0'; + } else { + cpu6502_y_value[0] = '\0'; + strcpy(cpu6502_y_alias, operand); + } cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "CMP") == 0 || strcmp(mnemonic, "CPX") == 0 || strcmp(mnemonic, "CPY") == 0) { /* Only flags affected */ cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "ADC") == 0 || strcmp(mnemonic, "SBC") == 0 || strcmp(mnemonic, "ORA") == 0 || strcmp(mnemonic, "EOR") == 0 || strcmp(mnemonic, "AND") == 0) { - cpu6502_a[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; cpu6502_flag_z_valid = 1; } else if (strcmp(mnemonic, "ROR") == 0 || strcmp(mnemonic, "ROL") == 0 || strcmp(mnemonic, "ASL") == 0 || strcmp(mnemonic, "LSR") == 0) { if (strcmp(operand, "A") == 0) { - cpu6502_a[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; cpu6502_flag_z_valid = 1; } else { - if (cpu6502_a[0] != '#') - cpu6502_a[0] = '\0'; - if (cpu6502_x[0] != '#') - cpu6502_x[0] = '\0'; - if (cpu6502_y[0] != '#') - cpu6502_y[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + cpu6502_x_alias[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } } else if (strcmp(mnemonic, "INC") == 0 || strcmp(mnemonic, "DEC") == 0) { - if (cpu6502_a[0] != '#') - cpu6502_a[0] = '\0'; - if (cpu6502_x[0] != '#') - cpu6502_x[0] = '\0'; - if (cpu6502_y[0] != '#') - cpu6502_y[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + cpu6502_x_alias[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "JSR") == 0 || strcmp(mnemonic, "JMP") == 0 || strcmp(mnemonic, "ORG") == 0 || strcmp(mnemonic, "FORG") == 0) { - cpu6502_a[0] = '\0'; - cpu6502_x[0] = '\0'; - cpu6502_y[0] = '\0'; + cpu6502_a_value[0] = '\0'; + cpu6502_a_alias[0] = '\0'; + cpu6502_x_value[0] = '\0'; + cpu6502_x_alias[0] = '\0'; + cpu6502_y_value[0] = '\0'; + cpu6502_y_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "STA") == 0) { - if (strchr(operand, ',') != NULL) - cpu6502_a[0] = '\0'; - else - strcpy(cpu6502_a, operand); + if (strchr(operand, ',') != NULL) { + cpu6502_a_alias[0] = '\0'; + } else { + strcpy(cpu6502_a_alias, operand); + } } else if (strcmp(mnemonic, "STX") == 0) { - if (strchr(operand, ',') != NULL) - cpu6502_x[0] = '\0'; - else - strcpy(cpu6502_x, operand); + if (strchr(operand, ',') != NULL) { + cpu6502_x_alias[0] = '\0'; + } else { + strcpy(cpu6502_x_alias, operand); + } } else if (strcmp(mnemonic, "STY") == 0) { - if (strchr(operand, ',') != NULL) - cpu6502_y[0] = '\0'; - else - strcpy(cpu6502_y, operand); + if (strchr(operand, ',') != NULL) { + cpu6502_y_alias[0] = '\0'; + } else { + strcpy(cpu6502_y_alias, operand); + } } else if (strcmp(mnemonic, "BEQ") == 0 || strcmp(mnemonic, "BEQ.L") == 0 || strcmp(mnemonic, "BNE") == 0 || strcmp(mnemonic, "BNE.L") == 0 || strcmp(mnemonic, "BCC") == 0 || strcmp(mnemonic, "BCC.L") == 0 From b7454348e5ef19ca5b35a9f0d4adc79a86c13484 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 6 Mar 2026 23:02:51 -0600 Subject: [PATCH 123/155] 6502: Added pointer alias for further optimization --- cpu6502.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/cpu6502.c b/cpu6502.c index 0217f23..4511095 100644 --- a/cpu6502.c +++ b/cpu6502.c @@ -17,6 +17,12 @@ #define REG_NONE 0 #define REG_ALL (REG_ACC | REG_X | REG_Y | REG_TEMP) +/* + ** Character used internally to mark precalculated array[index] addresses + */ +#define INDEX_ADD '[' +#define INDEX_ADD_STRING "[" + static char temp2[MAX_LINE_SIZE]; static char cpu6502_line[MAX_LINE_SIZE]; @@ -27,6 +33,7 @@ static char cpu6502_x_value[MAX_LINE_SIZE]; static char cpu6502_x_alias[MAX_LINE_SIZE]; static char cpu6502_y_value[MAX_LINE_SIZE]; static char cpu6502_y_alias[MAX_LINE_SIZE]; +static char cpu6502_pointer_alias[MAX_LINE_SIZE]; static int cpu6502_flag_z_valid; static void cpu6502_emit_line(void); @@ -50,8 +57,10 @@ void cpu6502_label(char *label) cpu6502_a_value[0] = '\0'; cpu6502_a_alias[0] = '\0'; cpu6502_x_value[0] = '\0'; + cpu6502_x_alias[0] = '\0'; cpu6502_y_value[0] = '\0'; cpu6502_y_alias[0] = '\0'; + cpu6502_pointer_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } @@ -63,8 +72,10 @@ void cpu6502_empty(void) cpu6502_a_value[0] = '\0'; cpu6502_a_alias[0] = '\0'; cpu6502_x_value[0] = '\0'; + cpu6502_x_alias[0] = '\0'; cpu6502_y_value[0] = '\0'; cpu6502_y_alias[0] = '\0'; + cpu6502_pointer_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } @@ -247,6 +258,7 @@ void cpu6502_1op(char *mnemonic, char *operand) cpu6502_x_alias[0] = '\0'; cpu6502_y_value[0] = '\0'; cpu6502_y_alias[0] = '\0'; + cpu6502_pointer_alias[0] = '\0'; cpu6502_flag_z_valid = 0; } else if (strcmp(mnemonic, "STA") == 0) { if (strchr(operand, ',') != NULL) { @@ -818,6 +830,14 @@ void cpu6502_node_generate(struct node *node, int decision) } cpu6502_node_generate(node->left, 0); cpu6502_1op("JSR", "_peek8"); + node = node->left; + if (node->type == N_PLUS16 && node->left->type == N_ADDR && node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { /* addr + var : addr - var */ + node_get_label(node->left, 0); + strcpy(cpu6502_pointer_alias, temp); + strcat(cpu6502_pointer_alias, INDEX_ADD_STRING); + node_get_label(node->right->left, 0); + strcat(cpu6502_pointer_alias, temp); + } break; case N_PEEK16: /* Load 16-bit content */ if (node->left->type == N_ADDR) { /* Optimize address */ @@ -1284,7 +1304,26 @@ void cpu6502_node_generate(struct node *node, int decision) sprintf(p, "%d)>>8", node->right->value); cpu6502_1op("LDY", temp); break; - } else if (node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { + } else if (node->right->type == N_EXTEND8 && node->right->left->type == N_LOAD8) { /* addr + var : addr - var */ + char *p; + + if ((p = strchr(cpu6502_pointer_alias, INDEX_ADD)) != NULL) { /* If there is an index saved... */ + node_get_label(node->right->left, 0); + if (strcmp(temp, p + 1) == 0) { /* ...and it is the same index */ + *p = '\0'; + node_get_label(node->left, 0); + if (strcmp(cpu6502_pointer_alias, temp) == 0) { + cpu6502_1op("LDA", "pointer"); + cpu6502_1op("LDY", "pointer+1"); + node_get_label(node->left, 0); + strcpy(cpu6502_pointer_alias, temp); + strcat(cpu6502_pointer_alias, INDEX_ADD_STRING); + node_get_label(node->right->left, 0); + strcat(cpu6502_pointer_alias, temp); + break; + } + } + } node_get_label(node->left, 2); cpu6502_1op("LDA", temp); cpu6502_noop("CLC"); From 80502cfe5323ba600edc9dcfdf0f9f52f3470460 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 9 Mar 2026 18:57:16 -0600 Subject: [PATCH 124/155] MSX: Adjustments in joystick reading --- controller.asm | 5552 ++++++++++++++++++++++++++++++++++++++++++ controller.rom | Bin 0 -> 8192 bytes cvbasic.c | 46 +- cvbasic_epilogue.asm | 10 + cvbasic_prologue.asm | 91 +- 5 files changed, 5693 insertions(+), 6 deletions(-) create mode 100644 controller.asm create mode 100644 controller.rom diff --git a/controller.asm b/controller.asm new file mode 100644 index 0000000..0e053b0 --- /dev/null +++ b/controller.asm @@ -0,0 +1,5552 @@ + ; CVBasic compiler v0.9.2 Mar/06/2026 + ; Command: ./cvbasic --msx examples/controller.bas controller.asm + ; Created: Mon Mar 9 11:24:18 2026 + +COLECO: equ 0 +SG1000: equ 0 +MSX: equ 1 +KONAMI: equ 0 +FM_SUPPORT: equ 0 +SGM: equ 0 +SVI: equ 0 +SORD: equ 0 +MEMOTECH: equ 0 +EINSTEIN: equ 0 +CPM: equ 0 +PENCIL: equ 0 +PV2000: equ 0 +TI99: equ 0 +NABU: equ 0 +SMS: equ 0 + +CVBASIC_MUSIC_PLAYER: equ 0 +CVBASIC_COMPRESSION: equ 0 +CVBASIC_BANK_SWITCHING: equ 0 +CVBASIC_BANK_ROM_SIZE: equ 0 +COLECO_SPINNER: equ 0 + +BASE_RAM: equ $e000 ; Base of RAM +RAM_SIZE: equ $1380 ; Base of RAM +STACK: equ $f380 ; Base stack pointer +VDP: equ $98 ; VDP port (write) +VDPR: equ $98 ; VDP port (read) +PSG: equ $00 ; PSG port (write) + + ; + ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. + ; Added 16-bit multiply, division, modulo, and abs. + ; Added random generator. Added sound routines. + ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. + ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/14/2024. Added _sgn16. + ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. + ; Revision date: Apr/11/2024. Added support for formatting numbers. Added + ; support for Super Game Module. + ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. + ; Shorter mode setting subroutines. + ; Revision date: Apr/26/2024. Interruption handler saves current bank. + ; Revision date: Apr/27/2024. Music player now supports bank switching. + ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller + ; support with keyboard (code by SiRioKD) + ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. + ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. + ; Revision date: Jun/17/2024. Added SVI-328 support. + ; Revision date: Aug/01/2024. Added Sord M5 support. + ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech + ; support. + ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support + ; for Casio PV-2000. + ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, + ; and Casio PV-2000. + ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision + ; with flicker flag). + ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number + ; keys values were inverted. + ; Revision date: Nov/12/2024. Saves the VDP status. + ; Revision date: Feb/05/2026. Added support for spinners and roller controller + ; (Colecovision). + ; Revision date: Feb/09/2026. Added support for palette in MSX2. + ; Revision date: Feb/10/2026. Added support for sprites in MSX2 and 64K VRAM + ; access. + ; Revision date: Feb/26/2026. Faster CPYBLK, LDIRVM3, and FILVRM. + ; Revision date: Mar/09/2026. Corrections on joystick read for MSX. + ; + + ; + ; Resources: + ; * Z80 instructions timing: https://map.grauw.nl/resources/z80instr.php + ; * Use the Timing Z80+M1 for MSX and Colecovision (both insert one + ; wait state in each M1 cycle) + ; + ; Technical requirements: + ; * Minimum of 28 cycles between VDP writes for 3.58 mhz. systems. + ; * Minimum of 31 cycles between VDP writes for 4.00 mhz. systems. + ; * For SMS minimum of 28 cycles between VDP writes (3.58 mhz) + ; * For MSX2 (V9938) minimum of 23 cycles between VDP writes (3.58 mhz) + ; + ; Dependances: + ; * LDIRVM, assumed to keep DE unchanged (target VRAM address) + ; * For speed. Required by CPYBLK and LDIRVM3. + ; + + if COLECO+SG1000+SMS +JOYSEL: equ $c0 +KEYSEL: equ $80 + +JOY1: equ $fc-$20*(SG1000+SMS) +JOY2: equ $ff-$22*(SG1000+SMS) + endif + + if COLECO + org $8000 + if PENCIL + db "COPYRIGHT SOUNDIC" + jp START + jp nmi_handler + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + jp 0 ; rst $38 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + db "CVBASIC!POWERED BY!2024!" + else + db $55,$aa + dw 0 + dw 0 + dw 0 + dw 0 + dw START + + jp 0 ; rst $08 + jp 0 ; rst $10 + jp 0 ; rst $18 + jp 0 ; rst $20 + jp 0 ; rst $28 + jp 0 ; rst $30 + if COLECO_SPINNER + jp spinner_handler + else + jp 0 ; rst $38 + endif + jp nmi_handler + + if COLECO_SPINNER +spinner_handler: + PUSH AF + PUSH HL + LD A,$FF + LD (spinner_data),A + OUT (JOYSEL),A + PUSH AF + POP AF + LD HL,spinner_data+1 + IN A,(JOY1) + BIT 4,A + JR NZ,.1 + BIT 5,A + JR NZ,$+4 + INC (HL) + DB $3E + DEC (HL) +.1: INC HL + IN A,(JOY2) + BIT 4,A + JR NZ,.2 + BIT 5,A + JR NZ,$+4 + INC (HL) + DB $3E + DEC (HL) +.2: POP HL + POP AF + EI + RETI + endif + endif + endif + if SG1000+SMS+SVI + org $0000 + di + ld sp,STACK + jp START + db $ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp 0 + db $ff,$ff,$ff,$ff,$ff + jp nmi_handler ; It should be called int_handler. + endif + if MSX + ORG $4000 + db "AB" + dw START + dw $0000 + dw $0000 + dw $0000 + dw $0000 + +WRTPSG: equ $0093 +RDPSG: equ $0096 + + endif + if SORD + ORG $2000 + db $02 ; Avoid checking $4000 + dw START ; Start address. + dw $002e ; Prestart address (just point to RET in BIOS). + endif + if PV2000 + ORG $C000 + jp START + endif + + if MEMOTECH + if CPM + org $0100 + else + org $40fc + dw rom_start + dw rom_end-rom_start + endif +rom_start: + jp START + db 0,0,0,0,0 + dw nmi_handler + dw null_vector + dw null_vector + dw rom_start + +null_vector: + ei + reti + endif + if EINSTEIN + org $0100 +rom_start: + jp START + db 0,0,0,0,0 + dw $0000 + dw $0000 + dw $0000 + dw $0000 + endif + if NABU + if CPM + org $0100 + else + org $140d + endif + nop + nop + nop + jp START + times $100-($&255) db $ff +nabu_int: + dw null_vector + dw null_vector + dw keyboard_handler + dw nmi_handler + dw null_vector + dw null_vector + dw null_vector + dw null_vector + +null_vector: + ei + reti + endif + + if SVI +WRTPSG: + out ($88),a + push af + ld a,e + out ($8c),a + pop af + ret + +RDPSG: + out ($88),a + push af + pop af + in a,($90) + ret + endif + + if EINSTEIN +WRTPSG: + out ($02),a + push af + ld a,e + out ($03),a + pop af + ret + +RDPSG: + out ($02),a + push af + pop af + in a,($02) + ret + endif + + if NABU +WRTPSG: + out ($41),a + push af + ld a,e + out ($40),a + pop af + ret + +RDPSG: + out ($41),a + push af + pop af + in a,($40) + ret + endif + + if PV2000 + ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) +WRTVDP: + ld a,b + ld (VDP+1),a + ld a,c + or $80 + ld (VDP+1),a + ret + +SETWRT: + ld a,l + ld (VDP+1),a + ld a,h + or $40 + ld (VDP+1),a + ret + +SETRD: + ld a,l + ld (VDP+1),a + ld a,h + and $3f + ld (VDP+1),a + ret + +WRTVRM: + push af + call SETWRT + pop af + ld (VDP),a + ret + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + ld a,(VDP) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) + inc c + inc b +.1: ld (VDP),a ; 13 14 + dec c ; 4 5 + jr nz,.1 ; 12 13 + ; -- -- + ; 29 32 + djnz .1 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + ld a,(VDP) + ld (de),a + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + EX DE,HL + CALL SETWRT + EX DE,HL + DEC BC + INC C + LD A,B + LD B,C + INC A + LD C,A +.1: + LD A,(HL) ; 7 8 + LD (VDP),A ; 13 14 + INC HL ; 6 7 + DJNZ .1 ; 13 14 + DEC C ; 4 5 + JP NZ,.1 ; 10 11 + RET + else + ; Normal platforms with VDP connected via ports (IORQ) +WRTVDP: + if COLECO_SPINNER + di + endif + ld a,b + out (VDP+1),a + ld a,c + or $80 + out (VDP+1),a + if COLECO_SPINNER + ei + endif + ret + +SETWRT: + if COLECO_SPINNER + di + endif + if MSX&2 + ld a,h + rlca + rlca + and 3 + out (VDP+1),a + ld a,$8e + out (VDP+1),a + ld a,l + out (VDP+1),a + ld a,h + and $3f + or $40 + out (VDP+1),a + else + ld a,l + out (VDP+1),a + ld a,h + or $40 + out (VDP+1),a + endif + if COLECO_SPINNER + ei + endif + ret + +SETRD: + if COLECO_SPINNER + di + endif + if MSX&2 + ld a,h + rlca + rlca + and 3 + out (VDP+1),a + ld a,$8e + out (VDP+1),a + endif + ld a,l + out (VDP+1),a + ld a,h + and $3f + out (VDP+1),a + if COLECO_SPINNER + ei + endif + ret + +WRTVRM: + push af + call SETWRT + pop af + out (VDP),a + ret + + if SG1000+SMS + db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Located at $0066 + ei ; NMI handler (pause button) + retn + endif + +RDVRM: + push af + call SETRD + pop af + ex (sp),hl + ex (sp),hl + in a,(VDPR) + ret + +FILVRM: + push af + call SETWRT + pop af + dec bc ; T-states (normal / M1) + inc c + inc b + if MSX+COLECO +.1: out (VDP),a ; 12 + dec c ; 5 + jp nz,.1 ; 11 + ; -- + ; 28 + else +.1: out (VDP),a ; 11 12 + nop ; 4 5 + dec c ; 4 5 + jr nz,.1 ; 12 13 + ; -- -- + ; 31 35 + endif + djnz .1 + ret + +LDIRMV: + ex de,hl + call SETRD + ex (sp),hl + ex (sp),hl +.1: + in a,(VDP) + ld (de),a + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + inc de + dec bc + ld a,b + or c + jp nz,.1 + ret + +LDIRVM: + ex de,hl + call SETWRT + ex de,hl + dec bc + inc c + ld a,b + ld b,c + inc a + ld c,VDP +.1: + if MSX&2 + otir ; 23 cycles per byte. + else + if SORD+SMS + nop + endif + if SG1000+MEMOTECH+EINSTEIN + nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. + nop + endif + outi ; 18 + jp nz,.1 ; 11 + endif + dec a + jp nz,.1 + ret + endif + + if SMS + else +LDIRVM3: + call .1 + call .1 +.1: push hl + push bc + call LDIRVM + pop bc + ld a,d + add a,8 + ld d,a + pop hl + ret + endif + +DISSCR: + call nmi_off + ld bc,$a201 + call WRTVDP + jp nmi_on + +ENASCR: + call nmi_off + ld bc,$e201 + call WRTVDP + jp nmi_on + +CPYBLK: + pop hl + ex af,af' + pop af + ld b,a + pop af + ld c,a + pop de + ex (sp),hl + call nmi_off +.1: push bc + push hl + ld b,0 + call LDIRVM + ex de,hl + if SMS + ld bc,$0040 + else + ld bc,$0020 + endif + add hl,bc + ex de,hl + pop hl + ex af,af' + ld c,a + ld b,0 + add hl,bc + ex af,af' + pop bc + djnz .1 + jp nmi_on + +nmi_off: + if COLECO+PV2000 + push hl + ld hl,mode + set 0,(hl) + pop hl + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + di + endif + ret + +nmi_on: + if COLECO+PV2000 + push af + push hl + ld hl,mode + res 0,(hl) + nop + bit 1,(hl) + jp nz,nmi_handler.0 + pop hl + pop af + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + ei + endif + ret + + if COLECO +keypad_table: + db $0f,$08,$04,$05,$0c,$07,$0b,$02 + db $0d,$0a,$00,$09,$03,$01,$06,$0f + endif + +cls: + if SMS + ld hl,$3800 + ld (cursor),hl + di + call SETWRT +.1: ld a,$20 ; 7 + out (VDP),a ; 11 + inc hl ; 6 + inc hl ; 6 + ld a,$00 ; 7 + out (VDP),a ; 11 + ld a,h ; 4 + cp $3e ; 7 + jp nz,.1 ; 10 + ei + ret + else + ld hl,$1800 + ld (cursor),hl + ld bc,$0300 + ld a,$20 + call nmi_off + call FILVRM + jp nmi_on + endif + +print_string: + ld c,a + ld b,0 + ld de,(cursor) + if SMS + ld a,d + and $07 + or $38 + ld d,a + else + ld a,d + and $07 + or $18 + ld d,a + endif + push de + push bc + call nmi_off + if SMS + ex de,hl +.1: ld a,(de) + call WRTVRM + inc de + inc hl + xor a + call WRTVRM + inc hl + dec bc + ld a,b + or c + jp nz,.1 + else + call LDIRVM + endif + call nmi_on + pop bc + pop hl + add hl,bc + if SMS + add hl,bc + endif + ld (cursor),hl + ret + +print_number: + ld b,0 + call nmi_off +print_number5: + ld de,10000 + call print_digit +print_number4: + ld de,1000 + call print_digit +print_number3: + ld de,100 + call print_digit +print_number2: + ld de,10 + call print_digit +print_number1: + ld de,1 + ld b,e + call print_digit + jp nmi_on + +print_digit: + ld a,$2f + or a +.2: inc a + sbc hl,de + jp nc,.2 + add hl,de + cp $30 + jr nz,.3 + ld a,b + or a + ret z + dec a + jr z,.4 + ld a,c + jr print_char +.4: + ld a,$30 +.3: ld b,1 + +print_char: + push hl + ld hl,(cursor) + ex af,af' + ld a,h + and $07 + if SMS + or $38 + else + or $18 + endif + ld h,a + ex af,af' + call WRTVRM + inc hl + if SMS + xor a + call WRTVRM + inc hl + endif + ld (cursor),hl + pop hl + ret + +define_char: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + di + call LDIRVM + ei + ret + else + call nmi_off + ld a,(mode) + and 8 + jr nz,.1 + call LDIRVM3 + jp nmi_on + +.1: call LDIRVM + jp nmi_on + endif + +define_color: + if SMS + ret + else + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d + call nmi_off + call LDIRVM3 + jp nmi_on + endif + +define_sprite: + ex de,hl + ld l,a + ld h,0 + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ld c,l + ld b,h + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + if SMS + set 1,h + else + ld h,$07 + endif + add hl,hl ; x8 + add hl,hl ; x16 + add hl,hl ; x32 + if SMS + add hl,hl ; x64 + endif + ex de,hl + call nmi_off + call LDIRVM + jp nmi_on + endif + +update_sprite: + if SMS + pop bc ; Pop return address. + pop de ; 3th. argument in D (Y-coordinate) + ld e,a ; 4th. argument in E (frame) + pop af ; 2nd. argument in A (X-coordinate) + pop hl ; 1st. argument in H (sprite number) + push bc ; Push return address. + ld l,h + res 7,l + res 6,l + ld h,sprites>>8 + ld (hl),a + sla l + set 7,l + ld (hl),d + inc l + ld (hl),e + else + pop bc + ld (sprite_data+3),a + pop af + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + ld d,sprites>>8 + add a,a + add a,a + if SORD + or $80 + endif + ld e,a + ld hl,sprite_data + ldi + ldi + ldi + ldi + endif + ret + + ; Fast 16-bit multiplication. +_mul16: + ld b,h + ld c,l + ld a,16 + ld hl,0 +.1: + srl d + rr e + jr nc,.2 + add hl,bc +.2: sla c + rl b + dec a + jp nz,.1 + ret + + ; 16-bit signed modulo. + ; hl = hl % de +_mod16s: + ld a,h + or a + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _mod16 + pop af + ret p + jp _neg16 + + ; 16-bit signed division. + ; hl = hl / de +_div16s: + ld a,h + xor d + push af + bit 7,h + call nz,_neg16 + ex de,hl + bit 7,h + call nz,_neg16 + ex de,hl + call _div16 + pop af + ret p + jp _neg16 + +_abs16: + bit 7,h + ret z +_neg16: + ld a,h + cpl + ld h,a + ld a,l + cpl + ld l,a + inc hl + ret + + ; Fast 16-bit division. + ; hl = hl / de +_div16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + rl c + rl b + ld h,b + ld l,c + ret + + ; Fast 16-bit modulo. +_mod16: + ld b,h + ld c,l + ld hl,0 + ld a,16 +.1: + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,.2 + add hl,de +.2: + ccf + dec a + jp nz,.1 + ret + +_sgn16: + ld a,h + or l + ret z + bit 7,h + ld hl,$ffff + ret nz + inc hl + inc hl + ret + + ; Random number generator. + ; From my game Mecha Eight. +random: + ld hl,(lfsr) + ld a,h + or l + jr nz,.0 + ld hl,$7811 +.0: ld a,h + and $80 + ld b,a + ld a,h + and $02 + rrca + rrca + xor b + ld b,a + ld a,h + and $01 + rrca + xor b + ld b,a + ld a,l + and $20 + rlca + rlca + xor b + rlca + rr h + rr l + ld (lfsr),hl + ret + +sn76489_freq: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld b,a + ld a,l + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + and $3f + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_vol: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + cpl + and $0f + or b + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +sn76489_control: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + and $0f + or $e0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + ret + +ay3_reg: + if COLECO + push af + ld a,b + out ($50),a + pop af + out ($51),a + ret + endif + if SG1000+SORD+SMS+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,a + ld a,b + jp WRTPSG + endif + +ay3_freq: + if COLECO + out ($50),a + push af + ld a,l + out ($51),a + pop af + inc a + out ($50),a + push af + ld a,h + and $0f + out ($51),a + pop af + ret + endif + if SG1000+SMS+SORD+MEMOTECH+PV2000 + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld e,l + call WRTPSG + ld e,h + inc a + jp WRTPSG + endif + + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ; Required for SG1000 and Sega Master System as both don't have a BIOS + ; Required for SVI because we don't have access to BIOS in cartridge. + ; Required for Sord M5 because it doesn't provide an ASCII charset. + ; Required for Memotech/Einstein because CP/M uses the memory. + ; My personal font for TMS9928. + ; + ; Patterned after the TMS9928 programming manual 6x8 letters + ; with better lowercase letters, also I made a proper + ; AT sign. + ; +font_bitmaps: + db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space + db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! + db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " + db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # + db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ + db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % + db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & + db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' + db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( + db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) + db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * + db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + + db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , + db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - + db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . + db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / + db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 + db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 + db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 + db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 + db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 + db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 + db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 + db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 + db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 + db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 + db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : + db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; + db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < + db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = + db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > + db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? + db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ + db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A + db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B + db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C + db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D + db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E + db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F + db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G + db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H + db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I + db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J + db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K + db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L + db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M + db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N + db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O + db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P + db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q + db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R + db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S + db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T + db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U + db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V + db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W + db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X + db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y + db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z + db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ + db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ + db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] + db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E + db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ + db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 + db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a + db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b + db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c + db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d + db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e + db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f + db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g + db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h + db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i + db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j + db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k + db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l + db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m + db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n + db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o + db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p + db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q + db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r + db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s + db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t + db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u + db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v + db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w + db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x + db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y + db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z + db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { + db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | + db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } + db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e + db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f + endif + + if MSX&2 +palette_default: + ld hl,msx2_default_palette +palette_load: + ld bc,$0010 + di + call WRTVDP + ld bc,32*256+VDP+2 + otir + ei + ret + +msx2_default_palette: + dw $000,$000,$611,$733,$117,$327,$151,$627 + dw $171,$373,$661,$664,$411,$265,$555,$777 + +define_sprite_color: + ex de,hl + add a,a ; x2 + add a,a ; x4 + add a,a ; x8 + add a,a ; x16 + ld c,a + ld b,0 + rl b + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ld h,$40/2 + add hl,hl ; x16 + ex de,hl + di + call LDIRVM + ei + ret + +update_sprite2: + pop bc + ld (sprite_data+2),a + pop af + ld (sprite_data+1),a + pop af + ld (sprite_data),a + pop af + ; A = Sprite number + push bc + ld d,sprites>>8 + add a,a + add a,a + ld e,a + ld hl,sprite_data + ldi + ldi + ldi + ret + + ; + ; Register that must be set for V9938 (MSX2) because larger VRAM: + ; Reg. 2 = 0 A16 A15 A14 A13 A12 A11 A10 Pattern name table. + ; Reg. 3 = A13 1 1 1 1 1 1 1 Color table (reg. D) + ; Reg. 10= 0 0 0 0 0 A16 A15 A14 Color table high bits. + ; Reg. 4 = 0 0 A16 A15 A14 A13 1 1 Bitmap table (reg. E) + ; Reg. 5 = A14 A13 A12 A11 A10 A9 1 1 Sprite attribute table... + ; Reg. 11= 0 0 0 0 0 0 A16 A15 ...and high bits. + ; Reg. 6 = 0 0 A16 A15 A14 A13 A12 A11 Sprite pattern generator + ; +mode_4: + ld hl,mode + res 3,(hl) + set 4,(hl) + ld bc,$0400 ; Normal mode but with enhanced sprites enabled. + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld bc,$000a ; Reg. 10 (high bits of color table) + call WRTVDP + ; The value $84 seems logical but it makes colors + ; for sprites 0-7 replicate in sprites 8-15, + ; 16-23, and 24-31. Not described in Yamaha docs, + ; but emulated by OpenMSX and BlueMSX. + ld bc,$8705 ; $4200 for sprite attribute table... + call WRTVDP ; ...so sprite colors appear at $4000-$41ff. + ld bc,$000b ; Reg. 11 (high bits of sprite attribute table) + call WRTVDP + ld hl,($0004) + inc h + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites + endif + + if SMS +palette_default: + ld hl,sms_default_palette +palette_load: + push hl + di + ld hl,$c000 + call SETWRT + pop hl + ld bc,32*256+VDP + outi + jp nz,$-2 + ei + ret + + ; TMS9118-alike palette +sms_default_palette: + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f + +mode_4: + di + ld bc,$0400 + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) + call WRTVDP + ld bc,$ff03 ; Not used (required value for SMS1) + call WRTVDP + ld bc,$0704 ; Not used (required value for SMS1) + call WRTVDP + ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) + call WRTVDP + ld bc,$0706 ; $2000 for sprites bitmaps (or $03 for $0000) + call WRTVDP + ld bc,$0007 + call WRTVDP + ld bc,$0008 ; Background X scroll + call WRTVDP + ld bc,$0009 ; Background Y scroll + call WRTVDP + ld hl,$20*32 ; Point to space character bitmap + call SETWRT + ld hl,font_bitmaps + ld c,96 +.1: ld b,8 +.2: ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + ld a,(hl) + out (VDP),a + inc hl + djnz .2 + dec c + jp nz,.1 + ei + call cls + di + ld hl,$3f00 + ld bc,$0040 + ld a,$e0 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,63 + ld (hl),$e0 + ldir + ei + call palette_default + jp ENASCR + + else +vdp_generic_mode: + call nmi_off + call WRTVDP + ld bc,$a201 + call WRTVDP + ld bc,$0602 ; $1800 for pattern table. + call WRTVDP + ld b,d + ld c,$03 ; for color table. + call WRTVDP + ld b,e + ld c,$04 ; for bitmap table + call WRTVDP + ld bc,$3605 ; $1b00 for sprite attribute table. + call WRTVDP + ld bc,$0706 ; $3800 for sprites bitmaps. + call WRTVDP + ld bc,$0107 + jp WRTVDP + +mode_0: + ld hl,mode + res 3,(hl) + res 4,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM3 + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + call cls +vdp_generic_sprites: + call nmi_off + ld a,(mode) + bit 4,a + ld hl,$1b00 + ld a,$d1 + jr z,$+6 + ld h,$42 + ld a,$e0 + ld bc,$0080 + call FILVRM + ld hl,sprites + ld de,sprites+1 + ld bc,127 + ld (hl),a + ldir + call nmi_on + jp ENASCR + +mode_1: + ld hl,mode + res 3,(hl) + res 4,(hl) + ld bc,$0200 + ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + ld hl,$0000 + ld bc,$1800 + xor a + call FILVRM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$1800 + ld a,$f0 + call FILVRM + call nmi_on + ld hl,$1800 +.1: call nmi_off + ld b,32 +.2: ld a,l + call WRTVRM + inc hl + djnz .2 + call nmi_on + ld a,h + cp $1b + jp nz,.1 + jp vdp_generic_sprites + +mode_2: + ld hl,mode + set 3,(hl) + res 4,(hl) + ld bc,$0000 + ld de,$8000 ; $2000 for color table, $0000 for bitmaps. + call vdp_generic_mode + if COLECO + if PENCIL + ld hl,($0013) + else + ld hl,($006c) + endif + ld de,-128 + add hl,de + endif + if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU + ld hl,font_bitmaps + endif + if MSX + ld hl,($0004) + inc h + endif + ld de,$0100 + ld bc,$0300 + call LDIRVM + call nmi_on + call nmi_off + ld hl,$2000 + ld bc,$0020 + ld a,$f0 + call FILVRM + call nmi_on + call cls + jp vdp_generic_sprites + endif + + if MSX +ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) +RSLREG: EQU $0138 ; Read slot status in A + + ; + ; Get slot mapping + ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) + ; A = Current slot selection status (CALL RSLREG) + ; +get_slot_mapping: + call rotate_slot + ld c,a + add a,$C1 ; EXPTBL + ld l,a + ld h,$FC + ld a,(hl) + and $80 ; Get expanded flag + or c + ld c,a + inc hl + inc hl + inc hl + inc hl + ld a,(hl) ; SLTTBL + call rotate_slot + rlca + rlca + or c ; A contains bit 7 = Marks expanded + ; bit 6 - 4 = Doesn't care + ; bit 3 - 2 = Secondary mapper + ; bit 1 - 0 = Primary mapper + ret + +rotate_slot: + push bc + dec b + inc b + jr z,.1 +.0: rrca + rrca + djnz .0 +.1: and 3 + pop bc + ret + + endif + +nmi_handler: + push af + push hl + ld hl,mode + bit 0,(hl) + jr z,.1 + set 1,(hl) + pop hl + pop af + retn + +.0: res 1,(hl) + +.1: push bc + push de + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fbf) + endif + if MSX + ld a,($bfff) + endif + push af + endif + if SORD+MEMOTECH + call ctc_reti + endif + if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU + in a,(VDPR+1) + ld (vdp_status),a + endif + + ; + ; Update of sprite attribute table + ; + if SMS + bit 2,(hl) + jr z,.4 + ld hl,$3f00 + call SETWRT + ld hl,sprites + ld bc,$4000+VDP + outi + jp nz,$-2 + ld hl,$3f80 + call SETWRT + ld hl,sprites+128 + ld bc,$8000+VDP + outi + jp nz,$-2 + jr .5 + +.4: ld hl,$3f00 + call SETWRT + ld a,(flicker) + inc a + and $3f + ld (flicker),a + ld l,a + ld h,sprites>>8 + ld bc,$4000+VDP + ld de,6 + outi + add hl,de + res 6,l + jp nz,$-5 + ld hl,$3f80 + call SETWRT + ld a,(flicker) + add a,a + or $80 + ld l,a + ld bc,$8000+VDP + ld de,12 + ld h,sprites>>8 + outi + nop + nop + nop + outi + add hl,de + set 7,l + jp nz,$-12 +.5: + else + ld bc,$8000+VDP + bit 2,(hl) + jr z,.4 + bit 4,(hl) + ld hl,$1b00 + jr z,$+4 +.10: + ld h,$42 + call SETWRT + ld hl,sprites +.7: + if MSX&2 + outi + outi + outi + outi + jp nz,.7 + else + if PV2000 + ld a,(hl) + ld (VDP),a + inc hl + djnz .7 + else + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp nz,.7 + endif + endif + jr .5 + +.4: + bit 4,(hl) + ld hl,$1b00 + jr nz,.10 ; No flicker sprites in MSX2 (MODE 4) + call SETWRT + ld a,(flicker) + add a,$04 + ld (flicker),a + ld de,24 + ld b,128 + ld l,a + if SORD + else + ld h,sprites>>8 + endif +.6: + if SORD + set 7,l + ld h,sprites>>8 + else + res 7,l + endif + if PV2000 + ld a,(hl) ; 7 8 + ld (VDP),a ; 13 14 + inc hl ; 6 7 + dec b ; 4 5 + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + ld a,(hl) + ld (VDP),a + inc hl + dec b + else + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + outi + jp $+3 + if MEMOTECH+EINSTEIN+SG1000 + nop + nop + endif + endif + add hl,de + jp nz,.6 +.5: + endif + + if COLECO + if COLECO_SPINNER + DI + endif + out (JOYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + or $b0 + ld b,a + in a,(JOY2) + if COLECO_SPINNER + EI + endif + or $b0 + ld c,a + + if COLECO_SPINNER + DI + endif + out (KEYSEL),a + ex (sp),hl + ex (sp),hl + in a,(JOY1) + ld d,a + in a,(JOY2) + if COLECO_SPINNER + EI + endif + ld e,a + + ld a,d + rlca + or $7f + and b + cpl + ld (joy1_data),a + + ld a,e + rlca + or $7f + and c + cpl + ld (joy2_data),a + + ld a,d + and $0f + ld c,a + ld b,0 + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key1_data),a + + ld a,e + and $0f + ld c,a + ld hl,keypad_table + add hl,bc + ld a,(hl) + ld (key2_data),a + endif + if SG1000+SMS + ld a,$07 + out ($de),a + ld b,$ff + in a,(JOY1) + ld h,a + in a,(JOY2) + ld l,a + in a,($de) + cp 7 + jp nz,.sg1000 + + ld a,$00 + out ($de),a + in a,($dc) + rra + ld c,1 + jr nc,.sg1 + in a,($dd) + rra + ld c,8 + jr nc,.sg1 + ld a,$01 + out ($de),a + in a,($dc) + rra + ld c,2 + jr nc,.sg1 + in a,($dd) + rra + ld c,9 + jr nc,.sg1 + ld a,$02 + out ($de),a + in a,($dc) + rra + ld c,3 + jr nc,.sg1 + in a,($dd) + rra + ld c,0 + jr nc,.sg1 + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a + ld c,10 + jr z,.sg1 + rra + ld c,4 + jr nc,.sg1 + ld a,$04 + out ($de),a + in a,($dc) + rra + ld c,5 + jr nc,.sg1 + ld a,$05 + out ($de),a + in a,($dc) + bit 6,a + ld c,11 + jr z,.sg1 + rra + ld c,6 + jr nc,.sg1 + ld a,$06 + out ($de),a + in a,($dc) + rra + ld c,7 + jr nc,.sg1 + ld c,15 +.sg1: ld a,c + ld (key1_data),a + + ld a,$04 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard down. + jr nz,$+4 + res 1,h + ld a,$05 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard left. + jr nz,$+4 + res 2,h + ld a,$06 + out ($de),a + in a,($dc) + bit 5,a ; Keyboard right. + jr nz,$+4 + res 3,h + bit 6,a ; Keyboard up. + jr nz,$+4 + res 0,h + ld a,$02 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Ins + jr nz,$+4 + res 4,h + ld a,$03 + out ($de),a + in a,($dc) + bit 4,a ; Keyboard Del + jr nz,$+4 + res 5,h +.sg1000: + bit 0,h + jr nz,$+4 + res 0,b + bit 1,h + jr nz,$+4 + res 2,b + bit 2,h + jr nz,$+4 + res 3,b + bit 3,h + jr nz,$+4 + res 1,b + bit 4,h + jr nz,$+4 + res 6,b + bit 5,h + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + + ld a,$ff + bit 6,h + jr nz,$+4 + res 0,a + bit 7,h + jr nz,$+4 + res 2,a + + bit 0,l + jr nz,$+4 + res 3,a + bit 1,l + jr nz,$+4 + res 1,a + bit 2,l + jr nz,$+4 + res 4,a + bit 3,l + jr nz,$+4 + res 5,a + cpl + ld (joy2_data),a + + endif + if MSX + ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php + ld a,15 + call RDPSG + and $d0 + or $4c ; Read joystick 2. + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + ld b,$ff + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + ld a,b + cpl + ld (joy2_data),a + + in a,($aa) + and $f0 + or $00 + out ($aa),a + in a,($a9) + cp $ff + ld c,$ff + jr nz,.key1 + in a,($aa) + and $f0 + or $01 + out ($aa),a + in a,($a9) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + in a,($aa) + and $f0 + or $07 + out ($aa),a + in a,($a9) + bit 5,a ; BS + ld c,$0a + jr z,.key2 + bit 7,a ; RET + ld c,$0b + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + in a,($aa) + and $f0 + or $08 + out ($aa),a + in a,($a9) + bit 5,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 6,a + jr nz,$+4 + res 2,b + bit 4,a + jr nz,$+4 + res 3,b + bit 0,a + jr nz,$+4 + res 6,b + in a,($aa) + and $f0 + or $04 + out ($aa),a + in a,($a9) + bit 2,a + jr nz,$+4 + res 7,b + + ld a,15 + call RDPSG + and $a0 + or $03 ; Read joystick 1. + ld e,a + ld a,15 + call WRTPSG + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + bit 4,a + jr nz,$+4 + res 6,b + bit 5,a + jr nz,$+4 + res 7,b + + ld a,b + cpl + ld (joy1_data),a + endif + if SVI + ld a,14 + call RDPSG + ld b,$ff + bit 4,a + jr nz,$+4 + res 0,b + bit 7,a + jr nz,$+4 + res 1,b + bit 5,a + jr nz,$+4 + res 2,b + bit 6,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 5,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy2_data),a + + ld a,$10 + out ($96),a + in a,($99) + cp $ff + ld c,$ff + jr nz,.key1 + ld a,$11 + out ($96),a + in a,($99) + and $03 + cp $03 + ld c,$07 + jr nz,.key1 + ld a,$16 + out ($96),a + in a,($99) + bit 6,a + ld c,$0b + jr z,.key2 + ld a,$15 + out ($96),a + in a,($99) + bit 6,a + ld c,$0a + jr z,.key2 + ld c,$0f + jr .key2 + +.key1: rra + inc c + jr c,.key1 +.key2: + ld a,c + ld (key1_data),a + + ld b,$ff + ld a,$15 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 0,b + ld a,$18 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 1,b + ld a,$17 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 2,b + ld a,$16 + out ($96),a + in a,($99) + bit 7,a + jr nz,$+4 + res 3,b + ld a,$18 + out ($96),a + in a,($99) + bit 0,a + jr nz,$+4 + res 6,b + ld a,$13 + out ($96),a + in a,($99) + bit 5,a + jr nz,$+4 + res 7,b + + ld a,14 + call RDPSG + bit 0,a + jr nz,$+4 + res 0,b + bit 3,a + jr nz,$+4 + res 1,b + bit 1,a + jr nz,$+4 + res 2,b + bit 2,a + jr nz,$+4 + res 3,b + + in a,($98) + bit 4,a + jr nz,$+4 + res 6,b + ld a,b + cpl + ld (joy1_data),a + endif + if SORD + ld bc,$ffff + in a,($37) ; Read joystick + rra + jr nc,$+4 + res 1,b + rra + jr nc,$+4 + res 0,b + rra + jr nc,$+4 + res 3,b + rra + jr nc,$+4 + res 2,b + rra + jr nc,$+4 + res 1,c + rra + jr nc,$+4 + res 0,c + rra + jr nc,$+4 + res 3,c + rra + jr nc,$+4 + res 2,c + in a,($31) + rra + jr nc,$+4 + res 6,b + rra + jr nc,$+4 + res 7,b + rra + rra + rra + jr nc,$+4 + res 6,c + rra + jr nc,$+4 + res 7,c + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + in a,($31) ; Keyboard 1-8 + or a + ld c,$00 + jr nz,.key3 + in a,($35) + bit 0,a ; 9 + ld c,$09 + jr nz,.key5 + bit 1,a ; 0 + ld c,$00 + jr nz,.key5 + bit 7,a ; Backspace + ld c,$0a + jr nz,.key5 + in a,($30) + bit 7,a ; Enter + ld c,$0b + jr nz,.key5 + ld c,$0f + jr .key5 + +.key3: rra + inc c + jr nc,.key3 +.key5: + ld a,c + ld (key1_data),a + + endif + if MEMOTECH + ld bc,$ffff + + ld a,$fb + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 0,b ; Up direction. + bit 3,a ; Y + jr nz,$+4 + res 0,c ; Up direction. + + ld a,$ef + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 1,b ; Right key. + ld a,$bf + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 2,b ; Down key. + ld a,$f7 + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a + jr nz,$+4 + res 3,b ; Left key. + ld a,$df + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 7,a ; Home key. + jr nz,$+4 + res 6,b ; Button 1 + + ld a,$7F + out ($05),a ; Select keyboard row. + ex (sp),hl + ex (sp),hl + in a,($05) ; Read keyboard data. + bit 2,a ; B + jr nz,$+4 + res 0,c ; Up key. + bit 1,a ; C + jr nz,$+4 + res 1,c ; Right key. + bit 3,a ; M + jr nz,$+4 + res 2,c ; Down key. + bit 0,a ; Z + jr nz,$+4 + res 3,c ; Left key. + bit 5,a ; - + jr nz,$+4 + res 7,c ; Button 2 for player 2. + bit 7,a ; - + jr nz,$+4 + res 7,b ; Button 2 for player 1. + in a,($06) ; Read keyboard data. + bit 0,a ; Space + jr nz,$+4 + res 6,c ; Button 1. + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$fe + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + ld b,1 + jr nc,.mt1 + rra + ld b,3 + jr nc,.mt1 + rra + ld b,5 + jr nc,.mt1 + rra + ld b,7 + jr nc,.mt1 + rra + ld b,9 + jr nc,.mt1 + ld a,$df + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + bit 6,a + ld b,11 + jr z,.mt1 + ld a,$fd + out ($05),a + ex (sp),hl + ex (sp),hl + in a,($05) + rra + rra + ld b,2 + jr nc,.mt1 + rra + ld b,4 + jr nc,.mt1 + rra + ld b,6 + jr nc,.mt1 + rra + ld b,8 + jr nc,.mt1 + rra + ld b,0 + jr nc,.mt1 + in a,($06) + rra + ld b,10 + jr nc,.mt1 + ld b,15 +.mt1: + ld a,b + ld (key1_data),a + endif + if EINSTEIN + ld bc,$ffff + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 0,b ; Up + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 4,a + jr nz,$+4 + res 1,b ; Right + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + jr nz,$+4 + res 2,b ; Down + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + jr nz,$+4 + res 3,b ; Left + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + jr nz,$+4 + res 6,b ; Fire + ld a,$0e + out ($02),a + ld a,$7f + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 0,a + jr nz,$+4 + res 7,b ; 2nd fire + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + + ld a,$0e + out ($02),a + ld a,$ef + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + rra + ld b,7 + jr nc,.te1 + rra + ld b,6 + jr nc,.te1 + rra + ld b,5 + jr nc,.te1 + rra + ld b,4 + jr nc,.te1 + rra + ld b,3 + jr nc,.te1 + rra + ld b,2 + jr nc,.te1 + rra + ld b,1 + jr nc,.te1 + ld a,$0e + out ($02),a + ld a,$f7 + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 3,a + ld b,8 + jr z,.te1 + bit 4,a + ld b,10 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fb + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 6,a + ld b,9 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fe + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 5,a + ld b,11 + jr z,.te1 + ld a,$0e + out ($02),a + ld a,$fd + out ($03),a + ex (sp),hl + ex (sp),hl + ld a,$0f + out ($02),a + in a,($02) + bit 7,a + ld b,0 + jr z,.te1 + ld b,15 +.te1: + ld a,b + ld (key1_data),a + endif + if PV2000 + ld bc,$ffff + ld a,7 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 0,b + bit 0,a + jr z,$+4 + res 3,b + ld a,6 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 1,a + jr z,$+4 + res 1,b + bit 0,a + jr z,$+4 + res 2,b + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + bit 0,a + jr z,$+4 + res 6,b + bit 1,a + jr z,$+4 + res 7,b + ld a,b + cpl + ld (joy1_data),a + ld a,c + cpl + ld (joy2_data),a + ld a,0 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + and $0f + ld b,$04 + jr nz,.pv1 + in a,($10) + and $0f + ld b,$08 + jr nz,.pv1 + ld a,8 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($10) + ld b,11 + bit 0,a + jr nz,.pv2 + ld a,4 + out ($20),a + ex (sp),hl + ex (sp),hl + in a,($20) + ld b,10 + bit 3,a + jr nz,.pv2 + in a,($10) + ld b,9 + bit 0,a + jr nz,.pv2 + ld b,0 + bit 3,a + jr nz,.pv2 + ld b,15 + jr .pv2 + +.pv1: rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b + rra + jr c,.pv2 + dec b +.pv2: ld a,b + ld (key1_data),a + endif + if NABU + ld a,(nabu_data0) + and $cf + ld (joy1_data),a + ld a,(nabu_data1) + and $cf + ld (joy2_data),a + ld a,(nabu_data2) + ld (key1_data),a + ld a,$0f + ld (nabu_data2),a + endif + + if CVBASIC_MUSIC_PLAYER + ld a,(music_mode) + or a + call nz,music_hardware + endif + + ld hl,(frame) + inc hl + ld (frame),hl + + ld hl,lfsr ; Make LFSR more random + inc (hl) + inc (hl) + inc (hl) + + if CVBASIC_MUSIC_PLAYER + ; + ; Music is played with a 50hz clock. + ; + ld a,(ntsc) + or a + jr z,.2 + ld a,(music_tick) + inc a + cp 6 + jr nz,$+3 + xor a + ld (music_tick),a + jr z,.3 +.2: + ld a,(music_mode) + or a + call nz,music_generate +.3: + endif + + if CVBASIC_BANK_SWITCHING + pop af + if COLECO + ld l,a + ld h,$ff + ld a,(hl) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + if KONAMI + ld ($8000),a + inc a + ld ($a000),a + else + ld ($7000),a + endif + endif + endif + pop de + pop bc + pop hl + if COLECO + in a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + if SG1000+SMS+SVI+NABU + pop af + ei + reti + endif + if MSX + pop af + ret + endif + if SORD+MEMOTECH + pop af + ei + ret + +ctc_reti: + reti + endif + if EINSTEIN + pop af + ret + endif + if PV2000 + ld a,(VDP+1) + ld (vdp_status),a + pop af + retn + endif + + if NABU +keyboard_handler: + push af + push bc + push hl + in a,($90) + ld c,a + cp $0d ; Enter + ld a,11 + jr z,.8 + ld a,c + cp $7f ; Del + ld a,10 + jr z,.8 + ld a,c + cp $30 + jr c,.7 + cp $3a + jr nc,.7 + sub $30 +.8: ld (nabu_data2),a + jr .1 +.7: + cp $a0 ; Is it data for joystick? + jr c,.2 + cp $c0 + jr c,.joystick ; Yes, jump. +.2: + ld hl,nabu_data0 + cp $80 + jr nz,.3 + res 4,(hl) ; Now data for joystick 1. + jr .1 +.3: + cp $81 + jr nz,.4 + set 4,(hl) ; Now data for joystick 2. + jr .1 +.4: + cp $e0 ; Keys with up/down event? + jr c,.1 ; No, jump. + and $0f ; Arrow right + ld b,2 + jr z,.5 + dec a ; Arrow left + ld b,8 + jr z,.5 + dec a ; Arrow up + ld b,1 + jr z,.5 + dec a ; Arrow down + ld b,4 + jr z,.5 + dec a ; |||> + ld b,$80 + jr z,.5 + dec a ; <||| + ld b,$40 + jr nz,.1 +.5: bit 4,c + jr nz,.6 ; Jump if depress event. + ld a,(hl) + or b ; Key pressed. + ld (hl),a + jr .1 + +.6: + ld a,b + cpl + and (hl) ; Key depressed. + ld (hl),a + jr .1 + +.joystick: + ld hl,nabu_data0 + bit 4,(hl) + jr z,$+5 + ld hl,nabu_data1 + ld b,$00 + bit 3,c + jr z,$+4 + set 0,b + bit 2,c + jr z,$+4 + set 1,b + bit 1,c + jr z,$+4 + set 2,b + bit 0,c + jr z,$+4 + set 3,b + bit 4,c + jr z,$+4 + set 6,b + ld (hl),b +.1: + pop hl + pop bc + pop af + ei + reti + endif + if SORD +wait: + ld de,(frame) +.1: + ld hl,(frame) + or a + sbc hl,de + jr z,.1 + ret + endif + if EINSTEIN +wait: + in a,(VDP+1) + nop + in a,(VDP+1) + bit 7,a + jr z,$-4 + ld (vdp_status),a + jp nmi_handler + endif + + ; + ; The music player code comes from my + ; game Princess Quest for Colecovision (2012) + ; + + ; + ; Init music player. + ; +music_init: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$9f + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$bf + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$df + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ff + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,$ec + out (PSG),a + if MEMOTECH + in a,($03) + endif + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 +MIX_BASE: equ $b8 + endif + if EINSTEIN+NABU +MIX_BASE: equ $78 + endif + if MSX+SVI+EINSTEIN+NABU + ld a,$08 + ld e,$00 + call WRTPSG + ld a,$09 + ld e,$00 + call WRTPSG + ld a,$0a + ld e,$00 + call WRTPSG + ld a,$07 + ld e,MIX_BASE + call WRTPSG + if FM_SUPPORT + ld a,7 + ld ($7000),a + ld a,(fm_slot) + inc a + call nz,init_fm + endif + endif + if SGM + ld b,$08 + xor a + call ay3_reg + ld b,$09 + call ay3_reg + ld b,$0a + call ay3_reg + ld b,$07 + ld a,$b8 + call ay3_reg + endif + if CVBASIC_MUSIC_PLAYER + else + ret + endif + + if CVBASIC_MUSIC_PLAYER + ld a,$ff + ld (audio_vol4hw),a + ld a,$ec + ld (audio_control),a + ld a,MIX_BASE + ld (audio_mix),a + ld hl,music_silence + ; + ; Play a music. + ; HL = Pointer to music. + ; +music_play: + call nmi_off + ld a,(hl) + ld (music_timing),a + inc hl + ld (music_start),hl + ld (music_pointer),hl + xor a + ld (music_note_counter),a + inc a + ld (music_playing),a + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffbf) + endif + if SG1000+SMS + ld a,($7fbf) + endif + if MSX + ld a,($bfff) + endif + ld (music_bank),a + endif + jp nmi_on + + ; + ; Generates music. + ; +music_generate: + ld a,(audio_mix) + and $c0 + or $38 + ld (audio_mix),a + xor a ; Turn off all the sound channels. + ld l,a + ld h,a + ld (audio_vol1),hl ; audio_vol1/audio_vol2 + ld (audio_vol3),a + ld a,$ff + ld (audio_vol4hw),a + + if MSX + if FM_SUPPORT + ld a,(fm_enabled) + or a + jp z,.fm1 + ld a,(fm_slot) + inc a + jp z,.fm1 + ld a,(music_note_counter) + or a + ld a,$07 + ld ($7000),a + jp nz,music_generate_fm.6 + ld hl,(music_pointer) +.fm15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if SG1000+SMS + ld ($fffe),a + endif + if MSX + if KONAMI + ld ($8000),a + inc a + ld ($a000),a + else + ld ($7000),a + endif + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.fm16 + ld e,d + ld d,0 + jr .fm17 + +.fm16: rlca + jr nc,.fm17 + ld e,0 +.fm17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.fm19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.fm19: cp -3 ; Repeat music? + ld a,$07 + ld ($7000),a + jp nz,music_generate_fm.0 + ld hl,(music_start) + jr .fm15 + +.fm1: + endif + endif + + ld a,(music_note_counter) + or a + jp nz,.6 + ld hl,(music_pointer) +.15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if COLECO + ld e,a + ld d,$ff + ld a,(de) + endif + if SG1000+SMS + ld ($fffe),a + endif + if MSX + if KONAMI + ld ($8000),a + inc a + ld ($a000),a + else + ld ($7000),a + endif + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.16 + ld e,d + ld d,0 + jr .17 + +.16: rlca + jr nc,.17 + ld e,0 +.17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.19: cp -3 ; Repeat music? + jp nz,.0 + ld hl,(music_start) + jr .15 + +.0: ld a,(music_timing) + and $3f ; Restart note time. + ld (music_note_counter),a + ld a,b + cp $3f ; Sustain? + jr z,.1 + rlca + rlca + and 3 + ld (music_instrument_1),a + ld a,b + and $3f + ld (music_note_1),a + xor a + ld (music_counter_1),a +.1: ld a,c + cp $3f + jr z,.2 + rlca + rlca + and 3 + ld (music_instrument_2),a + ld a,c + and $3f + ld (music_note_2),a + xor a + ld (music_counter_2),a +.2: ld a,d + cp $3f + jr z,.3 + rlca + rlca + and 3 + ld (music_instrument_3),a + ld a,d + and $3f + ld (music_note_3),a + xor a + ld (music_counter_3),a +.3: ld a,e + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + +.6: ld a,(music_note_1) + or a + jr z,.7 + ld bc,(music_instrument_1) + call music_note2freq + ld (audio_freq1),hl + ld (audio_vol1),a + +.7: ld a,(music_note_2) + or a + jr z,.8 + ld bc,(music_instrument_2) + call music_note2freq + ld (audio_freq2),hl + ld (audio_vol2),a + +.8: ld a,(music_note_3) + or a + jr z,.9 + ld bc,(music_instrument_3) + call music_note2freq + ld (audio_freq3),hl + ld (audio_vol3),a + +.9: ld a,(music_drum) + or a + jr z,.4 + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + cp 3 + jp nc,.4 +.10: ld a,5 + ld (audio_noise),a + call enable_drum + jr .4 + +.5: dec a ; 2 - Short durm. + jr nz,.11 + ld a,(music_counter_4) + or a + jp nz,.4 + ld a,8 + ld (audio_noise),a + call enable_drum + jr .4 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + cp 2 + jp c,.10 + cp b + jp c,.4 + dec a + dec a + cp b + jp c,.10 +.4: + ld a,(music_counter_1) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_1),a + + ld a,(music_counter_2) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_2),a + + ld a,(music_counter_3) + inc a + cp $18 + jp nz,$+5 + sub $08 + ld (music_counter_3),a + + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + + ; + ; Converts note to frequency. + ; Input: + ; A = Note (1-62). + ; B = Instrument counter. + ; C = Instrument. + ; Output: + ; HL = Frequency. + ; A = Volume. + ; +music_note2freq: + add a,a + ld e,a + ld d,0 + ld hl,music_notes_table + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ld a,c + or a + jp z,music_piano + dec a + jp z,music_clarinet + dec a + jp z,music_flute + ; + ; Bass instrument. + ; +music_bass: + add hl,hl + + ; + ; Piano instrument. + ; +music_piano: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ret + +.1: + db 12,11,11,10,10,9,9,8 + db 8,7,7,6,6,5,5,4 + db 4,4,5,5,4,4,3,3 + + ; + ; Clarinet instrument. + ; +music_clarinet: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + srl h + rr l + jp nc,.2 + inc hl +.2: ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + db 2,4,2,0 + db -2,-4,-2,0 + + db 13,14,14,13,13,12,12,12 + db 11,11,11,11,12,12,12,12 + db 11,11,11,11,12,12,12,12 + + ; + ; Flute instrument. + ; +music_flute: + ld a,b + add a,.1&255 + ld c,a + adc a,.1>>8 + sub c + ld b,a + ld a,(bc) + ld e,a + rlca + sbc a,a + ld d,a + add hl,de + ld a,c + add a,24 + ld c,a + jr nc,$+3 + inc b + ld a,(bc) + ret + +.1: + db 0,0,0,0 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + db 0,1,2,1 + + db 10,12,13,13,12,12,12,12 + db 11,11,11,11,10,10,10,10 + db 11,11,11,11,10,10,10,10 + + ; + ; Emit sound. + ; +music_hardware: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.7 ; Yes, jump. + ld a,(audio_vol2) + or a + jp nz,.7 + ld a,(audio_vol3) + or a + jp z,.7 + ld (audio_vol2),a + xor a + ld (audio_vol3),a + ld hl,(audio_freq3) + ld (audio_freq2),hl +.7: + ld hl,(audio_freq1) + ld a,h + cp 4 + ld a,$9f + jp nc,.1 + ld a,l + and $0f + or $80 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol1) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $90 +.1: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld hl,(audio_freq2) + ld a,h + cp 4 + ld a,$bf + jp nc,.2 + ld a,l + and $0f + or $a0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol2) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $b0 +.2: out (PSG),a + if MEMOTECH + in a,($03) + endif + + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.6 ; Yes, jump. + + ld hl,(audio_freq3) + ld a,h + cp 4 + ld a,$df + jp nc,.3 + ld a,l + and $0f + or $c0 + out (PSG),a + if MEMOTECH + in a,($03) + endif + add hl,hl + add hl,hl + add hl,hl + add hl,hl + ld a,h + out (PSG),a + if MEMOTECH + in a,($03) + endif + ld a,(audio_vol3) + add a,ay2sn&255 + ld l,a + adc a,ay2sn>>8 + sub l + ld h,a + ld a,(hl) + or $d0 +.3: out (PSG),a + if MEMOTECH + in a,($03) + endif + +.6: + ld a,(music_mode) + and 1 ; NO DRUMS? + ret z ; Yes, return. + + ld a,(audio_vol4hw) + inc a + jr z,.4 + ld a,(audio_noise) + cp 16 + ld b,$ec + jp c,.5 + ld b,$ed +; ld b,$ee +.5: ld a,(audio_control) + cp b + jr z,.4 + ld a,b + ld (audio_control),a + out (PSG),a + if MEMOTECH + in a,($03) + endif +.4: ld a,(audio_vol4hw) + out (PSG),a + if MEMOTECH + in a,($03) + endif + ret + endif + if MSX+SVI+EINSTEIN+NABU + ld a,(music_mode) + cp 4 ; PLAY SIMPLE? + jr c,.8 ; Yes, jump. + ld hl,audio_freq1 + ld bc,$0b00 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret +.8: + ld hl,audio_freq1 + ld bc,$0400 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + inc hl + inc hl + inc c + inc c + ld a,(music_mode) + and 1 + jr z,.9 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + jr .10 +.9: inc hl + inc c + inc hl + inc c +.10: ld b,$02 + ld a,c + ld e,(hl) + call WRTPSG + inc hl + inc c + djnz $-7 + ret + endif + + ; + ; Enable drum. + ; +enable_drum: + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ld a,$f5 + ld (audio_vol4hw),a + else + ld hl,audio_mix + ld a,(audio_vol2) + or a + jr nz,.1 + ld a,10 + ld (audio_vol2),a + set 1,(hl) +.1: res 4,(hl) + endif + ret + + ; + ; Musical notes table. + ; +music_notes_table: + ; Silence - 0 + dw 0 + if MEMOTECH+EINSTEIN + ; Values for 4.00 mhz. + ; 2nd octave - Index 1 + dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 + ; 3rd octave - Index 13 + dw 956,902,851,804,758,716,676,638,602,568,536,506 + ; 4th octave - Index 25 + dw 478,451,426,402,379,358,338,319,301,284,268,253 + ; 5th octave - Index 37 + dw 239,225,213,201,190,179,169,159,150,142,134,127 + ; 6th octave - Index 49 + dw 119,113,106,100,95,89,84,80,75,71,67,63 + ; 7th octave - Index 61 + dw 60,56,53 + else + ; Values for 3.58 mhz. + ; 2nd octave - Index 1 + dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 + ; 3rd octave - Index 13 + dw 855,807,762,719,679,641,605,571,539,508,480,453 + ; 4th octave - Index 25 + dw 428,404,381,360,339,320,302,285,269,254,240,226 + ; 5th octave - Index 37 + dw 214,202,190,180,170,160,151,143,135,127,120,113 + ; 6th octave - Index 49 + dw 107,101,95,90,85,80,76,71,67,64,60,57 + ; 7th octave - Index 61 + dw 53,50,48 + endif + + if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 + ; + ; Converts AY-3-8910 volume to SN76489 + ; +ay2sn: + db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 + endif + +music_silence: + db 8 + db 0,0,0,0 + db -2 + endif + + if CVBASIC_COMPRESSION +define_char_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + if SMS + add hl,hl ; x16 + add hl,hl ; x32 + endif + ex de,hl + if SMS + else + ld a,(mode) + and 8 + jp z,unpack3 + endif + jp unpack + + if SMS + else +define_color_unpack: + ex de,hl + pop af + pop hl + push af + add hl,hl ; x2 + add hl,hl ; x4 + add hl,hl ; x8 + ex de,hl + set 5,d +unpack3: + call .1 + call .1 +.1: + push de + push hl + call unpack + pop hl + pop de + ld a,d + add a,8 + ld d,a + ret + endif + + ; + ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) + ; +unpack: +; Initialization + ld a,(hl) + inc hl + exx + ld de,0 + add a,a + inc a + rl e + add a,a + rl e + add a,a + rl e + rl e + ld hl,.modes + add hl,de + ld c,(hl) + inc hl + ld b,(hl) + push bc + pop ix + ld e,1 + exx + ld iy,.loop + +; Main depack loop +.literal: + ex af,af' + call nmi_off + ld a,(hl) + ex de,hl + call WRTVRM + ex de,hl + inc hl + inc de + call nmi_on + ex af,af' +.loop: add a,a + call z,.getbit + jr nc,.literal + +; Compressed data + exx + ld h,d + ld l,e +.getlen: add a,a + call z,.getbitexx + jr nc,.lenok +.lus: add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr nc,.lenok + add a,a + call z,.getbitexx + adc hl,hl + ret c + add a,a + call z,.getbitexx + jr c,.lus +.lenok: inc hl + exx + ld c,(hl) + inc hl + ld b,0 + bit 7,c + jr z,.offsok + jp (ix) + +.mode6: add a,a + call z,.getbit + rl b +.mode5: add a,a + call z,.getbit + rl b +.mode4: add a,a + call z,.getbit + rl b +.mode3: add a,a + call z,.getbit + rl b +.mode2: add a,a + call z,.getbit + rl b + add a,a + call z,.getbit + jr nc,.offsok + or a + inc b + res 7,c +.offsok: inc bc + push hl + exx + push hl + exx + ld l,e + ld h,d + sbc hl,bc + pop bc + ex af,af' +.loop2: + call nmi_off + call RDVRM ; unpack + ex de,hl + call WRTVRM + ex de,hl ; 4 + call nmi_on + inc hl ; 6 + inc de ; 6 + dec bc ; 6 + ld a,b ; 4 + or c ; 4 + jr nz,.loop2 ; 10 + ex af,af' + pop hl + jp (iy) + +.getbit: ld a,(hl) + inc hl + rla + ret + +.getbitexx: + exx + ld a,(hl) + inc hl + exx + rla + ret + +.modes: + dw .offsok + dw .mode2 + dw .mode3 + dw .mode4 + dw .mode5 + dw .mode6 + + endif + +START: + if SVI+SG1000+SMS + im 1 + endif + if MEMOTECH +Z80_CTC: equ $08 + endif + if EINSTEIN +Z80_CTC: equ $28 + endif + + if EINSTEIN+MEMOTECH + di + im 2 + ld a,rom_start>>8 + ld i,a + ld a,$03 ; Reset Z80 CTC + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + out (Z80_CTC+0),a + out (Z80_CTC+1),a + out (Z80_CTC+2),a + out (Z80_CTC+3),a + ld a,$08 ; Interrupt vector offset + out (Z80_CTC+0),a + endif + if MEMOTECH + ld a,$25 ; Disable channel 2 interrupt. + out (Z80_CTC+2),a + ld a,$9c + out (Z80_CTC+2),a + ld a,$25 ; Disable channel 1 interrupt. + out (Z80_CTC+1),a + ld a,$9c + out (Z80_CTC+1),a + ld a,$c5 ; Enable channel 0 interrupt (VDP). + out (Z80_CTC+0),a + ld a,$01 + out (Z80_CTC+0),a + endif + if SORD + ld hl,$186c ; Disable handling of CTC Channel 1 interruption. + ld ($7002),hl + ld hl,$7040 + set 0,(hl) ; Avoid BIOS VDP handling. + endif + if SVI + ld e,$00 + ld a,$08 + call WRTPSG + ld a,$09 + call WRTPSG + ld a,$0A + call WRTPSG + ld a,$07 + ld e,$b8 + call WRTPSG + ld a,$92 ; Setup 8255 for keyboard/joystick reading. + out ($97),a + endif + if SG1000+SMS + ; Contributed by SiRioKD + ld a,$9F ; Turn off PSG + out (PSG),a + ld a,$BF + out (PSG),a + ld a,$DF + out (PSG),a + ld a,$FF + out (PSG),a + ld a,$92 ; Setup 8255 for SC3000. + out ($df),a + endif + if SG1000+SMS+SVI + ; Wait for VDP ready (around 1000 ms) + ld b,11 + ld de,$FFFF +.delay1: + ld hl,$39DE +.delay2: + add hl,de + jr c,.delay2 + djnz .delay1 + else + di + if COLECO_SPINNER + im 1 + endif + ld sp,STACK + endif + if NABU + im 2 + ld a,nabu_int>>8 + ld i,a + ld a,$03 ; Disable ROM + out ($00),a + ld a,$07 + out ($41),a + ld a,$78 ; Setup output ports and mixer. + out ($40),a + ld a,$0e + out ($41),a + ld a,$30 ; Enable video and keyboard. + out ($40),a + endif + if PV2000 + ld hl,nmi_handler + ld ($7499),hl + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + ld a,(VDPR+1) + ld bc,$8201 + call WRTVDP + else + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + in a,(VDPR+1) + ld bc,$8201 + call WRTVDP + endif + if CVBASIC_BANK_SWITCHING + if COLECO + ld a,($ffc0) ; Megacart + endif + if SG1000+SMS + ld a,1 ; Sega mapper + ld ($fffe),a + endif + if MSX + if KONAMI + ld a,1 + ld ($6000),a + inc a + ld ($8000),a + inc a + ld ($a000),a + else + ld a,1 ; ASCII 16K + ld ($7000),a + endif + endif + endif + if MEMOTECH+EINSTEIN+NABU + ld ix,(lfsr) + ld hl,ram_start + ld de,ram_start+1 + ld bc,ram_end-ram_start-1 + ld (hl),0 + ldir + ld (lfsr),ix + endif + if MSX+SVI+SMS + ld ix,(lfsr) + ld hl,BASE_RAM + ld de,BASE_RAM+1 + ld bc,RAM_SIZE-1 + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO+SG1000+SORD+PENCIL+PV2000 + ld hl,(lfsr) ; Save RAM trash for random generator. + ld de,BASE_RAM + xor a + ld (de),a + inc de + if PV2000 + bit 7,d ; 2.5K of RAM + endif + if PENCIL + bit 3,d ; 2K of RAM + endif + if COLECO+SG1000+SORD + bit 2,d ; 1K of RAM + endif + jp z,$-4 + ld (lfsr),hl + endif + + if SGM +WRITE_REGISTER: equ $1fd9 +FILL_VRAM: equ $1f82 +WRITE_VRAM: equ $1fdf + + ld b,$00 ; First step. +.0: ld hl,$2000 ; RAM at $2000. +.1: ld (hl),h ; Try to write a byte. + inc h + jp p,.1 ; Repeat until reaching $8000. + ld h,$20 ; Go back at $2000. +.2: ld a,(hl) ; Read back byte. + cp h ; Is it correct? + jr nz,.3 ; No, jump. + inc h + jp p,.2 ; Repeat until reaching $8000. + jp .4 ; Memory valid! + +.3: ld a,$01 ; Enable SGM + out ($53),a + inc b + bit 1,b ; Already enabled? + jr z,.0 ; No, test RAM again. + + ld bc,$0000 + call WRITE_REGISTER + ld bc,$0180 + call WRITE_REGISTER + ld bc,$0206 + call WRITE_REGISTER + ld bc,$0380 + call WRITE_REGISTER + ld bc,$0400 + call WRITE_REGISTER + ld bc,$0536 + call WRITE_REGISTER + ld bc,$0607 + call WRITE_REGISTER + ld bc,$070D + call WRITE_REGISTER + ld bc,$03F0 + ld de,$00E8 + ld hl,$158B ; Note! direct access to Colecovision ROM + call WRITE_VRAM + ld hl,$2000 + ld de,32 + ld a,$FD + call FILL_VRAM + ld hl,$1B00 + ld de,128 + ld a,$D1 + call FILL_VRAM + ld hl,$1800 + ld de,769 + ld a,$20 + call FILL_VRAM + ld bc,$0020 + ld de,$1980 + ld hl,.5 + call WRITE_VRAM + ld bc,$01C0 + call WRITE_REGISTER + jr $ + +.5: db " SUPER GAME MODULE NOT DETECTED " + +.4: + ld ix,(lfsr) + ld hl,$2000 + ld de,$2001 + ld bc,$5FFF + ld (hl),0 + ldir + ld (lfsr),ix + endif + if COLECO + ld a,($0069) + cp 50 + ld a,1 + jr nz,$+3 + dec a + endif + if SG1000+SMS+SVI+SORD+PV2000+NABU + ld a,1 ; Always NTSC. + endif + if MEMOTECH+EINSTEIN + ld a,0 ; Always PAL. + endif + if MSX + call RSLREG + ld b,1 ; $4000-$7fff + call get_slot_mapping + ld (cartridge_slot),a + ld h,$80 + call ENASLT ; Map into $8000-$BFFF + if FM_SUPPORT + ld a,$ff ; FM hasn't been discovered. + ld (fm_slot),a + ld a,7 + ld ($7000),a + call detect_fm + endif + ld a,($002b) + cpl + rlca + and $01 + endif + ld (ntsc),a + + call music_init + + xor a + ld (mode),a + if SMS + call mode_4 + else + call mode_0 + endif + + xor a + ld (joy1_data),a + ld (joy2_data),a + if NABU + ld (nabu_data0),a + ld (nabu_data1),a + endif + ld a,$0f + ld (key1_data),a + ld (key2_data),a + if NABU + ld (nabu_data2),a + endif + + if MSX + ld hl,nmi_handler + ld ($fd9b),hl + ld a,$c3 + ld ($fd9a),a + endif + if SORD + ld hl,nmi_handler + ld ($7006),hl + endif + if COLECO + if COLECO_SPINNER + ei + endif + endif + + ; CVBasic program start. + ; ' + ; ' Controller test + ; ' + ; ' by Oscar Toledo G. + ; ' https://nanochess.org/ + ; ' + ; ' Creation date: Aug/21/2024. + ; ' Revision date: Oct/15/2024. Solved wrong display for number key in 2nd controller. + ; ' Revision date: Nov/28/2025. Added support for Blue and Purple buttons (Super + ; ' Action Controller) + ; ' + ; + ; CONST left_x = 56 +const_LEFT_X: equ $0038 + ; CONST left_y = 40 +const_LEFT_Y: equ $0028 + ; CONST right_x = 160 +const_RIGHT_X: equ $00a0 + ; CONST right_y = 40 +const_RIGHT_Y: equ $0028 + ; + ; DEF FN CHAR_XY(x, y) = ((y) / 8 * 32 + (x) / 8) + ; + ; MODE 2 ' Color for sets of 8 characters. + CALL mode_2 + ; + ; DEFINE CHAR 27,7,extra_bitmaps + LD HL,27 + PUSH HL + LD A,7 + LD HL,cvb_EXTRA_BITMAPS + CALL define_char + ; + ; VPOKE $2003, $E1 ' Color for characters $18-$1f + LD HL,8195 + LD A,225 + DI + CALL WRTVRM + EI + ; VPOKE $2004, $14 ' $20-$27 + LD HL,8196 + LD A,20 + DI + CALL WRTVRM + EI + ; VPOKE $2005, $1F ' $28-$29 + LD HL,8197 + LD A,31 + DI + CALL WRTVRM + EI + ; VPOKE $2006, $1F ' $30-$37 + LD HL,8198 + LD A,31 + DI + CALL WRTVRM + EI + ; VPOKE $2007, $1F ' $38-$3f + LD HL,8199 + LD A,31 + DI + CALL WRTVRM + EI + ; VPOKE $2008, $F4 ' $40-$47 + LD HL,8200 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $2009, $F4 ' $48-$4f + LD HL,8201 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $200A, $F4 ' $50-$57 + LD HL,8202 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $200B, $F4 ' $58-$5f + LD HL,8203 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $200C, $F4 ' $60-$67 + LD HL,8204 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $200D, $F4 ' $68-$6f + LD HL,8205 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $200E, $F4 ' $70-$77 + LD HL,8206 + LD A,244 + DI + CALL WRTVRM + EI + ; VPOKE $200F, $F4 ' $78-$7f + LD HL,8207 + LD A,244 + DI + CALL WRTVRM + EI + ; + ; ' Center numbers bitmaps + ; FOR #c = $0150 TO $01CF + LD HL,336 + LD (cvb_#C),HL +cv1: + ; d = VPEEK(#c) + LD HL,(cvb_#C) + CALL nmi_off + CALL RDVRM + CALL nmi_on + LD (cvb_D),A + ; VPOKE #c, (d / 2) OR (d / 4) + LD HL,(cvb_D) + LD H,0 + SRL H + RR L + SRL H + RR L + EX DE,HL + LD HL,(cvb_D) + LD H,0 + SRL H + RR L + LD A,L + OR E + LD L,A + LD A,H + OR D + LD H,A + LD A,L + LD HL,(cvb_#C) + DI + CALL WRTVRM + EI + ; NEXT #c + LD HL,(cvb_#C) + INC HL + LD (cvb_#C),HL + LD DE,464 + OR A + SBC HL,DE + JP C,cv1 + ; DEFINE CHAR 42,4,number_bitmap + LD HL,42 + PUSH HL + LD A,4 + LD HL,cvb_NUMBER_BITMAP + CALL define_char + ; + ; VDP(1) = $E0 ' 8x8 sprites + LD A,224 + LD B,A + LD C,1 + DI + CALL WRTVDP + EI + ; VDP(6) = $00 ' Sprites use character bitmaps. + SUB A + LD B,A + LD C,6 + DI + CALL WRTVDP + EI + ; + ; PRINT AT 36,"CVBasic controller test" + LD HL,36 + LD (cursor),HL + LD HL,cv2 + LD A,23 + CALL print_string + JR cv3 +cv2: + DB $43,$56,$42,$61,$73,$69,$63,$20 + DB $63,$6f,$6e,$74,$72,$6f,$6c,$6c + DB $65,$72,$20,$74,$65,$73,$74 +cv3: + ; + ; #c = CHAR_XY(left_x, left_y) + LD HL,167 + LD (cvb_#C),HL + ; GOSUB draw_controller + CALL cvb_DRAW_CONTROLLER + ; #c = CHAR_XY(right_x, right_y) + LD HL,180 + LD (cvb_#C),HL + ; GOSUB draw_controller + CALL cvb_DRAW_CONTROLLER + ; + ; main_loop: +cvb_MAIN_LOOP: + ; WHILE 1 +cv4: + ; IF cont1.up THEN + LD A,(joy1_data) + AND 1 + JP Z,cv6 + ; SPRITE 0, left_y - 1, left_x + 16, 27, 9 + SUB A + PUSH AF + LD A,39 + PUSH AF + LD A,72 + PUSH AF + LD A,27 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv7 +cv6: + ; SPRITE 0, $d1, 0, 0, 0 + SUB A + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv7: + ; IF cont1.left THEN + LD A,(joy1_data) + AND 8 + JP Z,cv8 + ; SPRITE 1, left_y + 15, left_x, 30, 9 + LD A,1 + PUSH AF + LD A,55 + PUSH AF + LD A,56 + PUSH AF + LD A,30 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv9 +cv8: + ; SPRITE 1, $d1, 0, 0, 0 + LD A,1 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv9: + ; IF cont1.right THEN + LD A,(joy1_data) + AND 2 + JP Z,cv10 + ; SPRITE 2, left_y + 15, left_x + 32, 28, 9 + LD A,2 + PUSH AF + LD A,55 + PUSH AF + LD A,88 + PUSH AF + LD A,28 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv11 +cv10: + ; SPRITE 2, $d1, 0, 0, 0 + LD A,2 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv11: + ; IF cont1.down THEN + LD A,(joy1_data) + AND 4 + JP Z,cv12 + ; SPRITE 3, left_y + 31, left_x + 16, 29, 9 + LD A,3 + PUSH AF + LD A,71 + PUSH AF + LD A,72 + PUSH AF + LD A,29 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv13 +cv12: + ; SPRITE 3, $d1, 0, 0, 0 + LD A,3 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv13: + ; IF cont1.button THEN + LD A,(joy1_data) + AND 64 + JP Z,cv14 + ; SPRITE 4, left_y + 47, left_x - 8, 31, 9 + LD A,4 + PUSH AF + LD A,87 + PUSH AF + LD A,48 + PUSH AF + LD A,31 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv15 +cv14: + ; SPRITE 4, $d1, 0, 0, 0 + LD A,4 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv15: + ; IF cont1.button2 THEN + LD A,(joy1_data) + AND 128 + JP Z,cv16 + ; SPRITE 5, left_y + 47, left_x + 40, 31, 9 + LD A,5 + PUSH AF + LD A,87 + PUSH AF + LD A,96 + PUSH AF + LD A,31 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv17 +cv16: + ; SPRITE 5, $d1, 0, 0, 0 + LD A,5 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv17: + ; c = cont1.key + LD A,(key1_data) + LD (cvb_C),A + ; IF c = 15 THEN + CP 15 + JP NZ,cv18 + ; SPRITE 6, $d1, 0, 0, 0 + LD A,6 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; ELSE + JP cv19 +cv18: + ; GOSUB prepare_key + CALL cvb_PREPARE_KEY + ; SPRITE 6, left_y + y, left_x + x, c, 9 + LD A,6 + PUSH AF + LD A,(cvb_Y) + ADD A,40 + PUSH AF + LD A,(cvb_X) + ADD A,56 + PUSH AF + LD A,(cvb_C) + PUSH AF + LD A,9 + CALL update_sprite + ; END IF +cv19: + ; IF cont2.up THEN + LD A,(joy2_data) + AND 1 + JP Z,cv20 + ; SPRITE 7, right_y - 1, right_x + 16, 27, 9 + LD A,7 + PUSH AF + LD A,39 + PUSH AF + LD A,176 + PUSH AF + LD A,27 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv21 +cv20: + ; SPRITE 7, $d1, 0, 0, 0 + LD A,7 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv21: + ; IF cont2.left THEN + LD A,(joy2_data) + AND 8 + JP Z,cv22 + ; SPRITE 8, right_y + 15, right_x, 30, 9 + LD A,8 + PUSH AF + LD A,55 + PUSH AF + LD A,160 + PUSH AF + LD A,30 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv23 +cv22: + ; SPRITE 8, $d1, 0, 0, 0 + LD A,8 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv23: + ; IF cont2.right THEN + LD A,(joy2_data) + AND 2 + JP Z,cv24 + ; SPRITE 9, right_y + 15, right_x + 32, 28, 9 + LD A,9 + PUSH AF + LD A,55 + PUSH AF + LD A,192 + PUSH AF + LD A,28 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv25 +cv24: + ; SPRITE 9, $d1, 0, 0, 0 + LD A,9 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv25: + ; IF cont2.down THEN + LD A,(joy2_data) + AND 4 + JP Z,cv26 + ; SPRITE 10, right_y + 31, right_x + 16, 29, 9 + LD A,10 + PUSH AF + LD A,71 + PUSH AF + LD A,176 + PUSH AF + LD A,29 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv27 +cv26: + ; SPRITE 10, $d1, 0, 0, 0 + LD A,10 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv27: + ; IF cont2.button THEN + LD A,(joy2_data) + AND 64 + JP Z,cv28 + ; SPRITE 11, right_y + 47, right_x - 8, 31, 9 + LD A,11 + PUSH AF + LD A,87 + PUSH AF + LD A,152 + PUSH AF + LD A,31 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv29 +cv28: + ; SPRITE 11, $d1, 0, 0, 0 + LD A,11 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv29: + ; IF cont2.button2 THEN + LD A,(joy2_data) + AND 128 + JP Z,cv30 + ; SPRITE 12, right_y + 47, right_x + 40, 31, 9 + LD A,12 + PUSH AF + LD A,87 + PUSH AF + LD A,200 + PUSH AF + LD A,31 + PUSH AF + LD A,9 + CALL update_sprite + ; ELSE + JP cv31 +cv30: + ; SPRITE 12, $d1, 0, 0, 0 + LD A,12 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; END IF +cv31: + ; c = cont2.key + LD A,(key2_data) + LD (cvb_C),A + ; IF c = 15 THEN + CP 15 + JP NZ,cv32 + ; SPRITE 14, $d1, 0, 0, 0 + LD A,14 + PUSH AF + LD A,209 + PUSH AF + SUB A + PUSH AF + PUSH AF + CALL update_sprite + ; ELSE + JP cv33 +cv32: + ; GOSUB prepare_key + CALL cvb_PREPARE_KEY + ; SPRITE 14, right_y + y, right_x + x, c, 9 + LD A,14 + PUSH AF + LD A,(cvb_Y) + ADD A,40 + PUSH AF + LD A,(cvb_X) + ADD A,160 + PUSH AF + LD A,(cvb_C) + PUSH AF + LD A,9 + CALL update_sprite + ; END IF +cv33: + ; + ; WAIT + HALT + ; + ; WEND + JP cv4 +cv5: + ; + ; draw_controller: PROCEDURE +cvb_DRAW_CONTROLLER: + ; FOR #d = #c - $0021 TO #c + $01DF STEP $20 + LD HL,(cvb_#C) + LD DE,65503 + ADD HL,DE + LD (cvb_#D),HL +cv34: + ; PRINT AT #d, "!!!!!!!" + LD HL,(cvb_#D) + LD (cursor),HL + LD HL,cv35 + LD A,7 + CALL print_string + JR cv36 +cv35: + DB $21,$21,$21,$21,$21,$21,$21 +cv36: + ; NEXT #d + LD HL,(cvb_#D) + LD DE,32 + ADD HL,DE + LD (cvb_#D),HL + LD HL,(cvb_#C) + LD DE,479 + ADD HL,DE + LD DE,(cvb_#D) + OR A + SBC HL,DE + JP NC,cv34 + ; + ; PRINT AT #c + $0000, "!!\27!!" + LD HL,(cvb_#C) + LD (cursor),HL + LD HL,cv37 + LD A,5 + CALL print_string + JR cv38 +cv37: + DB $21,$21,$1b,$21,$21 +cv38: + ; PRINT AT #c + $0040, "\30!\31!\28" + LD HL,(cvb_#C) + LD DE,64 + ADD HL,DE + LD (cursor),HL + LD HL,cv39 + LD A,5 + CALL print_string + JR cv40 +cv39: + DB $1e,$21,$1f,$21,$1c +cv40: + ; PRINT AT #c + $0080, "!!\29!!" + LD HL,(cvb_#C) + LD DE,128 + ADD HL,DE + LD (cursor),HL + LD HL,cv41 + LD A,5 + CALL print_string + JR cv42 +cv41: + DB $21,$21,$1d,$21,$21 +cv42: + ; PRINT AT #c + $00bf, "\31!!!!!\31" + LD HL,(cvb_#C) + LD DE,191 + ADD HL,DE + LD (cursor),HL + LD HL,cv43 + LD A,7 + CALL print_string + JR cv44 +cv43: + DB $1f,$21,$21,$21,$21,$21,$1f +cv44: + ; PRINT AT #c + $0100, "1!2!3" + LD HL,(cvb_#C) + INC H + LD (cursor),HL + LD HL,cv45 + LD A,5 + CALL print_string + JR cv46 +cv45: + DB $31,$21,$32,$21,$33 +cv46: + ; PRINT AT #c + $0140, "4!5!6" + LD HL,(cvb_#C) + LD DE,320 + ADD HL,DE + LD (cursor),HL + LD HL,cv47 + LD A,5 + CALL print_string + JR cv48 +cv47: + DB $34,$21,$35,$21,$36 +cv48: + ; PRINT AT #c + $0180, "7!8!9" + LD HL,(cvb_#C) + LD DE,384 + ADD HL,DE + LD (cursor),HL + LD HL,cv49 + LD A,5 + CALL print_string + JR cv50 +cv49: + DB $37,$21,$38,$21,$39 +cv50: + ; PRINT AT #c + $01C0, "*!0!+" + LD HL,(cvb_#C) + LD DE,448 + ADD HL,DE + LD (cursor),HL + LD HL,cv51 + LD A,5 + CALL print_string + JR cv52 +cv51: + DB $2a,$21,$30,$21,$2b +cv52: + ; END + RET + ; + ; prepare_key: PROCEDURE +cvb_PREPARE_KEY: + ; IF c = 0 THEN + LD A,(cvb_C) + AND A + JP NZ,cv53 + ; x = 16 + LD A,16 + LD (cvb_X),A + ; y = 111 + LD A,111 + LD (cvb_Y),A + ; c = 48 + LD A,48 + LD (cvb_C),A + ; ELSEIF c = 10 THEN + JP cv54 +cv53: + LD A,(cvb_C) + CP 10 + JP NZ,cv55 + ; x = 0 + SUB A + LD (cvb_X),A + ; y = 111 + LD A,111 + LD (cvb_Y),A + ; c = 42 + LD A,42 + LD (cvb_C),A + ; ELSEIF c = 11 THEN + JP cv54 +cv55: + LD A,(cvb_C) + CP 11 + JP NZ,cv56 + ; x = 32 + LD A,32 + LD (cvb_X),A + ; y = 111 + LD A,111 + LD (cvb_Y),A + ; c = 43 + LD A,43 + LD (cvb_C),A + ; ELSEIF c > 0 AND c < 10 THEN + JP cv54 +cv56: + LD A,(cvb_C) + CP 10 + LD A,0 + SBC A,A + LD B,A + LD A,(cvb_C) + CP 1 + LD A,255 + ADC A,0 + AND B + JP Z,cv57 + ; x = ((c - 1) % 3) * 16 + LD HL,(cvb_C) + LD H,0 + DEC HL + LD DE,3 + CALL _mod16 + LD A,L + ADD A,A + ADD A,A + ADD A,A + ADD A,A + LD (cvb_X),A + ; y = 63 + ((c - 1) / 3) * 16 + LD HL,(cvb_C) + LD H,0 + DEC HL + LD DE,3 + CALL _div16 + LD A,L + ADD A,A + ADD A,A + ADD A,A + ADD A,A + ADD A,63 + LD (cvb_Y),A + ; c = c + 48 + LD HL,cvb_C + LD A,48 + ADD A,(HL) + LD (HL),A + ; ELSEIF c = 12 THEN + JP cv54 +cv57: + LD A,(cvb_C) + CP 12 + JP NZ,cv58 + ; x = 8 + LD A,8 + LD (cvb_X),A + ; y = 0 + SUB A + LD (cvb_Y),A + ; c = 44 + LD A,44 + LD (cvb_C),A + ; ELSEIF c = 13 THEN + JP cv54 +cv58: + LD A,(cvb_C) + CP 13 + JP NZ,cv59 + ; x = 8 + LD A,8 + LD (cvb_X),A + ; y = 8 + LD (cvb_Y),A + ; c = 45 + LD A,45 + LD (cvb_C),A + ; ELSE + JP cv54 +cv59: + ; ' Some systems have extra characters + ; x = 16 + LD A,16 + LD (cvb_X),A + ; y = 127 + LD A,127 + LD (cvb_Y),A + ; END IF +cv54: + ; END + RET + ; + ; extra_bitmaps: +cvb_EXTRA_BITMAPS: + ; BITMAP "...XX..." + ; BITMAP "..XXXX.." + ; BITMAP ".XXXXXX." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + DB $18,$3c,$7e,$18,$18,$18,$18,$18 + ; + ; BITMAP "........" + ; BITMAP ".....X.." + ; BITMAP ".....XX." + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP ".....XX." + ; BITMAP ".....X.." + ; BITMAP "........" + DB $00,$04,$06,$ff,$ff,$06,$04,$00 + ; + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP "...XX..." + ; BITMAP ".XXXXXX." + ; BITMAP "..XXXX.." + ; BITMAP "...XX..." + DB $18,$18,$18,$18,$18,$7e,$3c,$18 + ; + ; BITMAP "........" + ; BITMAP "..X....." + ; BITMAP ".XX....." + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP ".XX....." + ; BITMAP "..X....." + ; BITMAP "........" + DB $00,$20,$60,$ff,$ff,$60,$20,$00 + ; + ; BITMAP "..XXXX.." + ; BITMAP ".XXXXXX." + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP ".XXXXXX." + ; BITMAP "..XXXX.." + DB $3c,$7e,$ff,$ff,$ff,$ff,$7e,$3c + ; + ; BITMAP "........" + ; BITMAP "........" + ; BITMAP "........" + ; BITMAP "........" + ; BITMAP "........" + ; BITMAP "........" + ; BITMAP "........" + ; BITMAP "........" + DB $00,$00,$00,$00,$00,$00,$00,$00 + ; + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + ; BITMAP "XXXXXXXX" + DB $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + ; + ; number_bitmap: +cvb_NUMBER_BITMAP: + ; BITMAP "........" + ; BITMAP ".XX..XX." + ; BITMAP "..XXXX.." + ; BITMAP ".XXXXXX." + ; BITMAP "..XXXX.." + ; BITMAP ".XX..XX." + ; BITMAP "........" + ; BITMAP "........" + DB $00,$66,$3c,$7e,$3c,$66,$00,$00 + ; + ; BITMAP "..XX.XX." + ; BITMAP "..XX.XX." + ; BITMAP ".XXXXXXX" + ; BITMAP "..XX.XX." + ; BITMAP ".XXXXXXX" + ; BITMAP "..XX.XX." + ; BITMAP "..XX.XX." + ; BITMAP "........" + DB $36,$36,$7f,$36,$7f,$36,$36,$00 + ; + ; BITMAP "XXXXXXX." + ; BITMAP "XX....XX" + ; BITMAP "XX....XX" + ; BITMAP "XXXXXXX." + ; BITMAP "XX....XX" + ; BITMAP "XX....XX" + ; BITMAP "XXXXXXX." + ; BITMAP "........" + DB $fe,$c3,$c3,$fe,$c3,$c3,$fe,$00 + ; + ; BITMAP "XXXXXXX." + ; BITMAP "XX....XX" + ; BITMAP "XX....XX" + ; BITMAP "XXXXXXX." + ; BITMAP "XX......" + ; BITMAP "XX......" + ; BITMAP "XX......" + ; BITMAP "........" + DB $fe,$c3,$c3,$fe,$c0,$c0,$c0,$00 + ; + ; + ; CVBasic epilogue (BASIC compiler for Colecovision) + ; + ; by Oscar Toledo G. + ; https://nanochess.org/ + ; + ; Creation date: Feb/27/2024. + ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and + ; read_pointer variables. + ; Revision date: Mar/04/2024. Added music player. + ; Revision date: Mar/05/2024. Added support for Sega SG1000. + ; Revision date: Mar/12/2024. Added support for MSX. + ; Revision date: Mar/13/2024. Added Pletter decompressor. + ; Revision date: Mar/19/2024. Added support for sprite flicker. + ; Revision date: Apr/11/2024. Added support for Super Game Module. + ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. + ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it + ; can remain accessible in bank 0 (bank switching). + ; Revision date: Aug/02/2024. Added rom_end label for Memotech. + ; Revision date: Aug/15/2024. Added support for Tatung Einstein. + ; Revision date: Nov/12/2024. Added vdp_status. + ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. + ; Revision date: Feb/05/2026. Added support for spinners and roller controller + ; (Colecovision). + ; + +rom_end: + + ; ROM final size rounding + if MSX+COLECO+SG1000+SMS+SVI+SORD + TIMES (($+$1FFF)&$1e000)-$ DB $ff + endif + if MEMOTECH+EINSTEIN+NABU + ; Align following data to a 256-byte page. + TIMES $100-($&$ff) DB $4f + endif + if PV2000 + TIMES $10000-$ DB $ff + endif + if SG1000+SMS + if CVBASIC_BANK_SWITCHING + forg CVBASIC_BANK_ROM_SIZE*1024-1 ; Force final ROM size + db $ff + endif + forg $7FF0 + org $7FF0 + db "TMR SEGA" + db 0,0 + db 0,0 ; Checksum + db $11,$78 ; Product code + db $00 ; Version + db $4c ; SMS Export + 32KB for checksum + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 + org BASE_RAM + endif +ram_start: + +sprites: + if SMS + rb 256 + else + rb 128 + endif +sprite_data: + rb 4 +frame: + rb 2 +read_pointer: + rb 2 +cursor: + rb 2 +lfsr: + rb 2 + if MSX +cartridge_slot: + rb 1 +fm_slot: + rb 1 +fm_enabled: + rb 1 +fm_inst: + rb 4 + endif +mode: + rb 1 ; bit 0: NMI disabled. + ; bit 1: NMI received. + ; bit 2: No sprite flicker. + ; bit 3: Single charset mode. + ; bit 4: MSX2 sprites. +flicker: + rb 1 +joy1_data: + rb 1 +joy2_data: + rb 1 +key1_data: + rb 1 +key2_data: + rb 1 +ntsc: + rb 1 +vdp_status: + rb 1 + if COLECO + if COLECO_SPINNER +spinner_data: + rb 3 + endif + endif + if NABU +nabu_data0: rb 1 +nabu_data1: rb 1 +nabu_data2: rb 1 + endif + + if CVBASIC_MUSIC_PLAYER +music_tick: rb 1 +music_mode: rb 1 + + if CVBASIC_BANK_SWITCHING +music_bank: rb 1 + endif +music_start: rb 2 +music_pointer: rb 2 +music_playing: rb 1 +music_timing: rb 1 +music_note_counter: rb 1 +music_instrument_1: rb 1 +music_counter_1: rb 1 +music_note_1: rb 1 +music_instrument_2: rb 1 +music_counter_2: rb 1 +music_note_2: rb 1 +music_instrument_3: rb 1 +music_counter_3: rb 1 +music_note_3: rb 1 +music_counter_4: rb 1 +music_drum: rb 1 + +audio_freq1: rb 2 +audio_freq2: rb 2 +audio_freq3: rb 2 +audio_noise: rb 1 +audio_mix: rb 1 +audio_vol1: rb 1 +audio_vol2: rb 1 +audio_vol3: rb 1 + +audio_control: rb 1 +audio_vol4hw: rb 1 + endif + + if SGM + org $2000 ; Start for variables. + endif +cvb_C: rb 1 +cvb_D: rb 1 +cvb_X: rb 1 +cvb_Y: rb 1 +cvb_#C: rb 2 +cvb_#D: rb 2 +ram_end: diff --git a/controller.rom b/controller.rom new file mode 100644 index 0000000000000000000000000000000000000000..55148e0150e2b71842b8a199a8c9d6aaf6f577ba GIT binary patch literal 8192 zcmeHJZA@F&89o z47Rdf5n~-rTcE&1Z-i|ieSTl*mD%TA|9}na%54QBPu&<5kcCLV)$V19fRgGTqt7I58=k`-E-<`b)?)JfN*Qn! zNH-_DUAwfJcK6>c%>EQHTh6V3I$!}=NaK}2>cJ0id(~!>R55hr+J3L)q(>x8R$Z-|anPbUSao23 z%o}9Dz_G7{f55|`pb~lKni|2G%v^oF;yX3kC=0qk&6vf19W zsoT{Zb*HHUen1wZJpfbDRI3@>eA)@ozcCd4acJWkbf z>gxh3aa%IlOwcEyoo*yRbAZ6`{X;&CBmsHIEoc-5yvH#3mefIvs>uzn*bpRCh$0AM zMBM@vM$w7XEKuXW`AT}w26A1>ruuSjXiUg$m4;b^xc&nvBAeB*fsVM?!Or5JWnR%&S^h&_ zyZZi0I(1O}^}>hCQ~sB!Fd0=J@@`d+!d1N`4MBK9;g0Zdik+Tjj!K^a*7g!z6#Xwz zw+C6H;RdR{n|dw2w-d}hW?Go}Zf8~Oo1Mg|okhv(8{azu-Z&x-SXwh`NGegI>JhMG zY9H7a)x%&X)j_bcY8dR*p+^5%x_mKtYXdD^Tz+daq-E3Muu0$Gh>am? z*ir6vsH2VwuifGFh_#iicTV~zs5Qemc7p?{qv|NwG4%x47kSA^exO;-6FH9^=c;k| znGH+P;s3{@pP|0zX?@-E6rZNe&CNIFSJDcx*C3`rnK6|clda||fXe#5==$=MAUp@1 znwvj?=OWi)ceS9@>?iODXsv=(&@OfOU!V<9Z6|8mgBoo~!9PW{-h-F?<5asIyyQPa zK|SJx>-#4u{!2&Q^yeh*fBAE5r~_A{Rbs=qSG&I*TO_iw4&8SfixT;|;gw3H*6^%( z&zAS>68V=AEz5i5d9NbxRpz}ddC!seoO$m7q3%5Oou|;yS|fYl{I5{oE3^Tr0d)ua ztmRk3e+)_@hr9$8R7=s`Yi_x3f;$8JZLl zHK7Te?9xe>PO5cMrv1J>zMDZe^a)*u6=T^G2SY^A$vrx0)k#g3_I-{O^GXsw3y~7e z`=L&@XL%<%R?HI0JcVP$yl7%IL`pet zpukIWEYE|MnWmf0SVb4H7Ood>=+gRn0BJi%7rlDht8}qdZ=0q@t+umFqF@)XagAmR z8r{#ad~)E~6OVThJHPx)L8PZSR?I6&{I-jfao$`(q;niA=81_vb&+x|64cF!w8*hy zo}Bo!i&XH-PZlo!PmUGyqKWcuQptJO3cRfx%kw6)A~kgrN0CUq-Ap7$kw`NIk)DoQ zLeR7Bzh$cGE>PbE%G&W*H?gsHga?ujfZY<}1V$CAQvDYw^!Eo3cf($`W4fD^vK^%u zS7Xc)%D{)f+qpmuuEpC~AZi4(Tma)8#*RN5fn=_DEw5b*dv>x+o4F19upfV$mk@Y~ zZ9UoA&GYSPyaeU!^4MKSxOubX#2N zg}`Qc?Ae})e85)-RK%uxh?I})DMZQ%Iv-+t1(JCm%_LTPeADpTvBzye@E2zI6b#r_ zz_5WW9)Qw#8mj;5M7DTkY_o^hfjq%ZwYN}WOKfW|4>0^&25y{x6cEJ|81b-yL~ABv z6%k*I1UyI@$Ycg26d1|C7zyP5M6(qe=xAUha1^1ImQi@Mpv`!kz4<&hH-`+CX-x%8 r1xy7@1xy7@1xy7@1xy7@1xy7@1xy7@1xy7@1xy7@1xyA0ZwmYukfonQ literal 0 HcmV?d00001 diff --git a/cvbasic.c b/cvbasic.c index 9007a66..bcae085 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -138,6 +138,7 @@ int next_local = 1; static int option_explicit; static int option_warnings; +static int option_fm; static enum lexical_component { C_END, C_NAME, @@ -3557,6 +3558,19 @@ void compile_statement(int check_for_else) } else { emit_error("missing ON/OFF in OPTION WARNINGS"); } + } else if (strcmp(name, "FM") == 0) { + if (machine != MSX && machine != MSX2) + emit_warning("OPTION FM only works for MSX/MSX2 platforms"); + get_lex(); + if (lex == C_NAME && strcmp(name, "ON") == 0) { + get_lex(); + option_fm = 1; + } else if (lex == C_NAME && strcmp(name, "OFF") == 0) { + get_lex(); + option_fm = 0; + } else { + emit_error("missing ON/OFF in OPTION FM"); + } } else { emit_error("non-recognized OPTION"); } @@ -5532,6 +5546,34 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "(music_mode)", "A"); } + } else if (strcmp(name, "INSTRUMENT") == 0) { + get_lex(); + if (machine != MSX && machine != MSX2) + emit_warning("PLAY INSTRUMENT only allowed for MSX and MSX2"); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst)", "A"); + if (lex != C_COMMA) + emit_error("missing comma"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst+1)", "A"); + if (lex != C_COMMA) + emit_error("missing comma"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst+2)", "A"); + if (lex != C_COMMA) + emit_error("missing comma"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst+3)", "A"); } else { struct label *label; @@ -6932,8 +6974,10 @@ int main(int argc, char *argv[]) else c = 0; fprintf(output, "MSX:\tequ %d\n", c); - if (c) + if (c) { fprintf(output, "KONAMI:\tequ %d\n", bank_konami); + fprintf(output, "FM_SUPPORT:\tequ %d\n", option_fm); + } fprintf(output, "SGM:\tequ %d\n", (machine == COLECOVISION_SGM) ? 1 : 0); fprintf(output, "SVI:\tequ %d\n", (machine == SVI) ? 1 : 0); fprintf(output, "SORD:\tequ %d\n", (machine == SORD) ? 1 : 0); diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 2db8b1d..82ca1e5 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -72,6 +72,16 @@ cursor: rb 2 lfsr: rb 2 + if MSX +cartridge_slot: + rb 1 +fm_slot: + rb 1 +fm_enabled: + rb 1 +fm_inst: + rb 4 + endif mode: rb 1 ; bit 0: NMI disabled. ; bit 1: NMI received. diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index de66a6f..1bda1a5 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -45,6 +45,7 @@ ; Revision date: Feb/10/2026. Added support for sprites in MSX2 and 64K VRAM ; access. ; Revision date: Feb/26/2026. Faster CPYBLK, LDIRVM3, and FILVRM. + ; Revision date: Mar/09/2026. Corrections on joystick read for MSX. ; ; @@ -2064,8 +2065,8 @@ nmi_handler: ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php ld a,15 call RDPSG - and $b0 - or $4f + and $80 + or $5c ; Read joystick 2. ld e,a ld a,15 call WRTPSG @@ -2164,8 +2165,8 @@ nmi_handler: ld a,15 call RDPSG - and $b0 - or $0f + and $80 + or $23 ; Read joystick 1. ld e,a ld a,15 call WRTPSG @@ -3075,6 +3076,13 @@ MIX_BASE: equ $78 ld a,$07 ld e,MIX_BASE call WRTPSG + if FM_SUPPORT + ld a,7 + ld ($7000),a + ld a,(fm_slot) + inc a + call nz,init_fm + endif endif if SGM ld b,$08 @@ -3146,6 +3154,72 @@ music_generate: ld a,$ff ld (audio_vol4hw),a + if MSX + if FM_SUPPORT + ld a,(fm_enabled) + or a + jp z,.fm1 + ld a,(fm_slot) + inc a + jp z,.fm1 + ld a,(music_note_counter) + or a + ld a,$07 + ld ($7000),a + jp nz,music_generate_fm.6 + ld hl,(music_pointer) +.fm15: push hl + if CVBASIC_BANK_SWITCHING + ld a,(music_bank) + if SG1000+SMS + ld ($fffe),a + endif + if MSX + if KONAMI + ld ($8000),a + inc a + ld ($a000),a + else + ld ($7000),a + endif + endif + endif + ld b,(hl) + inc hl + ld c,(hl) + inc hl + ld d,(hl) + inc hl + ld e,(hl) + pop hl + ld a,(music_timing) + rlca + jr nc,.fm16 + ld e,d + ld d,0 + jr .fm17 + +.fm16: rlca + jr nc,.fm17 + ld e,0 +.fm17: ld a,b ; Read first byte. + cp -2 ; End of music? + jr nz,.fm19 ; No, jump. + xor a ; Keep at same place. + ld (music_playing),a + ret + +.fm19: cp -3 ; Repeat music? + ld a,$07 + ld ($7000),a + jp nz,music_generate_fm.0 + ld hl,(music_start) + jr .fm15 + +.fm1: + endif + endif + ld a,(music_note_counter) or a jp nz,.6 @@ -4218,9 +4292,16 @@ WRITE_VRAM: equ $1fdf call RSLREG ld b,1 ; $4000-$7fff call get_slot_mapping + ld (cartridge_slot),a ld h,$80 call ENASLT ; Map into $8000-$BFFF - + if FM_SUPPORT + ld a,$ff ; FM hasn't been discovered. + ld (fm_slot),a + ld a,7 + ld ($7000),a + call detect_fm + endif ld a,($002b) cpl rlca From c527c69ce87a358ecb6ffa7b3c239558234c96b7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 12 Mar 2026 13:08:51 -0600 Subject: [PATCH 125/155] MSX/MSX2: Added library for FM synthesis --- controller.asm | 5552 ------------------------------------------ controller.rom | Bin 8192 -> 0 bytes cpuz80.c | 9 +- cvbasic.c | 40 +- cvbasic_epilogue.asm | 418 ++++ cvbasic_prologue.asm | 38 +- manual.txt | 61 + 7 files changed, 557 insertions(+), 5561 deletions(-) delete mode 100644 controller.asm delete mode 100644 controller.rom diff --git a/controller.asm b/controller.asm deleted file mode 100644 index 0e053b0..0000000 --- a/controller.asm +++ /dev/null @@ -1,5552 +0,0 @@ - ; CVBasic compiler v0.9.2 Mar/06/2026 - ; Command: ./cvbasic --msx examples/controller.bas controller.asm - ; Created: Mon Mar 9 11:24:18 2026 - -COLECO: equ 0 -SG1000: equ 0 -MSX: equ 1 -KONAMI: equ 0 -FM_SUPPORT: equ 0 -SGM: equ 0 -SVI: equ 0 -SORD: equ 0 -MEMOTECH: equ 0 -EINSTEIN: equ 0 -CPM: equ 0 -PENCIL: equ 0 -PV2000: equ 0 -TI99: equ 0 -NABU: equ 0 -SMS: equ 0 - -CVBASIC_MUSIC_PLAYER: equ 0 -CVBASIC_COMPRESSION: equ 0 -CVBASIC_BANK_SWITCHING: equ 0 -CVBASIC_BANK_ROM_SIZE: equ 0 -COLECO_SPINNER: equ 0 - -BASE_RAM: equ $e000 ; Base of RAM -RAM_SIZE: equ $1380 ; Base of RAM -STACK: equ $f380 ; Base stack pointer -VDP: equ $98 ; VDP port (write) -VDPR: equ $98 ; VDP port (read) -PSG: equ $00 ; PSG port (write) - - ; - ; CVBasic prologue (BASIC compiler for Colecovision and other consoles) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Turns off sound. Now it reads the controllers. - ; Added 16-bit multiply, division, modulo, and abs. - ; Added random generator. Added sound routines. - ; Revision date: Mar/03/2024. Removed fname directive to use gasm80. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/06/2024. Added ENASCR, DISSCR, and CPYBLK. - ; Revision date: Mar/08/2024. Added modes 0, 1 and 2. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/14/2024. Added _sgn16. - ; Revision date: Mar/15/2024. Added upper 16k enable for MSX. - ; Revision date: Apr/11/2024. Added support for formatting numbers. Added - ; support for Super Game Module. - ; Revision date: Apr/13/2024. Saved bytes in SG-1000 ROMs. Faster LDIRVM. - ; Shorter mode setting subroutines. - ; Revision date: Apr/26/2024. Interruption handler saves current bank. - ; Revision date: Apr/27/2024. Music player now supports bank switching. - ; Revision date: May/17/2024. Added delay for SG1000 and SC3000 controller - ; support with keyboard (code by SiRioKD) - ; Revision date: Jun/04/2024. SGM supported deleted NTSC flag. - ; Revision date: Jun/07/2024. Keys 0-9, = and - emulate keypad in MSX. - ; Revision date: Jun/17/2024. Added SVI-328 support. - ; Revision date: Aug/01/2024. Added Sord M5 support. - ; Revision date: Aug/02/2024. PSG label now defined by CVBasic. Added Memotech - ; support. - ; Revision date: Aug/08/2024. Added Soundic/Hanimex Pencil II support. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. Added support - ; for Casio PV-2000. - ; Revision date: Aug/21/2024. Added keypad support for Memotech, Tatung Einstein, - ; and Casio PV-2000. - ; Revision date: Aug/30/2024. Changed mode bit to bit 3 (avoids collision - ; with flicker flag). - ; Revision date: Oct/15/2024. Added LDIRMV. Solved bug where asterisk and number - ; keys values were inverted. - ; Revision date: Nov/12/2024. Saves the VDP status. - ; Revision date: Feb/05/2026. Added support for spinners and roller controller - ; (Colecovision). - ; Revision date: Feb/09/2026. Added support for palette in MSX2. - ; Revision date: Feb/10/2026. Added support for sprites in MSX2 and 64K VRAM - ; access. - ; Revision date: Feb/26/2026. Faster CPYBLK, LDIRVM3, and FILVRM. - ; Revision date: Mar/09/2026. Corrections on joystick read for MSX. - ; - - ; - ; Resources: - ; * Z80 instructions timing: https://map.grauw.nl/resources/z80instr.php - ; * Use the Timing Z80+M1 for MSX and Colecovision (both insert one - ; wait state in each M1 cycle) - ; - ; Technical requirements: - ; * Minimum of 28 cycles between VDP writes for 3.58 mhz. systems. - ; * Minimum of 31 cycles between VDP writes for 4.00 mhz. systems. - ; * For SMS minimum of 28 cycles between VDP writes (3.58 mhz) - ; * For MSX2 (V9938) minimum of 23 cycles between VDP writes (3.58 mhz) - ; - ; Dependances: - ; * LDIRVM, assumed to keep DE unchanged (target VRAM address) - ; * For speed. Required by CPYBLK and LDIRVM3. - ; - - if COLECO+SG1000+SMS -JOYSEL: equ $c0 -KEYSEL: equ $80 - -JOY1: equ $fc-$20*(SG1000+SMS) -JOY2: equ $ff-$22*(SG1000+SMS) - endif - - if COLECO - org $8000 - if PENCIL - db "COPYRIGHT SOUNDIC" - jp START - jp nmi_handler - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - jp 0 ; rst $38 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - db "CVBASIC!POWERED BY!2024!" - else - db $55,$aa - dw 0 - dw 0 - dw 0 - dw 0 - dw START - - jp 0 ; rst $08 - jp 0 ; rst $10 - jp 0 ; rst $18 - jp 0 ; rst $20 - jp 0 ; rst $28 - jp 0 ; rst $30 - if COLECO_SPINNER - jp spinner_handler - else - jp 0 ; rst $38 - endif - jp nmi_handler - - if COLECO_SPINNER -spinner_handler: - PUSH AF - PUSH HL - LD A,$FF - LD (spinner_data),A - OUT (JOYSEL),A - PUSH AF - POP AF - LD HL,spinner_data+1 - IN A,(JOY1) - BIT 4,A - JR NZ,.1 - BIT 5,A - JR NZ,$+4 - INC (HL) - DB $3E - DEC (HL) -.1: INC HL - IN A,(JOY2) - BIT 4,A - JR NZ,.2 - BIT 5,A - JR NZ,$+4 - INC (HL) - DB $3E - DEC (HL) -.2: POP HL - POP AF - EI - RETI - endif - endif - endif - if SG1000+SMS+SVI - org $0000 - di - ld sp,STACK - jp START - db $ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp 0 - db $ff,$ff,$ff,$ff,$ff - jp nmi_handler ; It should be called int_handler. - endif - if MSX - ORG $4000 - db "AB" - dw START - dw $0000 - dw $0000 - dw $0000 - dw $0000 - -WRTPSG: equ $0093 -RDPSG: equ $0096 - - endif - if SORD - ORG $2000 - db $02 ; Avoid checking $4000 - dw START ; Start address. - dw $002e ; Prestart address (just point to RET in BIOS). - endif - if PV2000 - ORG $C000 - jp START - endif - - if MEMOTECH - if CPM - org $0100 - else - org $40fc - dw rom_start - dw rom_end-rom_start - endif -rom_start: - jp START - db 0,0,0,0,0 - dw nmi_handler - dw null_vector - dw null_vector - dw rom_start - -null_vector: - ei - reti - endif - if EINSTEIN - org $0100 -rom_start: - jp START - db 0,0,0,0,0 - dw $0000 - dw $0000 - dw $0000 - dw $0000 - endif - if NABU - if CPM - org $0100 - else - org $140d - endif - nop - nop - nop - jp START - times $100-($&255) db $ff -nabu_int: - dw null_vector - dw null_vector - dw keyboard_handler - dw nmi_handler - dw null_vector - dw null_vector - dw null_vector - dw null_vector - -null_vector: - ei - reti - endif - - if SVI -WRTPSG: - out ($88),a - push af - ld a,e - out ($8c),a - pop af - ret - -RDPSG: - out ($88),a - push af - pop af - in a,($90) - ret - endif - - if EINSTEIN -WRTPSG: - out ($02),a - push af - ld a,e - out ($03),a - pop af - ret - -RDPSG: - out ($02),a - push af - pop af - in a,($02) - ret - endif - - if NABU -WRTPSG: - out ($41),a - push af - ld a,e - out ($40),a - pop af - ret - -RDPSG: - out ($41),a - push af - pop af - in a,($40) - ret - endif - - if PV2000 - ; The Casio PV2000 has the VDP ports mapped into main memory (MREQ) -WRTVDP: - ld a,b - ld (VDP+1),a - ld a,c - or $80 - ld (VDP+1),a - ret - -SETWRT: - ld a,l - ld (VDP+1),a - ld a,h - or $40 - ld (VDP+1),a - ret - -SETRD: - ld a,l - ld (VDP+1),a - ld a,h - and $3f - ld (VDP+1),a - ret - -WRTVRM: - push af - call SETWRT - pop af - ld (VDP),a - ret - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - ld a,(VDP) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) - inc c - inc b -.1: ld (VDP),a ; 13 14 - dec c ; 4 5 - jr nz,.1 ; 12 13 - ; -- -- - ; 29 32 - djnz .1 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - ld a,(VDP) - ld (de),a - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - EX DE,HL - CALL SETWRT - EX DE,HL - DEC BC - INC C - LD A,B - LD B,C - INC A - LD C,A -.1: - LD A,(HL) ; 7 8 - LD (VDP),A ; 13 14 - INC HL ; 6 7 - DJNZ .1 ; 13 14 - DEC C ; 4 5 - JP NZ,.1 ; 10 11 - RET - else - ; Normal platforms with VDP connected via ports (IORQ) -WRTVDP: - if COLECO_SPINNER - di - endif - ld a,b - out (VDP+1),a - ld a,c - or $80 - out (VDP+1),a - if COLECO_SPINNER - ei - endif - ret - -SETWRT: - if COLECO_SPINNER - di - endif - if MSX&2 - ld a,h - rlca - rlca - and 3 - out (VDP+1),a - ld a,$8e - out (VDP+1),a - ld a,l - out (VDP+1),a - ld a,h - and $3f - or $40 - out (VDP+1),a - else - ld a,l - out (VDP+1),a - ld a,h - or $40 - out (VDP+1),a - endif - if COLECO_SPINNER - ei - endif - ret - -SETRD: - if COLECO_SPINNER - di - endif - if MSX&2 - ld a,h - rlca - rlca - and 3 - out (VDP+1),a - ld a,$8e - out (VDP+1),a - endif - ld a,l - out (VDP+1),a - ld a,h - and $3f - out (VDP+1),a - if COLECO_SPINNER - ei - endif - ret - -WRTVRM: - push af - call SETWRT - pop af - out (VDP),a - ret - - if SG1000+SMS - db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff - - ; Located at $0066 - ei ; NMI handler (pause button) - retn - endif - -RDVRM: - push af - call SETRD - pop af - ex (sp),hl - ex (sp),hl - in a,(VDPR) - ret - -FILVRM: - push af - call SETWRT - pop af - dec bc ; T-states (normal / M1) - inc c - inc b - if MSX+COLECO -.1: out (VDP),a ; 12 - dec c ; 5 - jp nz,.1 ; 11 - ; -- - ; 28 - else -.1: out (VDP),a ; 11 12 - nop ; 4 5 - dec c ; 4 5 - jr nz,.1 ; 12 13 - ; -- -- - ; 31 35 - endif - djnz .1 - ret - -LDIRMV: - ex de,hl - call SETRD - ex (sp),hl - ex (sp),hl -.1: - in a,(VDP) - ld (de),a - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - inc de - dec bc - ld a,b - or c - jp nz,.1 - ret - -LDIRVM: - ex de,hl - call SETWRT - ex de,hl - dec bc - inc c - ld a,b - ld b,c - inc a - ld c,VDP -.1: - if MSX&2 - otir ; 23 cycles per byte. - else - if SORD+SMS - nop - endif - if SG1000+MEMOTECH+EINSTEIN - nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. - nop - endif - outi ; 18 - jp nz,.1 ; 11 - endif - dec a - jp nz,.1 - ret - endif - - if SMS - else -LDIRVM3: - call .1 - call .1 -.1: push hl - push bc - call LDIRVM - pop bc - ld a,d - add a,8 - ld d,a - pop hl - ret - endif - -DISSCR: - call nmi_off - ld bc,$a201 - call WRTVDP - jp nmi_on - -ENASCR: - call nmi_off - ld bc,$e201 - call WRTVDP - jp nmi_on - -CPYBLK: - pop hl - ex af,af' - pop af - ld b,a - pop af - ld c,a - pop de - ex (sp),hl - call nmi_off -.1: push bc - push hl - ld b,0 - call LDIRVM - ex de,hl - if SMS - ld bc,$0040 - else - ld bc,$0020 - endif - add hl,bc - ex de,hl - pop hl - ex af,af' - ld c,a - ld b,0 - add hl,bc - ex af,af' - pop bc - djnz .1 - jp nmi_on - -nmi_off: - if COLECO+PV2000 - push hl - ld hl,mode - set 0,(hl) - pop hl - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - di - endif - ret - -nmi_on: - if COLECO+PV2000 - push af - push hl - ld hl,mode - res 0,(hl) - nop - bit 1,(hl) - jp nz,nmi_handler.0 - pop hl - pop af - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - ei - endif - ret - - if COLECO -keypad_table: - db $0f,$08,$04,$05,$0c,$07,$0b,$02 - db $0d,$0a,$00,$09,$03,$01,$06,$0f - endif - -cls: - if SMS - ld hl,$3800 - ld (cursor),hl - di - call SETWRT -.1: ld a,$20 ; 7 - out (VDP),a ; 11 - inc hl ; 6 - inc hl ; 6 - ld a,$00 ; 7 - out (VDP),a ; 11 - ld a,h ; 4 - cp $3e ; 7 - jp nz,.1 ; 10 - ei - ret - else - ld hl,$1800 - ld (cursor),hl - ld bc,$0300 - ld a,$20 - call nmi_off - call FILVRM - jp nmi_on - endif - -print_string: - ld c,a - ld b,0 - ld de,(cursor) - if SMS - ld a,d - and $07 - or $38 - ld d,a - else - ld a,d - and $07 - or $18 - ld d,a - endif - push de - push bc - call nmi_off - if SMS - ex de,hl -.1: ld a,(de) - call WRTVRM - inc de - inc hl - xor a - call WRTVRM - inc hl - dec bc - ld a,b - or c - jp nz,.1 - else - call LDIRVM - endif - call nmi_on - pop bc - pop hl - add hl,bc - if SMS - add hl,bc - endif - ld (cursor),hl - ret - -print_number: - ld b,0 - call nmi_off -print_number5: - ld de,10000 - call print_digit -print_number4: - ld de,1000 - call print_digit -print_number3: - ld de,100 - call print_digit -print_number2: - ld de,10 - call print_digit -print_number1: - ld de,1 - ld b,e - call print_digit - jp nmi_on - -print_digit: - ld a,$2f - or a -.2: inc a - sbc hl,de - jp nc,.2 - add hl,de - cp $30 - jr nz,.3 - ld a,b - or a - ret z - dec a - jr z,.4 - ld a,c - jr print_char -.4: - ld a,$30 -.3: ld b,1 - -print_char: - push hl - ld hl,(cursor) - ex af,af' - ld a,h - and $07 - if SMS - or $38 - else - or $18 - endif - ld h,a - ex af,af' - call WRTVRM - inc hl - if SMS - xor a - call WRTVRM - inc hl - endif - ld (cursor),hl - pop hl - ret - -define_char: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - di - call LDIRVM - ei - ret - else - call nmi_off - ld a,(mode) - and 8 - jr nz,.1 - call LDIRVM3 - jp nmi_on - -.1: call LDIRVM - jp nmi_on - endif - -define_color: - if SMS - ret - else - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d - call nmi_off - call LDIRVM3 - jp nmi_on - endif - -define_sprite: - ex de,hl - ld l,a - ld h,0 - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ld c,l - ld b,h - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - if SMS - set 1,h - else - ld h,$07 - endif - add hl,hl ; x8 - add hl,hl ; x16 - add hl,hl ; x32 - if SMS - add hl,hl ; x64 - endif - ex de,hl - call nmi_off - call LDIRVM - jp nmi_on - endif - -update_sprite: - if SMS - pop bc ; Pop return address. - pop de ; 3th. argument in D (Y-coordinate) - ld e,a ; 4th. argument in E (frame) - pop af ; 2nd. argument in A (X-coordinate) - pop hl ; 1st. argument in H (sprite number) - push bc ; Push return address. - ld l,h - res 7,l - res 6,l - ld h,sprites>>8 - ld (hl),a - sla l - set 7,l - ld (hl),d - inc l - ld (hl),e - else - pop bc - ld (sprite_data+3),a - pop af - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - ld d,sprites>>8 - add a,a - add a,a - if SORD - or $80 - endif - ld e,a - ld hl,sprite_data - ldi - ldi - ldi - ldi - endif - ret - - ; Fast 16-bit multiplication. -_mul16: - ld b,h - ld c,l - ld a,16 - ld hl,0 -.1: - srl d - rr e - jr nc,.2 - add hl,bc -.2: sla c - rl b - dec a - jp nz,.1 - ret - - ; 16-bit signed modulo. - ; hl = hl % de -_mod16s: - ld a,h - or a - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _mod16 - pop af - ret p - jp _neg16 - - ; 16-bit signed division. - ; hl = hl / de -_div16s: - ld a,h - xor d - push af - bit 7,h - call nz,_neg16 - ex de,hl - bit 7,h - call nz,_neg16 - ex de,hl - call _div16 - pop af - ret p - jp _neg16 - -_abs16: - bit 7,h - ret z -_neg16: - ld a,h - cpl - ld h,a - ld a,l - cpl - ld l,a - inc hl - ret - - ; Fast 16-bit division. - ; hl = hl / de -_div16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - rl c - rl b - ld h,b - ld l,c - ret - - ; Fast 16-bit modulo. -_mod16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 - ret - -_sgn16: - ld a,h - or l - ret z - bit 7,h - ld hl,$ffff - ret nz - inc hl - inc hl - ret - - ; Random number generator. - ; From my game Mecha Eight. -random: - ld hl,(lfsr) - ld a,h - or l - jr nz,.0 - ld hl,$7811 -.0: ld a,h - and $80 - ld b,a - ld a,h - and $02 - rrca - rrca - xor b - ld b,a - ld a,h - and $01 - rrca - xor b - ld b,a - ld a,l - and $20 - rlca - rlca - xor b - rlca - rr h - rr l - ld (lfsr),hl - ret - -sn76489_freq: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld b,a - ld a,l - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - and $3f - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_vol: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - cpl - and $0f - or b - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -sn76489_control: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - and $0f - or $e0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - ret - -ay3_reg: - if COLECO - push af - ld a,b - out ($50),a - pop af - out ($51),a - ret - endif - if SG1000+SORD+SMS+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,a - ld a,b - jp WRTPSG - endif - -ay3_freq: - if COLECO - out ($50),a - push af - ld a,l - out ($51),a - pop af - inc a - out ($50),a - push af - ld a,h - and $0f - out ($51),a - pop af - ret - endif - if SG1000+SMS+SORD+MEMOTECH+PV2000 - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld e,l - call WRTPSG - ld e,h - inc a - jp WRTPSG - endif - - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ; Required for SG1000 and Sega Master System as both don't have a BIOS - ; Required for SVI because we don't have access to BIOS in cartridge. - ; Required for Sord M5 because it doesn't provide an ASCII charset. - ; Required for Memotech/Einstein because CP/M uses the memory. - ; My personal font for TMS9928. - ; - ; Patterned after the TMS9928 programming manual 6x8 letters - ; with better lowercase letters, also I made a proper - ; AT sign. - ; -font_bitmaps: - db $00,$00,$00,$00,$00,$00,$00,$00 ; $20 space - db $20,$20,$20,$20,$20,$00,$20,$00 ; $21 ! - db $50,$50,$50,$00,$00,$00,$00,$00 ; $22 " - db $50,$50,$f8,$50,$f8,$50,$50,$00 ; $23 # - db $20,$78,$a0,$70,$28,$f0,$20,$00 ; $24 $ - db $c0,$c8,$10,$20,$40,$98,$18,$00 ; $25 % - db $40,$a0,$40,$a0,$a8,$90,$68,$00 ; $26 & - db $60,$20,$40,$00,$00,$00,$00,$00 ; $27 ' - db $10,$20,$40,$40,$40,$20,$10,$00 ; $28 ( - db $40,$20,$10,$10,$10,$20,$40,$00 ; $29 ) - db $00,$a8,$70,$20,$70,$a8,$00,$00 ; $2a * - db $00,$20,$20,$f8,$20,$20,$00,$00 ; $2b + - db $00,$00,$00,$00,$00,$60,$20,$40 ; $2c , - db $00,$00,$00,$fc,$00,$00,$00,$00 ; $2d - - db $00,$00,$00,$00,$00,$00,$60,$00 ; $2e . - db $00,$08,$10,$20,$40,$80,$00,$00 ; $2f / - db $70,$88,$98,$a8,$c8,$88,$70,$00 ; $30 0 - db $20,$60,$20,$20,$20,$20,$f8,$00 ; $31 1 - db $70,$88,$08,$10,$60,$80,$f8,$00 ; $32 2 - db $70,$88,$08,$30,$08,$88,$70,$00 ; $33 3 - db $30,$50,$90,$90,$f8,$10,$10,$00 ; $34 4 - db $f8,$80,$f0,$08,$08,$08,$f0,$00 ; $35 5 - db $30,$40,$80,$f0,$88,$88,$70,$00 ; $36 6 - db $f8,$08,$10,$20,$20,$20,$20,$00 ; $37 7 - db $70,$88,$88,$70,$88,$88,$70,$00 ; $38 8 - db $70,$88,$88,$78,$08,$10,$60,$00 ; $39 9 - db $00,$00,$00,$60,$00,$60,$00,$00 ; $3a : - db $00,$00,$00,$60,$00,$60,$20,$40 ; $3b ; - db $10,$20,$40,$80,$40,$20,$10,$00 ; $3c < - db $00,$00,$f8,$00,$f8,$00,$00,$00 ; $3d = - db $08,$04,$02,$01,$02,$04,$08,$00 ; $3e > - db $70,$88,$08,$10,$20,$00,$20,$00 ; $3f ? - db $70,$88,$98,$a8,$98,$80,$70,$00 ; $40 @ - db $20,$50,$88,$88,$f8,$88,$88,$00 ; $41 A - db $f0,$88,$88,$f0,$88,$88,$f0,$00 ; $42 B - db $70,$88,$80,$80,$80,$88,$70,$00 ; $43 C - db $f0,$88,$88,$88,$88,$88,$f0,$00 ; $44 D - db $f8,$80,$80,$f0,$80,$80,$f8,$00 ; $45 E - db $f8,$80,$80,$f0,$80,$80,$80,$00 ; $46 F - db $70,$88,$80,$b8,$88,$88,$70,$00 ; $47 G - db $88,$88,$88,$f8,$88,$88,$88,$00 ; $48 H - db $70,$20,$20,$20,$20,$20,$70,$00 ; $49 I - db $08,$08,$08,$08,$88,$88,$70,$00 ; $4A J - db $88,$90,$a0,$c0,$a0,$90,$88,$00 ; $4B K - db $80,$80,$80,$80,$80,$80,$f8,$00 ; $4C L - db $88,$d8,$a8,$a8,$88,$88,$88,$00 ; $4D M - db $88,$c8,$c8,$a8,$98,$98,$88,$00 ; $4E N - db $70,$88,$88,$88,$88,$88,$70,$00 ; $4F O - db $f0,$88,$88,$f0,$80,$80,$80,$00 ; $50 P - db $70,$88,$88,$88,$88,$a8,$90,$68 ; $51 Q - db $f0,$88,$88,$f0,$a0,$90,$88,$00 ; $52 R - db $70,$88,$80,$70,$08,$88,$70,$00 ; $53 S - db $f8,$20,$20,$20,$20,$20,$20,$00 ; $54 T - db $88,$88,$88,$88,$88,$88,$70,$00 ; $55 U - db $88,$88,$88,$88,$50,$50,$20,$00 ; $56 V - db $88,$88,$88,$a8,$a8,$d8,$88,$00 ; $57 W - db $88,$88,$50,$20,$50,$88,$88,$00 ; $58 X - db $88,$88,$88,$70,$20,$20,$20,$00 ; $59 Y - db $f8,$08,$10,$20,$40,$80,$f8,$00 ; $5A Z - db $78,$60,$60,$60,$60,$60,$78,$00 ; $5B [ - db $00,$80,$40,$20,$10,$08,$00,$00 ; $5C \ - db $F0,$30,$30,$30,$30,$30,$F0,$00 ; $5D ] - db $20,$50,$88,$00,$00,$00,$00,$00 ; $5E - db $00,$00,$00,$00,$00,$00,$f8,$00 ; $5F _ - db $40,$20,$10,$00,$00,$00,$00,$00 ; $60 - db $00,$00,$68,$98,$88,$98,$68,$00 ; $61 a - db $80,$80,$f0,$88,$88,$88,$f0,$00 ; $62 b - db $00,$00,$78,$80,$80,$80,$78,$00 ; $63 c - db $08,$08,$68,$98,$88,$98,$68,$00 ; $64 d - db $00,$00,$70,$88,$f8,$80,$70,$00 ; $65 e - db $30,$48,$40,$e0,$40,$40,$40,$00 ; $66 f - db $00,$00,$78,$88,$88,$78,$08,$70 ; $67 g - db $80,$80,$f0,$88,$88,$88,$88,$00 ; $68 h - db $20,$00,$60,$20,$20,$20,$70,$00 ; $69 i - db $08,$00,$18,$08,$88,$88,$70,$00 ; $6a j - db $80,$80,$88,$90,$e0,$90,$88,$00 ; $6b k - db $60,$20,$20,$20,$20,$20,$70,$00 ; $6c l - db $00,$00,$d0,$a8,$a8,$a8,$a8,$00 ; $6d m - db $00,$00,$b0,$c8,$88,$88,$88,$00 ; $6e n - db $00,$00,$70,$88,$88,$88,$70,$00 ; $6f o - db $00,$00,$f0,$88,$88,$88,$f0,$80 ; $70 p - db $00,$00,$78,$88,$88,$88,$78,$08 ; $71 q - db $00,$00,$b8,$c0,$80,$80,$80,$00 ; $72 r - db $00,$00,$78,$80,$70,$08,$f0,$00 ; $73 s - db $20,$20,$f8,$20,$20,$20,$20,$00 ; $74 t - db $00,$00,$88,$88,$88,$98,$68,$00 ; $75 u - db $00,$00,$88,$88,$88,$50,$20,$00 ; $76 v - db $00,$00,$88,$a8,$a8,$a8,$50,$00 ; $77 w - db $00,$00,$88,$50,$20,$50,$88,$00 ; $78 x - db $00,$00,$88,$88,$98,$68,$08,$70 ; $79 y - db $00,$00,$f8,$10,$20,$40,$f8,$00 ; $7a z - db $18,$20,$20,$40,$20,$20,$18,$00 ; $7b { - db $20,$20,$20,$20,$20,$20,$20,$00 ; $7c | - db $c0,$20,$20,$10,$20,$20,$c0,$00 ; $7d } - db $00,$00,$40,$a8,$10,$00,$00,$00 ; $7e - db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f - endif - - if MSX&2 -palette_default: - ld hl,msx2_default_palette -palette_load: - ld bc,$0010 - di - call WRTVDP - ld bc,32*256+VDP+2 - otir - ei - ret - -msx2_default_palette: - dw $000,$000,$611,$733,$117,$327,$151,$627 - dw $171,$373,$661,$664,$411,$265,$555,$777 - -define_sprite_color: - ex de,hl - add a,a ; x2 - add a,a ; x4 - add a,a ; x8 - add a,a ; x16 - ld c,a - ld b,0 - rl b - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ld h,$40/2 - add hl,hl ; x16 - ex de,hl - di - call LDIRVM - ei - ret - -update_sprite2: - pop bc - ld (sprite_data+2),a - pop af - ld (sprite_data+1),a - pop af - ld (sprite_data),a - pop af - ; A = Sprite number - push bc - ld d,sprites>>8 - add a,a - add a,a - ld e,a - ld hl,sprite_data - ldi - ldi - ldi - ret - - ; - ; Register that must be set for V9938 (MSX2) because larger VRAM: - ; Reg. 2 = 0 A16 A15 A14 A13 A12 A11 A10 Pattern name table. - ; Reg. 3 = A13 1 1 1 1 1 1 1 Color table (reg. D) - ; Reg. 10= 0 0 0 0 0 A16 A15 A14 Color table high bits. - ; Reg. 4 = 0 0 A16 A15 A14 A13 1 1 Bitmap table (reg. E) - ; Reg. 5 = A14 A13 A12 A11 A10 A9 1 1 Sprite attribute table... - ; Reg. 11= 0 0 0 0 0 0 A16 A15 ...and high bits. - ; Reg. 6 = 0 0 A16 A15 A14 A13 A12 A11 Sprite pattern generator - ; -mode_4: - ld hl,mode - res 3,(hl) - set 4,(hl) - ld bc,$0400 ; Normal mode but with enhanced sprites enabled. - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - ld bc,$000a ; Reg. 10 (high bits of color table) - call WRTVDP - ; The value $84 seems logical but it makes colors - ; for sprites 0-7 replicate in sprites 8-15, - ; 16-23, and 24-31. Not described in Yamaha docs, - ; but emulated by OpenMSX and BlueMSX. - ld bc,$8705 ; $4200 for sprite attribute table... - call WRTVDP ; ...so sprite colors appear at $4000-$41ff. - ld bc,$000b ; Reg. 11 (high bits of sprite attribute table) - call WRTVDP - ld hl,($0004) - inc h - ld de,$0100 - ld bc,$0300 - call LDIRVM3 - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - call cls - jp vdp_generic_sprites - endif - - if SMS -palette_default: - ld hl,sms_default_palette -palette_load: - push hl - di - ld hl,$c000 - call SETWRT - pop hl - ld bc,32*256+VDP - outi - jp nz,$-2 - ei - ret - - ; TMS9118-alike palette -sms_default_palette: - db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f - db $00,$00,$0c,$2e,$20,$30,$02,$3c,$17,$2B,$0f,$2f,$08,$33,$2a,$3f - -mode_4: - di - ld bc,$0400 - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0f02 ; $3800 for pattern table (required bit 0 set to 1 for SMS1) - call WRTVDP - ld bc,$ff03 ; Not used (required value for SMS1) - call WRTVDP - ld bc,$0704 ; Not used (required value for SMS1) - call WRTVDP - ld bc,$7f05 ; $3f00 for sprite attribute table (required bit 0 set to 1) - call WRTVDP - ld bc,$0706 ; $2000 for sprites bitmaps (or $03 for $0000) - call WRTVDP - ld bc,$0007 - call WRTVDP - ld bc,$0008 ; Background X scroll - call WRTVDP - ld bc,$0009 ; Background Y scroll - call WRTVDP - ld hl,$20*32 ; Point to space character bitmap - call SETWRT - ld hl,font_bitmaps - ld c,96 -.1: ld b,8 -.2: ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - ld a,(hl) - out (VDP),a - inc hl - djnz .2 - dec c - jp nz,.1 - ei - call cls - di - ld hl,$3f00 - ld bc,$0040 - ld a,$e0 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,63 - ld (hl),$e0 - ldir - ei - call palette_default - jp ENASCR - - else -vdp_generic_mode: - call nmi_off - call WRTVDP - ld bc,$a201 - call WRTVDP - ld bc,$0602 ; $1800 for pattern table. - call WRTVDP - ld b,d - ld c,$03 ; for color table. - call WRTVDP - ld b,e - ld c,$04 ; for bitmap table - call WRTVDP - ld bc,$3605 ; $1b00 for sprite attribute table. - call WRTVDP - ld bc,$0706 ; $3800 for sprites bitmaps. - call WRTVDP - ld bc,$0107 - jp WRTVDP - -mode_0: - ld hl,mode - res 3,(hl) - res 4,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM3 - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - call cls -vdp_generic_sprites: - call nmi_off - ld a,(mode) - bit 4,a - ld hl,$1b00 - ld a,$d1 - jr z,$+6 - ld h,$42 - ld a,$e0 - ld bc,$0080 - call FILVRM - ld hl,sprites - ld de,sprites+1 - ld bc,127 - ld (hl),a - ldir - call nmi_on - jp ENASCR - -mode_1: - ld hl,mode - res 3,(hl) - res 4,(hl) - ld bc,$0200 - ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - ld hl,$0000 - ld bc,$1800 - xor a - call FILVRM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$1800 - ld a,$f0 - call FILVRM - call nmi_on - ld hl,$1800 -.1: call nmi_off - ld b,32 -.2: ld a,l - call WRTVRM - inc hl - djnz .2 - call nmi_on - ld a,h - cp $1b - jp nz,.1 - jp vdp_generic_sprites - -mode_2: - ld hl,mode - set 3,(hl) - res 4,(hl) - ld bc,$0000 - ld de,$8000 ; $2000 for color table, $0000 for bitmaps. - call vdp_generic_mode - if COLECO - if PENCIL - ld hl,($0013) - else - ld hl,($006c) - endif - ld de,-128 - add hl,de - endif - if SG1000+SMS+SVI+SORD+MEMOTECH+EINSTEIN+PV2000+NABU - ld hl,font_bitmaps - endif - if MSX - ld hl,($0004) - inc h - endif - ld de,$0100 - ld bc,$0300 - call LDIRVM - call nmi_on - call nmi_off - ld hl,$2000 - ld bc,$0020 - ld a,$f0 - call FILVRM - call nmi_on - call cls - jp vdp_generic_sprites - endif - - if MSX -ENASLT: EQU $0024 ; Select slot (H=Addr, A=Slot) -RSLREG: EQU $0138 ; Read slot status in A - - ; - ; Get slot mapping - ; B = 16K bank (0 for $0000, 1 for $4000, 2 for $8000, 3 for $c000) - ; A = Current slot selection status (CALL RSLREG) - ; -get_slot_mapping: - call rotate_slot - ld c,a - add a,$C1 ; EXPTBL - ld l,a - ld h,$FC - ld a,(hl) - and $80 ; Get expanded flag - or c - ld c,a - inc hl - inc hl - inc hl - inc hl - ld a,(hl) ; SLTTBL - call rotate_slot - rlca - rlca - or c ; A contains bit 7 = Marks expanded - ; bit 6 - 4 = Doesn't care - ; bit 3 - 2 = Secondary mapper - ; bit 1 - 0 = Primary mapper - ret - -rotate_slot: - push bc - dec b - inc b - jr z,.1 -.0: rrca - rrca - djnz .0 -.1: and 3 - pop bc - ret - - endif - -nmi_handler: - push af - push hl - ld hl,mode - bit 0,(hl) - jr z,.1 - set 1,(hl) - pop hl - pop af - retn - -.0: res 1,(hl) - -.1: push bc - push de - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fbf) - endif - if MSX - ld a,($bfff) - endif - push af - endif - if SORD+MEMOTECH - call ctc_reti - endif - if SG1000+SMS+MSX+SVI+SORD+MEMOTECH+NABU - in a,(VDPR+1) - ld (vdp_status),a - endif - - ; - ; Update of sprite attribute table - ; - if SMS - bit 2,(hl) - jr z,.4 - ld hl,$3f00 - call SETWRT - ld hl,sprites - ld bc,$4000+VDP - outi - jp nz,$-2 - ld hl,$3f80 - call SETWRT - ld hl,sprites+128 - ld bc,$8000+VDP - outi - jp nz,$-2 - jr .5 - -.4: ld hl,$3f00 - call SETWRT - ld a,(flicker) - inc a - and $3f - ld (flicker),a - ld l,a - ld h,sprites>>8 - ld bc,$4000+VDP - ld de,6 - outi - add hl,de - res 6,l - jp nz,$-5 - ld hl,$3f80 - call SETWRT - ld a,(flicker) - add a,a - or $80 - ld l,a - ld bc,$8000+VDP - ld de,12 - ld h,sprites>>8 - outi - nop - nop - nop - outi - add hl,de - set 7,l - jp nz,$-12 -.5: - else - ld bc,$8000+VDP - bit 2,(hl) - jr z,.4 - bit 4,(hl) - ld hl,$1b00 - jr z,$+4 -.10: - ld h,$42 - call SETWRT - ld hl,sprites -.7: - if MSX&2 - outi - outi - outi - outi - jp nz,.7 - else - if PV2000 - ld a,(hl) - ld (VDP),a - inc hl - djnz .7 - else - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp nz,.7 - endif - endif - jr .5 - -.4: - bit 4,(hl) - ld hl,$1b00 - jr nz,.10 ; No flicker sprites in MSX2 (MODE 4) - call SETWRT - ld a,(flicker) - add a,$04 - ld (flicker),a - ld de,24 - ld b,128 - ld l,a - if SORD - else - ld h,sprites>>8 - endif -.6: - if SORD - set 7,l - ld h,sprites>>8 - else - res 7,l - endif - if PV2000 - ld a,(hl) ; 7 8 - ld (VDP),a ; 13 14 - inc hl ; 6 7 - dec b ; 4 5 - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - ld a,(hl) - ld (VDP),a - inc hl - dec b - else - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - outi - jp $+3 - if MEMOTECH+EINSTEIN+SG1000 - nop - nop - endif - endif - add hl,de - jp nz,.6 -.5: - endif - - if COLECO - if COLECO_SPINNER - DI - endif - out (JOYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - or $b0 - ld b,a - in a,(JOY2) - if COLECO_SPINNER - EI - endif - or $b0 - ld c,a - - if COLECO_SPINNER - DI - endif - out (KEYSEL),a - ex (sp),hl - ex (sp),hl - in a,(JOY1) - ld d,a - in a,(JOY2) - if COLECO_SPINNER - EI - endif - ld e,a - - ld a,d - rlca - or $7f - and b - cpl - ld (joy1_data),a - - ld a,e - rlca - or $7f - and c - cpl - ld (joy2_data),a - - ld a,d - and $0f - ld c,a - ld b,0 - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key1_data),a - - ld a,e - and $0f - ld c,a - ld hl,keypad_table - add hl,bc - ld a,(hl) - ld (key2_data),a - endif - if SG1000+SMS - ld a,$07 - out ($de),a - ld b,$ff - in a,(JOY1) - ld h,a - in a,(JOY2) - ld l,a - in a,($de) - cp 7 - jp nz,.sg1000 - - ld a,$00 - out ($de),a - in a,($dc) - rra - ld c,1 - jr nc,.sg1 - in a,($dd) - rra - ld c,8 - jr nc,.sg1 - ld a,$01 - out ($de),a - in a,($dc) - rra - ld c,2 - jr nc,.sg1 - in a,($dd) - rra - ld c,9 - jr nc,.sg1 - ld a,$02 - out ($de),a - in a,($dc) - rra - ld c,3 - jr nc,.sg1 - in a,($dd) - rra - ld c,0 - jr nc,.sg1 - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a - ld c,10 - jr z,.sg1 - rra - ld c,4 - jr nc,.sg1 - ld a,$04 - out ($de),a - in a,($dc) - rra - ld c,5 - jr nc,.sg1 - ld a,$05 - out ($de),a - in a,($dc) - bit 6,a - ld c,11 - jr z,.sg1 - rra - ld c,6 - jr nc,.sg1 - ld a,$06 - out ($de),a - in a,($dc) - rra - ld c,7 - jr nc,.sg1 - ld c,15 -.sg1: ld a,c - ld (key1_data),a - - ld a,$04 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard down. - jr nz,$+4 - res 1,h - ld a,$05 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard left. - jr nz,$+4 - res 2,h - ld a,$06 - out ($de),a - in a,($dc) - bit 5,a ; Keyboard right. - jr nz,$+4 - res 3,h - bit 6,a ; Keyboard up. - jr nz,$+4 - res 0,h - ld a,$02 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Ins - jr nz,$+4 - res 4,h - ld a,$03 - out ($de),a - in a,($dc) - bit 4,a ; Keyboard Del - jr nz,$+4 - res 5,h -.sg1000: - bit 0,h - jr nz,$+4 - res 0,b - bit 1,h - jr nz,$+4 - res 2,b - bit 2,h - jr nz,$+4 - res 3,b - bit 3,h - jr nz,$+4 - res 1,b - bit 4,h - jr nz,$+4 - res 6,b - bit 5,h - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - - ld a,$ff - bit 6,h - jr nz,$+4 - res 0,a - bit 7,h - jr nz,$+4 - res 2,a - - bit 0,l - jr nz,$+4 - res 3,a - bit 1,l - jr nz,$+4 - res 1,a - bit 2,l - jr nz,$+4 - res 4,a - bit 3,l - jr nz,$+4 - res 5,a - cpl - ld (joy2_data),a - - endif - if MSX - ; Keyboard matrix from https://map.grauw.nl/articles/keymatrix.php - ld a,15 - call RDPSG - and $d0 - or $4c ; Read joystick 2. - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - ld b,$ff - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - ld a,b - cpl - ld (joy2_data),a - - in a,($aa) - and $f0 - or $00 - out ($aa),a - in a,($a9) - cp $ff - ld c,$ff - jr nz,.key1 - in a,($aa) - and $f0 - or $01 - out ($aa),a - in a,($a9) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - in a,($aa) - and $f0 - or $07 - out ($aa),a - in a,($a9) - bit 5,a ; BS - ld c,$0a - jr z,.key2 - bit 7,a ; RET - ld c,$0b - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - in a,($aa) - and $f0 - or $08 - out ($aa),a - in a,($a9) - bit 5,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 6,a - jr nz,$+4 - res 2,b - bit 4,a - jr nz,$+4 - res 3,b - bit 0,a - jr nz,$+4 - res 6,b - in a,($aa) - and $f0 - or $04 - out ($aa),a - in a,($a9) - bit 2,a - jr nz,$+4 - res 7,b - - ld a,15 - call RDPSG - and $a0 - or $03 ; Read joystick 1. - ld e,a - ld a,15 - call WRTPSG - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - bit 4,a - jr nz,$+4 - res 6,b - bit 5,a - jr nz,$+4 - res 7,b - - ld a,b - cpl - ld (joy1_data),a - endif - if SVI - ld a,14 - call RDPSG - ld b,$ff - bit 4,a - jr nz,$+4 - res 0,b - bit 7,a - jr nz,$+4 - res 1,b - bit 5,a - jr nz,$+4 - res 2,b - bit 6,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 5,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy2_data),a - - ld a,$10 - out ($96),a - in a,($99) - cp $ff - ld c,$ff - jr nz,.key1 - ld a,$11 - out ($96),a - in a,($99) - and $03 - cp $03 - ld c,$07 - jr nz,.key1 - ld a,$16 - out ($96),a - in a,($99) - bit 6,a - ld c,$0b - jr z,.key2 - ld a,$15 - out ($96),a - in a,($99) - bit 6,a - ld c,$0a - jr z,.key2 - ld c,$0f - jr .key2 - -.key1: rra - inc c - jr c,.key1 -.key2: - ld a,c - ld (key1_data),a - - ld b,$ff - ld a,$15 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 0,b - ld a,$18 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 1,b - ld a,$17 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 2,b - ld a,$16 - out ($96),a - in a,($99) - bit 7,a - jr nz,$+4 - res 3,b - ld a,$18 - out ($96),a - in a,($99) - bit 0,a - jr nz,$+4 - res 6,b - ld a,$13 - out ($96),a - in a,($99) - bit 5,a - jr nz,$+4 - res 7,b - - ld a,14 - call RDPSG - bit 0,a - jr nz,$+4 - res 0,b - bit 3,a - jr nz,$+4 - res 1,b - bit 1,a - jr nz,$+4 - res 2,b - bit 2,a - jr nz,$+4 - res 3,b - - in a,($98) - bit 4,a - jr nz,$+4 - res 6,b - ld a,b - cpl - ld (joy1_data),a - endif - if SORD - ld bc,$ffff - in a,($37) ; Read joystick - rra - jr nc,$+4 - res 1,b - rra - jr nc,$+4 - res 0,b - rra - jr nc,$+4 - res 3,b - rra - jr nc,$+4 - res 2,b - rra - jr nc,$+4 - res 1,c - rra - jr nc,$+4 - res 0,c - rra - jr nc,$+4 - res 3,c - rra - jr nc,$+4 - res 2,c - in a,($31) - rra - jr nc,$+4 - res 6,b - rra - jr nc,$+4 - res 7,b - rra - rra - rra - jr nc,$+4 - res 6,c - rra - jr nc,$+4 - res 7,c - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - in a,($31) ; Keyboard 1-8 - or a - ld c,$00 - jr nz,.key3 - in a,($35) - bit 0,a ; 9 - ld c,$09 - jr nz,.key5 - bit 1,a ; 0 - ld c,$00 - jr nz,.key5 - bit 7,a ; Backspace - ld c,$0a - jr nz,.key5 - in a,($30) - bit 7,a ; Enter - ld c,$0b - jr nz,.key5 - ld c,$0f - jr .key5 - -.key3: rra - inc c - jr nc,.key3 -.key5: - ld a,c - ld (key1_data),a - - endif - if MEMOTECH - ld bc,$ffff - - ld a,$fb - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 0,b ; Up direction. - bit 3,a ; Y - jr nz,$+4 - res 0,c ; Up direction. - - ld a,$ef - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 1,b ; Right key. - ld a,$bf - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 2,b ; Down key. - ld a,$f7 - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a - jr nz,$+4 - res 3,b ; Left key. - ld a,$df - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 7,a ; Home key. - jr nz,$+4 - res 6,b ; Button 1 - - ld a,$7F - out ($05),a ; Select keyboard row. - ex (sp),hl - ex (sp),hl - in a,($05) ; Read keyboard data. - bit 2,a ; B - jr nz,$+4 - res 0,c ; Up key. - bit 1,a ; C - jr nz,$+4 - res 1,c ; Right key. - bit 3,a ; M - jr nz,$+4 - res 2,c ; Down key. - bit 0,a ; Z - jr nz,$+4 - res 3,c ; Left key. - bit 5,a ; - - jr nz,$+4 - res 7,c ; Button 2 for player 2. - bit 7,a ; - - jr nz,$+4 - res 7,b ; Button 2 for player 1. - in a,($06) ; Read keyboard data. - bit 0,a ; Space - jr nz,$+4 - res 6,c ; Button 1. - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$fe - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - ld b,1 - jr nc,.mt1 - rra - ld b,3 - jr nc,.mt1 - rra - ld b,5 - jr nc,.mt1 - rra - ld b,7 - jr nc,.mt1 - rra - ld b,9 - jr nc,.mt1 - ld a,$df - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - bit 6,a - ld b,11 - jr z,.mt1 - ld a,$fd - out ($05),a - ex (sp),hl - ex (sp),hl - in a,($05) - rra - rra - ld b,2 - jr nc,.mt1 - rra - ld b,4 - jr nc,.mt1 - rra - ld b,6 - jr nc,.mt1 - rra - ld b,8 - jr nc,.mt1 - rra - ld b,0 - jr nc,.mt1 - in a,($06) - rra - ld b,10 - jr nc,.mt1 - ld b,15 -.mt1: - ld a,b - ld (key1_data),a - endif - if EINSTEIN - ld bc,$ffff - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 0,b ; Up - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 4,a - jr nz,$+4 - res 1,b ; Right - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - jr nz,$+4 - res 2,b ; Down - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - jr nz,$+4 - res 3,b ; Left - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - jr nz,$+4 - res 6,b ; Fire - ld a,$0e - out ($02),a - ld a,$7f - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 0,a - jr nz,$+4 - res 7,b ; 2nd fire - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - - ld a,$0e - out ($02),a - ld a,$ef - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - rra - ld b,7 - jr nc,.te1 - rra - ld b,6 - jr nc,.te1 - rra - ld b,5 - jr nc,.te1 - rra - ld b,4 - jr nc,.te1 - rra - ld b,3 - jr nc,.te1 - rra - ld b,2 - jr nc,.te1 - rra - ld b,1 - jr nc,.te1 - ld a,$0e - out ($02),a - ld a,$f7 - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 3,a - ld b,8 - jr z,.te1 - bit 4,a - ld b,10 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fb - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 6,a - ld b,9 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fe - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 5,a - ld b,11 - jr z,.te1 - ld a,$0e - out ($02),a - ld a,$fd - out ($03),a - ex (sp),hl - ex (sp),hl - ld a,$0f - out ($02),a - in a,($02) - bit 7,a - ld b,0 - jr z,.te1 - ld b,15 -.te1: - ld a,b - ld (key1_data),a - endif - if PV2000 - ld bc,$ffff - ld a,7 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 0,b - bit 0,a - jr z,$+4 - res 3,b - ld a,6 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 1,a - jr z,$+4 - res 1,b - bit 0,a - jr z,$+4 - res 2,b - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - bit 0,a - jr z,$+4 - res 6,b - bit 1,a - jr z,$+4 - res 7,b - ld a,b - cpl - ld (joy1_data),a - ld a,c - cpl - ld (joy2_data),a - ld a,0 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - and $0f - ld b,$04 - jr nz,.pv1 - in a,($10) - and $0f - ld b,$08 - jr nz,.pv1 - ld a,8 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($10) - ld b,11 - bit 0,a - jr nz,.pv2 - ld a,4 - out ($20),a - ex (sp),hl - ex (sp),hl - in a,($20) - ld b,10 - bit 3,a - jr nz,.pv2 - in a,($10) - ld b,9 - bit 0,a - jr nz,.pv2 - ld b,0 - bit 3,a - jr nz,.pv2 - ld b,15 - jr .pv2 - -.pv1: rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b - rra - jr c,.pv2 - dec b -.pv2: ld a,b - ld (key1_data),a - endif - if NABU - ld a,(nabu_data0) - and $cf - ld (joy1_data),a - ld a,(nabu_data1) - and $cf - ld (joy2_data),a - ld a,(nabu_data2) - ld (key1_data),a - ld a,$0f - ld (nabu_data2),a - endif - - if CVBASIC_MUSIC_PLAYER - ld a,(music_mode) - or a - call nz,music_hardware - endif - - ld hl,(frame) - inc hl - ld (frame),hl - - ld hl,lfsr ; Make LFSR more random - inc (hl) - inc (hl) - inc (hl) - - if CVBASIC_MUSIC_PLAYER - ; - ; Music is played with a 50hz clock. - ; - ld a,(ntsc) - or a - jr z,.2 - ld a,(music_tick) - inc a - cp 6 - jr nz,$+3 - xor a - ld (music_tick),a - jr z,.3 -.2: - ld a,(music_mode) - or a - call nz,music_generate -.3: - endif - - if CVBASIC_BANK_SWITCHING - pop af - if COLECO - ld l,a - ld h,$ff - ld a,(hl) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - if KONAMI - ld ($8000),a - inc a - ld ($a000),a - else - ld ($7000),a - endif - endif - endif - pop de - pop bc - pop hl - if COLECO - in a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - if SG1000+SMS+SVI+NABU - pop af - ei - reti - endif - if MSX - pop af - ret - endif - if SORD+MEMOTECH - pop af - ei - ret - -ctc_reti: - reti - endif - if EINSTEIN - pop af - ret - endif - if PV2000 - ld a,(VDP+1) - ld (vdp_status),a - pop af - retn - endif - - if NABU -keyboard_handler: - push af - push bc - push hl - in a,($90) - ld c,a - cp $0d ; Enter - ld a,11 - jr z,.8 - ld a,c - cp $7f ; Del - ld a,10 - jr z,.8 - ld a,c - cp $30 - jr c,.7 - cp $3a - jr nc,.7 - sub $30 -.8: ld (nabu_data2),a - jr .1 -.7: - cp $a0 ; Is it data for joystick? - jr c,.2 - cp $c0 - jr c,.joystick ; Yes, jump. -.2: - ld hl,nabu_data0 - cp $80 - jr nz,.3 - res 4,(hl) ; Now data for joystick 1. - jr .1 -.3: - cp $81 - jr nz,.4 - set 4,(hl) ; Now data for joystick 2. - jr .1 -.4: - cp $e0 ; Keys with up/down event? - jr c,.1 ; No, jump. - and $0f ; Arrow right - ld b,2 - jr z,.5 - dec a ; Arrow left - ld b,8 - jr z,.5 - dec a ; Arrow up - ld b,1 - jr z,.5 - dec a ; Arrow down - ld b,4 - jr z,.5 - dec a ; |||> - ld b,$80 - jr z,.5 - dec a ; <||| - ld b,$40 - jr nz,.1 -.5: bit 4,c - jr nz,.6 ; Jump if depress event. - ld a,(hl) - or b ; Key pressed. - ld (hl),a - jr .1 - -.6: - ld a,b - cpl - and (hl) ; Key depressed. - ld (hl),a - jr .1 - -.joystick: - ld hl,nabu_data0 - bit 4,(hl) - jr z,$+5 - ld hl,nabu_data1 - ld b,$00 - bit 3,c - jr z,$+4 - set 0,b - bit 2,c - jr z,$+4 - set 1,b - bit 1,c - jr z,$+4 - set 2,b - bit 0,c - jr z,$+4 - set 3,b - bit 4,c - jr z,$+4 - set 6,b - ld (hl),b -.1: - pop hl - pop bc - pop af - ei - reti - endif - if SORD -wait: - ld de,(frame) -.1: - ld hl,(frame) - or a - sbc hl,de - jr z,.1 - ret - endif - if EINSTEIN -wait: - in a,(VDP+1) - nop - in a,(VDP+1) - bit 7,a - jr z,$-4 - ld (vdp_status),a - jp nmi_handler - endif - - ; - ; The music player code comes from my - ; game Princess Quest for Colecovision (2012) - ; - - ; - ; Init music player. - ; -music_init: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$9f - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$bf - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$df - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ff - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,$ec - out (PSG),a - if MEMOTECH - in a,($03) - endif - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 -MIX_BASE: equ $b8 - endif - if EINSTEIN+NABU -MIX_BASE: equ $78 - endif - if MSX+SVI+EINSTEIN+NABU - ld a,$08 - ld e,$00 - call WRTPSG - ld a,$09 - ld e,$00 - call WRTPSG - ld a,$0a - ld e,$00 - call WRTPSG - ld a,$07 - ld e,MIX_BASE - call WRTPSG - if FM_SUPPORT - ld a,7 - ld ($7000),a - ld a,(fm_slot) - inc a - call nz,init_fm - endif - endif - if SGM - ld b,$08 - xor a - call ay3_reg - ld b,$09 - call ay3_reg - ld b,$0a - call ay3_reg - ld b,$07 - ld a,$b8 - call ay3_reg - endif - if CVBASIC_MUSIC_PLAYER - else - ret - endif - - if CVBASIC_MUSIC_PLAYER - ld a,$ff - ld (audio_vol4hw),a - ld a,$ec - ld (audio_control),a - ld a,MIX_BASE - ld (audio_mix),a - ld hl,music_silence - ; - ; Play a music. - ; HL = Pointer to music. - ; -music_play: - call nmi_off - ld a,(hl) - ld (music_timing),a - inc hl - ld (music_start),hl - ld (music_pointer),hl - xor a - ld (music_note_counter),a - inc a - ld (music_playing),a - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffbf) - endif - if SG1000+SMS - ld a,($7fbf) - endif - if MSX - ld a,($bfff) - endif - ld (music_bank),a - endif - jp nmi_on - - ; - ; Generates music. - ; -music_generate: - ld a,(audio_mix) - and $c0 - or $38 - ld (audio_mix),a - xor a ; Turn off all the sound channels. - ld l,a - ld h,a - ld (audio_vol1),hl ; audio_vol1/audio_vol2 - ld (audio_vol3),a - ld a,$ff - ld (audio_vol4hw),a - - if MSX - if FM_SUPPORT - ld a,(fm_enabled) - or a - jp z,.fm1 - ld a,(fm_slot) - inc a - jp z,.fm1 - ld a,(music_note_counter) - or a - ld a,$07 - ld ($7000),a - jp nz,music_generate_fm.6 - ld hl,(music_pointer) -.fm15: push hl - if CVBASIC_BANK_SWITCHING - ld a,(music_bank) - if SG1000+SMS - ld ($fffe),a - endif - if MSX - if KONAMI - ld ($8000),a - inc a - ld ($a000),a - else - ld ($7000),a - endif - endif - endif - ld b,(hl) - inc hl - ld c,(hl) - inc hl - ld d,(hl) - inc hl - ld e,(hl) - pop hl - ld a,(music_timing) - rlca - jr nc,.fm16 - ld e,d - ld d,0 - jr .fm17 - -.fm16: rlca - jr nc,.fm17 - ld e,0 -.fm17: ld a,b ; Read first byte. - cp -2 ; End of music? - jr nz,.fm19 ; No, jump. - xor a ; Keep at same place. - ld (music_playing),a - ret - -.fm19: cp -3 ; Repeat music? - ld a,$07 - ld ($7000),a - jp nz,music_generate_fm.0 - ld hl,(music_start) - jr .fm15 - -.fm1: - endif - endif - - ld a,(music_note_counter) - or a - jp nz,.6 - ld hl,(music_pointer) -.15: push hl - if CVBASIC_BANK_SWITCHING - ld a,(music_bank) - if COLECO - ld e,a - ld d,$ff - ld a,(de) - endif - if SG1000+SMS - ld ($fffe),a - endif - if MSX - if KONAMI - ld ($8000),a - inc a - ld ($a000),a - else - ld ($7000),a - endif - endif - endif - ld b,(hl) - inc hl - ld c,(hl) - inc hl - ld d,(hl) - inc hl - ld e,(hl) - pop hl - ld a,(music_timing) - rlca - jr nc,.16 - ld e,d - ld d,0 - jr .17 - -.16: rlca - jr nc,.17 - ld e,0 -.17: ld a,b ; Read first byte. - cp -2 ; End of music? - jr nz,.19 ; No, jump. - xor a ; Keep at same place. - ld (music_playing),a - ret - -.19: cp -3 ; Repeat music? - jp nz,.0 - ld hl,(music_start) - jr .15 - -.0: ld a,(music_timing) - and $3f ; Restart note time. - ld (music_note_counter),a - ld a,b - cp $3f ; Sustain? - jr z,.1 - rlca - rlca - and 3 - ld (music_instrument_1),a - ld a,b - and $3f - ld (music_note_1),a - xor a - ld (music_counter_1),a -.1: ld a,c - cp $3f - jr z,.2 - rlca - rlca - and 3 - ld (music_instrument_2),a - ld a,c - and $3f - ld (music_note_2),a - xor a - ld (music_counter_2),a -.2: ld a,d - cp $3f - jr z,.3 - rlca - rlca - and 3 - ld (music_instrument_3),a - ld a,d - and $3f - ld (music_note_3),a - xor a - ld (music_counter_3),a -.3: ld a,e - ld (music_drum),a - xor a - ld (music_counter_4),a - inc hl - inc hl - inc hl - ld a,(music_timing) - and $c0 - jr nz,.14 - inc hl -.14: ld (music_pointer),hl - -.6: ld a,(music_note_1) - or a - jr z,.7 - ld bc,(music_instrument_1) - call music_note2freq - ld (audio_freq1),hl - ld (audio_vol1),a - -.7: ld a,(music_note_2) - or a - jr z,.8 - ld bc,(music_instrument_2) - call music_note2freq - ld (audio_freq2),hl - ld (audio_vol2),a - -.8: ld a,(music_note_3) - or a - jr z,.9 - ld bc,(music_instrument_3) - call music_note2freq - ld (audio_freq3),hl - ld (audio_vol3),a - -.9: ld a,(music_drum) - or a - jr z,.4 - dec a ; 1 - Long drum. - jr nz,.5 - ld a,(music_counter_4) - cp 3 - jp nc,.4 -.10: ld a,5 - ld (audio_noise),a - call enable_drum - jr .4 - -.5: dec a ; 2 - Short durm. - jr nz,.11 - ld a,(music_counter_4) - or a - jp nz,.4 - ld a,8 - ld (audio_noise),a - call enable_drum - jr .4 - -.11: ;dec a ; 3 - Roll. - ;jp nz,.4 - ld a,(music_timing) - and $3e - rrca - ld b,a - ld a,(music_counter_4) - cp 2 - jp c,.10 - cp b - jp c,.4 - dec a - dec a - cp b - jp c,.10 -.4: - ld a,(music_counter_1) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_1),a - - ld a,(music_counter_2) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_2),a - - ld a,(music_counter_3) - inc a - cp $18 - jp nz,$+5 - sub $08 - ld (music_counter_3),a - - ld hl,music_counter_4 - inc (hl) - ld hl,music_note_counter - dec (hl) - ret - - ; - ; Converts note to frequency. - ; Input: - ; A = Note (1-62). - ; B = Instrument counter. - ; C = Instrument. - ; Output: - ; HL = Frequency. - ; A = Volume. - ; -music_note2freq: - add a,a - ld e,a - ld d,0 - ld hl,music_notes_table - add hl,de - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - ld a,c - or a - jp z,music_piano - dec a - jp z,music_clarinet - dec a - jp z,music_flute - ; - ; Bass instrument. - ; -music_bass: - add hl,hl - - ; - ; Piano instrument. - ; -music_piano: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ret - -.1: - db 12,11,11,10,10,9,9,8 - db 8,7,7,6,6,5,5,4 - db 4,4,5,5,4,4,3,3 - - ; - ; Clarinet instrument. - ; -music_clarinet: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - srl h - rr l - jp nc,.2 - inc hl -.2: ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - db 2,4,2,0 - db -2,-4,-2,0 - - db 13,14,14,13,13,12,12,12 - db 11,11,11,11,12,12,12,12 - db 11,11,11,11,12,12,12,12 - - ; - ; Flute instrument. - ; -music_flute: - ld a,b - add a,.1&255 - ld c,a - adc a,.1>>8 - sub c - ld b,a - ld a,(bc) - ld e,a - rlca - sbc a,a - ld d,a - add hl,de - ld a,c - add a,24 - ld c,a - jr nc,$+3 - inc b - ld a,(bc) - ret - -.1: - db 0,0,0,0 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - db 0,1,2,1 - - db 10,12,13,13,12,12,12,12 - db 11,11,11,11,10,10,10,10 - db 11,11,11,11,10,10,10,10 - - ; - ; Emit sound. - ; -music_hardware: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.7 ; Yes, jump. - ld a,(audio_vol2) - or a - jp nz,.7 - ld a,(audio_vol3) - or a - jp z,.7 - ld (audio_vol2),a - xor a - ld (audio_vol3),a - ld hl,(audio_freq3) - ld (audio_freq2),hl -.7: - ld hl,(audio_freq1) - ld a,h - cp 4 - ld a,$9f - jp nc,.1 - ld a,l - and $0f - or $80 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol1) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $90 -.1: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld hl,(audio_freq2) - ld a,h - cp 4 - ld a,$bf - jp nc,.2 - ld a,l - and $0f - or $a0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol2) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $b0 -.2: out (PSG),a - if MEMOTECH - in a,($03) - endif - - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.6 ; Yes, jump. - - ld hl,(audio_freq3) - ld a,h - cp 4 - ld a,$df - jp nc,.3 - ld a,l - and $0f - or $c0 - out (PSG),a - if MEMOTECH - in a,($03) - endif - add hl,hl - add hl,hl - add hl,hl - add hl,hl - ld a,h - out (PSG),a - if MEMOTECH - in a,($03) - endif - ld a,(audio_vol3) - add a,ay2sn&255 - ld l,a - adc a,ay2sn>>8 - sub l - ld h,a - ld a,(hl) - or $d0 -.3: out (PSG),a - if MEMOTECH - in a,($03) - endif - -.6: - ld a,(music_mode) - and 1 ; NO DRUMS? - ret z ; Yes, return. - - ld a,(audio_vol4hw) - inc a - jr z,.4 - ld a,(audio_noise) - cp 16 - ld b,$ec - jp c,.5 - ld b,$ed -; ld b,$ee -.5: ld a,(audio_control) - cp b - jr z,.4 - ld a,b - ld (audio_control),a - out (PSG),a - if MEMOTECH - in a,($03) - endif -.4: ld a,(audio_vol4hw) - out (PSG),a - if MEMOTECH - in a,($03) - endif - ret - endif - if MSX+SVI+EINSTEIN+NABU - ld a,(music_mode) - cp 4 ; PLAY SIMPLE? - jr c,.8 ; Yes, jump. - ld hl,audio_freq1 - ld bc,$0b00 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret -.8: - ld hl,audio_freq1 - ld bc,$0400 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - inc hl - inc hl - inc c - inc c - ld a,(music_mode) - and 1 - jr z,.9 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - jr .10 -.9: inc hl - inc c - inc hl - inc c -.10: ld b,$02 - ld a,c - ld e,(hl) - call WRTPSG - inc hl - inc c - djnz $-7 - ret - endif - - ; - ; Enable drum. - ; -enable_drum: - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ld a,$f5 - ld (audio_vol4hw),a - else - ld hl,audio_mix - ld a,(audio_vol2) - or a - jr nz,.1 - ld a,10 - ld (audio_vol2),a - set 1,(hl) -.1: res 4,(hl) - endif - ret - - ; - ; Musical notes table. - ; -music_notes_table: - ; Silence - 0 - dw 0 - if MEMOTECH+EINSTEIN - ; Values for 4.00 mhz. - ; 2nd octave - Index 1 - dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 - ; 3rd octave - Index 13 - dw 956,902,851,804,758,716,676,638,602,568,536,506 - ; 4th octave - Index 25 - dw 478,451,426,402,379,358,338,319,301,284,268,253 - ; 5th octave - Index 37 - dw 239,225,213,201,190,179,169,159,150,142,134,127 - ; 6th octave - Index 49 - dw 119,113,106,100,95,89,84,80,75,71,67,63 - ; 7th octave - Index 61 - dw 60,56,53 - else - ; Values for 3.58 mhz. - ; 2nd octave - Index 1 - dw 1710,1614,1524,1438,1357,1281,1209,1141,1077,1017,960,906 - ; 3rd octave - Index 13 - dw 855,807,762,719,679,641,605,571,539,508,480,453 - ; 4th octave - Index 25 - dw 428,404,381,360,339,320,302,285,269,254,240,226 - ; 5th octave - Index 37 - dw 214,202,190,180,170,160,151,143,135,127,120,113 - ; 6th octave - Index 49 - dw 107,101,95,90,85,80,76,71,67,64,60,57 - ; 7th octave - Index 61 - dw 53,50,48 - endif - - if COLECO+SG1000+SMS+SORD+MEMOTECH+PV2000 - ; - ; Converts AY-3-8910 volume to SN76489 - ; -ay2sn: - db $0f,$0f,$0f,$0e,$0e,$0e,$0d,$0b,$0a,$08,$07,$05,$04,$03,$01,$00 - endif - -music_silence: - db 8 - db 0,0,0,0 - db -2 - endif - - if CVBASIC_COMPRESSION -define_char_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - if SMS - add hl,hl ; x16 - add hl,hl ; x32 - endif - ex de,hl - if SMS - else - ld a,(mode) - and 8 - jp z,unpack3 - endif - jp unpack - - if SMS - else -define_color_unpack: - ex de,hl - pop af - pop hl - push af - add hl,hl ; x2 - add hl,hl ; x4 - add hl,hl ; x8 - ex de,hl - set 5,d -unpack3: - call .1 - call .1 -.1: - push de - push hl - call unpack - pop hl - pop de - ld a,d - add a,8 - ld d,a - ret - endif - - ; - ; Pletter-0.5c decompressor (XL2S Entertainment & Team Bomba) - ; -unpack: -; Initialization - ld a,(hl) - inc hl - exx - ld de,0 - add a,a - inc a - rl e - add a,a - rl e - add a,a - rl e - rl e - ld hl,.modes - add hl,de - ld c,(hl) - inc hl - ld b,(hl) - push bc - pop ix - ld e,1 - exx - ld iy,.loop - -; Main depack loop -.literal: - ex af,af' - call nmi_off - ld a,(hl) - ex de,hl - call WRTVRM - ex de,hl - inc hl - inc de - call nmi_on - ex af,af' -.loop: add a,a - call z,.getbit - jr nc,.literal - -; Compressed data - exx - ld h,d - ld l,e -.getlen: add a,a - call z,.getbitexx - jr nc,.lenok -.lus: add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr nc,.lenok - add a,a - call z,.getbitexx - adc hl,hl - ret c - add a,a - call z,.getbitexx - jr c,.lus -.lenok: inc hl - exx - ld c,(hl) - inc hl - ld b,0 - bit 7,c - jr z,.offsok - jp (ix) - -.mode6: add a,a - call z,.getbit - rl b -.mode5: add a,a - call z,.getbit - rl b -.mode4: add a,a - call z,.getbit - rl b -.mode3: add a,a - call z,.getbit - rl b -.mode2: add a,a - call z,.getbit - rl b - add a,a - call z,.getbit - jr nc,.offsok - or a - inc b - res 7,c -.offsok: inc bc - push hl - exx - push hl - exx - ld l,e - ld h,d - sbc hl,bc - pop bc - ex af,af' -.loop2: - call nmi_off - call RDVRM ; unpack - ex de,hl - call WRTVRM - ex de,hl ; 4 - call nmi_on - inc hl ; 6 - inc de ; 6 - dec bc ; 6 - ld a,b ; 4 - or c ; 4 - jr nz,.loop2 ; 10 - ex af,af' - pop hl - jp (iy) - -.getbit: ld a,(hl) - inc hl - rla - ret - -.getbitexx: - exx - ld a,(hl) - inc hl - exx - rla - ret - -.modes: - dw .offsok - dw .mode2 - dw .mode3 - dw .mode4 - dw .mode5 - dw .mode6 - - endif - -START: - if SVI+SG1000+SMS - im 1 - endif - if MEMOTECH -Z80_CTC: equ $08 - endif - if EINSTEIN -Z80_CTC: equ $28 - endif - - if EINSTEIN+MEMOTECH - di - im 2 - ld a,rom_start>>8 - ld i,a - ld a,$03 ; Reset Z80 CTC - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - out (Z80_CTC+0),a - out (Z80_CTC+1),a - out (Z80_CTC+2),a - out (Z80_CTC+3),a - ld a,$08 ; Interrupt vector offset - out (Z80_CTC+0),a - endif - if MEMOTECH - ld a,$25 ; Disable channel 2 interrupt. - out (Z80_CTC+2),a - ld a,$9c - out (Z80_CTC+2),a - ld a,$25 ; Disable channel 1 interrupt. - out (Z80_CTC+1),a - ld a,$9c - out (Z80_CTC+1),a - ld a,$c5 ; Enable channel 0 interrupt (VDP). - out (Z80_CTC+0),a - ld a,$01 - out (Z80_CTC+0),a - endif - if SORD - ld hl,$186c ; Disable handling of CTC Channel 1 interruption. - ld ($7002),hl - ld hl,$7040 - set 0,(hl) ; Avoid BIOS VDP handling. - endif - if SVI - ld e,$00 - ld a,$08 - call WRTPSG - ld a,$09 - call WRTPSG - ld a,$0A - call WRTPSG - ld a,$07 - ld e,$b8 - call WRTPSG - ld a,$92 ; Setup 8255 for keyboard/joystick reading. - out ($97),a - endif - if SG1000+SMS - ; Contributed by SiRioKD - ld a,$9F ; Turn off PSG - out (PSG),a - ld a,$BF - out (PSG),a - ld a,$DF - out (PSG),a - ld a,$FF - out (PSG),a - ld a,$92 ; Setup 8255 for SC3000. - out ($df),a - endif - if SG1000+SMS+SVI - ; Wait for VDP ready (around 1000 ms) - ld b,11 - ld de,$FFFF -.delay1: - ld hl,$39DE -.delay2: - add hl,de - jr c,.delay2 - djnz .delay1 - else - di - if COLECO_SPINNER - im 1 - endif - ld sp,STACK - endif - if NABU - im 2 - ld a,nabu_int>>8 - ld i,a - ld a,$03 ; Disable ROM - out ($00),a - ld a,$07 - out ($41),a - ld a,$78 ; Setup output ports and mixer. - out ($40),a - ld a,$0e - out ($41),a - ld a,$30 ; Enable video and keyboard. - out ($40),a - endif - if PV2000 - ld hl,nmi_handler - ld ($7499),hl - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - ld a,(VDPR+1) - ld bc,$8201 - call WRTVDP - else - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - in a,(VDPR+1) - ld bc,$8201 - call WRTVDP - endif - if CVBASIC_BANK_SWITCHING - if COLECO - ld a,($ffc0) ; Megacart - endif - if SG1000+SMS - ld a,1 ; Sega mapper - ld ($fffe),a - endif - if MSX - if KONAMI - ld a,1 - ld ($6000),a - inc a - ld ($8000),a - inc a - ld ($a000),a - else - ld a,1 ; ASCII 16K - ld ($7000),a - endif - endif - endif - if MEMOTECH+EINSTEIN+NABU - ld ix,(lfsr) - ld hl,ram_start - ld de,ram_start+1 - ld bc,ram_end-ram_start-1 - ld (hl),0 - ldir - ld (lfsr),ix - endif - if MSX+SVI+SMS - ld ix,(lfsr) - ld hl,BASE_RAM - ld de,BASE_RAM+1 - ld bc,RAM_SIZE-1 - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO+SG1000+SORD+PENCIL+PV2000 - ld hl,(lfsr) ; Save RAM trash for random generator. - ld de,BASE_RAM - xor a - ld (de),a - inc de - if PV2000 - bit 7,d ; 2.5K of RAM - endif - if PENCIL - bit 3,d ; 2K of RAM - endif - if COLECO+SG1000+SORD - bit 2,d ; 1K of RAM - endif - jp z,$-4 - ld (lfsr),hl - endif - - if SGM -WRITE_REGISTER: equ $1fd9 -FILL_VRAM: equ $1f82 -WRITE_VRAM: equ $1fdf - - ld b,$00 ; First step. -.0: ld hl,$2000 ; RAM at $2000. -.1: ld (hl),h ; Try to write a byte. - inc h - jp p,.1 ; Repeat until reaching $8000. - ld h,$20 ; Go back at $2000. -.2: ld a,(hl) ; Read back byte. - cp h ; Is it correct? - jr nz,.3 ; No, jump. - inc h - jp p,.2 ; Repeat until reaching $8000. - jp .4 ; Memory valid! - -.3: ld a,$01 ; Enable SGM - out ($53),a - inc b - bit 1,b ; Already enabled? - jr z,.0 ; No, test RAM again. - - ld bc,$0000 - call WRITE_REGISTER - ld bc,$0180 - call WRITE_REGISTER - ld bc,$0206 - call WRITE_REGISTER - ld bc,$0380 - call WRITE_REGISTER - ld bc,$0400 - call WRITE_REGISTER - ld bc,$0536 - call WRITE_REGISTER - ld bc,$0607 - call WRITE_REGISTER - ld bc,$070D - call WRITE_REGISTER - ld bc,$03F0 - ld de,$00E8 - ld hl,$158B ; Note! direct access to Colecovision ROM - call WRITE_VRAM - ld hl,$2000 - ld de,32 - ld a,$FD - call FILL_VRAM - ld hl,$1B00 - ld de,128 - ld a,$D1 - call FILL_VRAM - ld hl,$1800 - ld de,769 - ld a,$20 - call FILL_VRAM - ld bc,$0020 - ld de,$1980 - ld hl,.5 - call WRITE_VRAM - ld bc,$01C0 - call WRITE_REGISTER - jr $ - -.5: db " SUPER GAME MODULE NOT DETECTED " - -.4: - ld ix,(lfsr) - ld hl,$2000 - ld de,$2001 - ld bc,$5FFF - ld (hl),0 - ldir - ld (lfsr),ix - endif - if COLECO - ld a,($0069) - cp 50 - ld a,1 - jr nz,$+3 - dec a - endif - if SG1000+SMS+SVI+SORD+PV2000+NABU - ld a,1 ; Always NTSC. - endif - if MEMOTECH+EINSTEIN - ld a,0 ; Always PAL. - endif - if MSX - call RSLREG - ld b,1 ; $4000-$7fff - call get_slot_mapping - ld (cartridge_slot),a - ld h,$80 - call ENASLT ; Map into $8000-$BFFF - if FM_SUPPORT - ld a,$ff ; FM hasn't been discovered. - ld (fm_slot),a - ld a,7 - ld ($7000),a - call detect_fm - endif - ld a,($002b) - cpl - rlca - and $01 - endif - ld (ntsc),a - - call music_init - - xor a - ld (mode),a - if SMS - call mode_4 - else - call mode_0 - endif - - xor a - ld (joy1_data),a - ld (joy2_data),a - if NABU - ld (nabu_data0),a - ld (nabu_data1),a - endif - ld a,$0f - ld (key1_data),a - ld (key2_data),a - if NABU - ld (nabu_data2),a - endif - - if MSX - ld hl,nmi_handler - ld ($fd9b),hl - ld a,$c3 - ld ($fd9a),a - endif - if SORD - ld hl,nmi_handler - ld ($7006),hl - endif - if COLECO - if COLECO_SPINNER - ei - endif - endif - - ; CVBasic program start. - ; ' - ; ' Controller test - ; ' - ; ' by Oscar Toledo G. - ; ' https://nanochess.org/ - ; ' - ; ' Creation date: Aug/21/2024. - ; ' Revision date: Oct/15/2024. Solved wrong display for number key in 2nd controller. - ; ' Revision date: Nov/28/2025. Added support for Blue and Purple buttons (Super - ; ' Action Controller) - ; ' - ; - ; CONST left_x = 56 -const_LEFT_X: equ $0038 - ; CONST left_y = 40 -const_LEFT_Y: equ $0028 - ; CONST right_x = 160 -const_RIGHT_X: equ $00a0 - ; CONST right_y = 40 -const_RIGHT_Y: equ $0028 - ; - ; DEF FN CHAR_XY(x, y) = ((y) / 8 * 32 + (x) / 8) - ; - ; MODE 2 ' Color for sets of 8 characters. - CALL mode_2 - ; - ; DEFINE CHAR 27,7,extra_bitmaps - LD HL,27 - PUSH HL - LD A,7 - LD HL,cvb_EXTRA_BITMAPS - CALL define_char - ; - ; VPOKE $2003, $E1 ' Color for characters $18-$1f - LD HL,8195 - LD A,225 - DI - CALL WRTVRM - EI - ; VPOKE $2004, $14 ' $20-$27 - LD HL,8196 - LD A,20 - DI - CALL WRTVRM - EI - ; VPOKE $2005, $1F ' $28-$29 - LD HL,8197 - LD A,31 - DI - CALL WRTVRM - EI - ; VPOKE $2006, $1F ' $30-$37 - LD HL,8198 - LD A,31 - DI - CALL WRTVRM - EI - ; VPOKE $2007, $1F ' $38-$3f - LD HL,8199 - LD A,31 - DI - CALL WRTVRM - EI - ; VPOKE $2008, $F4 ' $40-$47 - LD HL,8200 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $2009, $F4 ' $48-$4f - LD HL,8201 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $200A, $F4 ' $50-$57 - LD HL,8202 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $200B, $F4 ' $58-$5f - LD HL,8203 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $200C, $F4 ' $60-$67 - LD HL,8204 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $200D, $F4 ' $68-$6f - LD HL,8205 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $200E, $F4 ' $70-$77 - LD HL,8206 - LD A,244 - DI - CALL WRTVRM - EI - ; VPOKE $200F, $F4 ' $78-$7f - LD HL,8207 - LD A,244 - DI - CALL WRTVRM - EI - ; - ; ' Center numbers bitmaps - ; FOR #c = $0150 TO $01CF - LD HL,336 - LD (cvb_#C),HL -cv1: - ; d = VPEEK(#c) - LD HL,(cvb_#C) - CALL nmi_off - CALL RDVRM - CALL nmi_on - LD (cvb_D),A - ; VPOKE #c, (d / 2) OR (d / 4) - LD HL,(cvb_D) - LD H,0 - SRL H - RR L - SRL H - RR L - EX DE,HL - LD HL,(cvb_D) - LD H,0 - SRL H - RR L - LD A,L - OR E - LD L,A - LD A,H - OR D - LD H,A - LD A,L - LD HL,(cvb_#C) - DI - CALL WRTVRM - EI - ; NEXT #c - LD HL,(cvb_#C) - INC HL - LD (cvb_#C),HL - LD DE,464 - OR A - SBC HL,DE - JP C,cv1 - ; DEFINE CHAR 42,4,number_bitmap - LD HL,42 - PUSH HL - LD A,4 - LD HL,cvb_NUMBER_BITMAP - CALL define_char - ; - ; VDP(1) = $E0 ' 8x8 sprites - LD A,224 - LD B,A - LD C,1 - DI - CALL WRTVDP - EI - ; VDP(6) = $00 ' Sprites use character bitmaps. - SUB A - LD B,A - LD C,6 - DI - CALL WRTVDP - EI - ; - ; PRINT AT 36,"CVBasic controller test" - LD HL,36 - LD (cursor),HL - LD HL,cv2 - LD A,23 - CALL print_string - JR cv3 -cv2: - DB $43,$56,$42,$61,$73,$69,$63,$20 - DB $63,$6f,$6e,$74,$72,$6f,$6c,$6c - DB $65,$72,$20,$74,$65,$73,$74 -cv3: - ; - ; #c = CHAR_XY(left_x, left_y) - LD HL,167 - LD (cvb_#C),HL - ; GOSUB draw_controller - CALL cvb_DRAW_CONTROLLER - ; #c = CHAR_XY(right_x, right_y) - LD HL,180 - LD (cvb_#C),HL - ; GOSUB draw_controller - CALL cvb_DRAW_CONTROLLER - ; - ; main_loop: -cvb_MAIN_LOOP: - ; WHILE 1 -cv4: - ; IF cont1.up THEN - LD A,(joy1_data) - AND 1 - JP Z,cv6 - ; SPRITE 0, left_y - 1, left_x + 16, 27, 9 - SUB A - PUSH AF - LD A,39 - PUSH AF - LD A,72 - PUSH AF - LD A,27 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv7 -cv6: - ; SPRITE 0, $d1, 0, 0, 0 - SUB A - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv7: - ; IF cont1.left THEN - LD A,(joy1_data) - AND 8 - JP Z,cv8 - ; SPRITE 1, left_y + 15, left_x, 30, 9 - LD A,1 - PUSH AF - LD A,55 - PUSH AF - LD A,56 - PUSH AF - LD A,30 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv9 -cv8: - ; SPRITE 1, $d1, 0, 0, 0 - LD A,1 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv9: - ; IF cont1.right THEN - LD A,(joy1_data) - AND 2 - JP Z,cv10 - ; SPRITE 2, left_y + 15, left_x + 32, 28, 9 - LD A,2 - PUSH AF - LD A,55 - PUSH AF - LD A,88 - PUSH AF - LD A,28 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv11 -cv10: - ; SPRITE 2, $d1, 0, 0, 0 - LD A,2 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv11: - ; IF cont1.down THEN - LD A,(joy1_data) - AND 4 - JP Z,cv12 - ; SPRITE 3, left_y + 31, left_x + 16, 29, 9 - LD A,3 - PUSH AF - LD A,71 - PUSH AF - LD A,72 - PUSH AF - LD A,29 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv13 -cv12: - ; SPRITE 3, $d1, 0, 0, 0 - LD A,3 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv13: - ; IF cont1.button THEN - LD A,(joy1_data) - AND 64 - JP Z,cv14 - ; SPRITE 4, left_y + 47, left_x - 8, 31, 9 - LD A,4 - PUSH AF - LD A,87 - PUSH AF - LD A,48 - PUSH AF - LD A,31 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv15 -cv14: - ; SPRITE 4, $d1, 0, 0, 0 - LD A,4 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv15: - ; IF cont1.button2 THEN - LD A,(joy1_data) - AND 128 - JP Z,cv16 - ; SPRITE 5, left_y + 47, left_x + 40, 31, 9 - LD A,5 - PUSH AF - LD A,87 - PUSH AF - LD A,96 - PUSH AF - LD A,31 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv17 -cv16: - ; SPRITE 5, $d1, 0, 0, 0 - LD A,5 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv17: - ; c = cont1.key - LD A,(key1_data) - LD (cvb_C),A - ; IF c = 15 THEN - CP 15 - JP NZ,cv18 - ; SPRITE 6, $d1, 0, 0, 0 - LD A,6 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; ELSE - JP cv19 -cv18: - ; GOSUB prepare_key - CALL cvb_PREPARE_KEY - ; SPRITE 6, left_y + y, left_x + x, c, 9 - LD A,6 - PUSH AF - LD A,(cvb_Y) - ADD A,40 - PUSH AF - LD A,(cvb_X) - ADD A,56 - PUSH AF - LD A,(cvb_C) - PUSH AF - LD A,9 - CALL update_sprite - ; END IF -cv19: - ; IF cont2.up THEN - LD A,(joy2_data) - AND 1 - JP Z,cv20 - ; SPRITE 7, right_y - 1, right_x + 16, 27, 9 - LD A,7 - PUSH AF - LD A,39 - PUSH AF - LD A,176 - PUSH AF - LD A,27 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv21 -cv20: - ; SPRITE 7, $d1, 0, 0, 0 - LD A,7 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv21: - ; IF cont2.left THEN - LD A,(joy2_data) - AND 8 - JP Z,cv22 - ; SPRITE 8, right_y + 15, right_x, 30, 9 - LD A,8 - PUSH AF - LD A,55 - PUSH AF - LD A,160 - PUSH AF - LD A,30 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv23 -cv22: - ; SPRITE 8, $d1, 0, 0, 0 - LD A,8 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv23: - ; IF cont2.right THEN - LD A,(joy2_data) - AND 2 - JP Z,cv24 - ; SPRITE 9, right_y + 15, right_x + 32, 28, 9 - LD A,9 - PUSH AF - LD A,55 - PUSH AF - LD A,192 - PUSH AF - LD A,28 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv25 -cv24: - ; SPRITE 9, $d1, 0, 0, 0 - LD A,9 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv25: - ; IF cont2.down THEN - LD A,(joy2_data) - AND 4 - JP Z,cv26 - ; SPRITE 10, right_y + 31, right_x + 16, 29, 9 - LD A,10 - PUSH AF - LD A,71 - PUSH AF - LD A,176 - PUSH AF - LD A,29 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv27 -cv26: - ; SPRITE 10, $d1, 0, 0, 0 - LD A,10 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv27: - ; IF cont2.button THEN - LD A,(joy2_data) - AND 64 - JP Z,cv28 - ; SPRITE 11, right_y + 47, right_x - 8, 31, 9 - LD A,11 - PUSH AF - LD A,87 - PUSH AF - LD A,152 - PUSH AF - LD A,31 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv29 -cv28: - ; SPRITE 11, $d1, 0, 0, 0 - LD A,11 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv29: - ; IF cont2.button2 THEN - LD A,(joy2_data) - AND 128 - JP Z,cv30 - ; SPRITE 12, right_y + 47, right_x + 40, 31, 9 - LD A,12 - PUSH AF - LD A,87 - PUSH AF - LD A,200 - PUSH AF - LD A,31 - PUSH AF - LD A,9 - CALL update_sprite - ; ELSE - JP cv31 -cv30: - ; SPRITE 12, $d1, 0, 0, 0 - LD A,12 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; END IF -cv31: - ; c = cont2.key - LD A,(key2_data) - LD (cvb_C),A - ; IF c = 15 THEN - CP 15 - JP NZ,cv32 - ; SPRITE 14, $d1, 0, 0, 0 - LD A,14 - PUSH AF - LD A,209 - PUSH AF - SUB A - PUSH AF - PUSH AF - CALL update_sprite - ; ELSE - JP cv33 -cv32: - ; GOSUB prepare_key - CALL cvb_PREPARE_KEY - ; SPRITE 14, right_y + y, right_x + x, c, 9 - LD A,14 - PUSH AF - LD A,(cvb_Y) - ADD A,40 - PUSH AF - LD A,(cvb_X) - ADD A,160 - PUSH AF - LD A,(cvb_C) - PUSH AF - LD A,9 - CALL update_sprite - ; END IF -cv33: - ; - ; WAIT - HALT - ; - ; WEND - JP cv4 -cv5: - ; - ; draw_controller: PROCEDURE -cvb_DRAW_CONTROLLER: - ; FOR #d = #c - $0021 TO #c + $01DF STEP $20 - LD HL,(cvb_#C) - LD DE,65503 - ADD HL,DE - LD (cvb_#D),HL -cv34: - ; PRINT AT #d, "!!!!!!!" - LD HL,(cvb_#D) - LD (cursor),HL - LD HL,cv35 - LD A,7 - CALL print_string - JR cv36 -cv35: - DB $21,$21,$21,$21,$21,$21,$21 -cv36: - ; NEXT #d - LD HL,(cvb_#D) - LD DE,32 - ADD HL,DE - LD (cvb_#D),HL - LD HL,(cvb_#C) - LD DE,479 - ADD HL,DE - LD DE,(cvb_#D) - OR A - SBC HL,DE - JP NC,cv34 - ; - ; PRINT AT #c + $0000, "!!\27!!" - LD HL,(cvb_#C) - LD (cursor),HL - LD HL,cv37 - LD A,5 - CALL print_string - JR cv38 -cv37: - DB $21,$21,$1b,$21,$21 -cv38: - ; PRINT AT #c + $0040, "\30!\31!\28" - LD HL,(cvb_#C) - LD DE,64 - ADD HL,DE - LD (cursor),HL - LD HL,cv39 - LD A,5 - CALL print_string - JR cv40 -cv39: - DB $1e,$21,$1f,$21,$1c -cv40: - ; PRINT AT #c + $0080, "!!\29!!" - LD HL,(cvb_#C) - LD DE,128 - ADD HL,DE - LD (cursor),HL - LD HL,cv41 - LD A,5 - CALL print_string - JR cv42 -cv41: - DB $21,$21,$1d,$21,$21 -cv42: - ; PRINT AT #c + $00bf, "\31!!!!!\31" - LD HL,(cvb_#C) - LD DE,191 - ADD HL,DE - LD (cursor),HL - LD HL,cv43 - LD A,7 - CALL print_string - JR cv44 -cv43: - DB $1f,$21,$21,$21,$21,$21,$1f -cv44: - ; PRINT AT #c + $0100, "1!2!3" - LD HL,(cvb_#C) - INC H - LD (cursor),HL - LD HL,cv45 - LD A,5 - CALL print_string - JR cv46 -cv45: - DB $31,$21,$32,$21,$33 -cv46: - ; PRINT AT #c + $0140, "4!5!6" - LD HL,(cvb_#C) - LD DE,320 - ADD HL,DE - LD (cursor),HL - LD HL,cv47 - LD A,5 - CALL print_string - JR cv48 -cv47: - DB $34,$21,$35,$21,$36 -cv48: - ; PRINT AT #c + $0180, "7!8!9" - LD HL,(cvb_#C) - LD DE,384 - ADD HL,DE - LD (cursor),HL - LD HL,cv49 - LD A,5 - CALL print_string - JR cv50 -cv49: - DB $37,$21,$38,$21,$39 -cv50: - ; PRINT AT #c + $01C0, "*!0!+" - LD HL,(cvb_#C) - LD DE,448 - ADD HL,DE - LD (cursor),HL - LD HL,cv51 - LD A,5 - CALL print_string - JR cv52 -cv51: - DB $2a,$21,$30,$21,$2b -cv52: - ; END - RET - ; - ; prepare_key: PROCEDURE -cvb_PREPARE_KEY: - ; IF c = 0 THEN - LD A,(cvb_C) - AND A - JP NZ,cv53 - ; x = 16 - LD A,16 - LD (cvb_X),A - ; y = 111 - LD A,111 - LD (cvb_Y),A - ; c = 48 - LD A,48 - LD (cvb_C),A - ; ELSEIF c = 10 THEN - JP cv54 -cv53: - LD A,(cvb_C) - CP 10 - JP NZ,cv55 - ; x = 0 - SUB A - LD (cvb_X),A - ; y = 111 - LD A,111 - LD (cvb_Y),A - ; c = 42 - LD A,42 - LD (cvb_C),A - ; ELSEIF c = 11 THEN - JP cv54 -cv55: - LD A,(cvb_C) - CP 11 - JP NZ,cv56 - ; x = 32 - LD A,32 - LD (cvb_X),A - ; y = 111 - LD A,111 - LD (cvb_Y),A - ; c = 43 - LD A,43 - LD (cvb_C),A - ; ELSEIF c > 0 AND c < 10 THEN - JP cv54 -cv56: - LD A,(cvb_C) - CP 10 - LD A,0 - SBC A,A - LD B,A - LD A,(cvb_C) - CP 1 - LD A,255 - ADC A,0 - AND B - JP Z,cv57 - ; x = ((c - 1) % 3) * 16 - LD HL,(cvb_C) - LD H,0 - DEC HL - LD DE,3 - CALL _mod16 - LD A,L - ADD A,A - ADD A,A - ADD A,A - ADD A,A - LD (cvb_X),A - ; y = 63 + ((c - 1) / 3) * 16 - LD HL,(cvb_C) - LD H,0 - DEC HL - LD DE,3 - CALL _div16 - LD A,L - ADD A,A - ADD A,A - ADD A,A - ADD A,A - ADD A,63 - LD (cvb_Y),A - ; c = c + 48 - LD HL,cvb_C - LD A,48 - ADD A,(HL) - LD (HL),A - ; ELSEIF c = 12 THEN - JP cv54 -cv57: - LD A,(cvb_C) - CP 12 - JP NZ,cv58 - ; x = 8 - LD A,8 - LD (cvb_X),A - ; y = 0 - SUB A - LD (cvb_Y),A - ; c = 44 - LD A,44 - LD (cvb_C),A - ; ELSEIF c = 13 THEN - JP cv54 -cv58: - LD A,(cvb_C) - CP 13 - JP NZ,cv59 - ; x = 8 - LD A,8 - LD (cvb_X),A - ; y = 8 - LD (cvb_Y),A - ; c = 45 - LD A,45 - LD (cvb_C),A - ; ELSE - JP cv54 -cv59: - ; ' Some systems have extra characters - ; x = 16 - LD A,16 - LD (cvb_X),A - ; y = 127 - LD A,127 - LD (cvb_Y),A - ; END IF -cv54: - ; END - RET - ; - ; extra_bitmaps: -cvb_EXTRA_BITMAPS: - ; BITMAP "...XX..." - ; BITMAP "..XXXX.." - ; BITMAP ".XXXXXX." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - DB $18,$3c,$7e,$18,$18,$18,$18,$18 - ; - ; BITMAP "........" - ; BITMAP ".....X.." - ; BITMAP ".....XX." - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP ".....XX." - ; BITMAP ".....X.." - ; BITMAP "........" - DB $00,$04,$06,$ff,$ff,$06,$04,$00 - ; - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP "...XX..." - ; BITMAP ".XXXXXX." - ; BITMAP "..XXXX.." - ; BITMAP "...XX..." - DB $18,$18,$18,$18,$18,$7e,$3c,$18 - ; - ; BITMAP "........" - ; BITMAP "..X....." - ; BITMAP ".XX....." - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP ".XX....." - ; BITMAP "..X....." - ; BITMAP "........" - DB $00,$20,$60,$ff,$ff,$60,$20,$00 - ; - ; BITMAP "..XXXX.." - ; BITMAP ".XXXXXX." - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP ".XXXXXX." - ; BITMAP "..XXXX.." - DB $3c,$7e,$ff,$ff,$ff,$ff,$7e,$3c - ; - ; BITMAP "........" - ; BITMAP "........" - ; BITMAP "........" - ; BITMAP "........" - ; BITMAP "........" - ; BITMAP "........" - ; BITMAP "........" - ; BITMAP "........" - DB $00,$00,$00,$00,$00,$00,$00,$00 - ; - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - ; BITMAP "XXXXXXXX" - DB $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff - ; - ; number_bitmap: -cvb_NUMBER_BITMAP: - ; BITMAP "........" - ; BITMAP ".XX..XX." - ; BITMAP "..XXXX.." - ; BITMAP ".XXXXXX." - ; BITMAP "..XXXX.." - ; BITMAP ".XX..XX." - ; BITMAP "........" - ; BITMAP "........" - DB $00,$66,$3c,$7e,$3c,$66,$00,$00 - ; - ; BITMAP "..XX.XX." - ; BITMAP "..XX.XX." - ; BITMAP ".XXXXXXX" - ; BITMAP "..XX.XX." - ; BITMAP ".XXXXXXX" - ; BITMAP "..XX.XX." - ; BITMAP "..XX.XX." - ; BITMAP "........" - DB $36,$36,$7f,$36,$7f,$36,$36,$00 - ; - ; BITMAP "XXXXXXX." - ; BITMAP "XX....XX" - ; BITMAP "XX....XX" - ; BITMAP "XXXXXXX." - ; BITMAP "XX....XX" - ; BITMAP "XX....XX" - ; BITMAP "XXXXXXX." - ; BITMAP "........" - DB $fe,$c3,$c3,$fe,$c3,$c3,$fe,$00 - ; - ; BITMAP "XXXXXXX." - ; BITMAP "XX....XX" - ; BITMAP "XX....XX" - ; BITMAP "XXXXXXX." - ; BITMAP "XX......" - ; BITMAP "XX......" - ; BITMAP "XX......" - ; BITMAP "........" - DB $fe,$c3,$c3,$fe,$c0,$c0,$c0,$00 - ; - ; - ; CVBasic epilogue (BASIC compiler for Colecovision) - ; - ; by Oscar Toledo G. - ; https://nanochess.org/ - ; - ; Creation date: Feb/27/2024. - ; Revision date: Feb/29/2024. Added joystick, keypad, frame, random, and - ; read_pointer variables. - ; Revision date: Mar/04/2024. Added music player. - ; Revision date: Mar/05/2024. Added support for Sega SG1000. - ; Revision date: Mar/12/2024. Added support for MSX. - ; Revision date: Mar/13/2024. Added Pletter decompressor. - ; Revision date: Mar/19/2024. Added support for sprite flicker. - ; Revision date: Apr/11/2024. Added support for Super Game Module. - ; Revision date: Apr/13/2024. Updates LFSR in interruption handler. - ; Revision date: Apr/26/2024. All code moved to cvbasic_prologue.asm so it - ; can remain accessible in bank 0 (bank switching). - ; Revision date: Aug/02/2024. Added rom_end label for Memotech. - ; Revision date: Aug/15/2024. Added support for Tatung Einstein. - ; Revision date: Nov/12/2024. Added vdp_status. - ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. - ; Revision date: Feb/05/2026. Added support for spinners and roller controller - ; (Colecovision). - ; - -rom_end: - - ; ROM final size rounding - if MSX+COLECO+SG1000+SMS+SVI+SORD - TIMES (($+$1FFF)&$1e000)-$ DB $ff - endif - if MEMOTECH+EINSTEIN+NABU - ; Align following data to a 256-byte page. - TIMES $100-($&$ff) DB $4f - endif - if PV2000 - TIMES $10000-$ DB $ff - endif - if SG1000+SMS - if CVBASIC_BANK_SWITCHING - forg CVBASIC_BANK_ROM_SIZE*1024-1 ; Force final ROM size - db $ff - endif - forg $7FF0 - org $7FF0 - db "TMR SEGA" - db 0,0 - db 0,0 ; Checksum - db $11,$78 ; Product code - db $00 ; Version - db $4c ; SMS Export + 32KB for checksum - endif - if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 - org BASE_RAM - endif -ram_start: - -sprites: - if SMS - rb 256 - else - rb 128 - endif -sprite_data: - rb 4 -frame: - rb 2 -read_pointer: - rb 2 -cursor: - rb 2 -lfsr: - rb 2 - if MSX -cartridge_slot: - rb 1 -fm_slot: - rb 1 -fm_enabled: - rb 1 -fm_inst: - rb 4 - endif -mode: - rb 1 ; bit 0: NMI disabled. - ; bit 1: NMI received. - ; bit 2: No sprite flicker. - ; bit 3: Single charset mode. - ; bit 4: MSX2 sprites. -flicker: - rb 1 -joy1_data: - rb 1 -joy2_data: - rb 1 -key1_data: - rb 1 -key2_data: - rb 1 -ntsc: - rb 1 -vdp_status: - rb 1 - if COLECO - if COLECO_SPINNER -spinner_data: - rb 3 - endif - endif - if NABU -nabu_data0: rb 1 -nabu_data1: rb 1 -nabu_data2: rb 1 - endif - - if CVBASIC_MUSIC_PLAYER -music_tick: rb 1 -music_mode: rb 1 - - if CVBASIC_BANK_SWITCHING -music_bank: rb 1 - endif -music_start: rb 2 -music_pointer: rb 2 -music_playing: rb 1 -music_timing: rb 1 -music_note_counter: rb 1 -music_instrument_1: rb 1 -music_counter_1: rb 1 -music_note_1: rb 1 -music_instrument_2: rb 1 -music_counter_2: rb 1 -music_note_2: rb 1 -music_instrument_3: rb 1 -music_counter_3: rb 1 -music_note_3: rb 1 -music_counter_4: rb 1 -music_drum: rb 1 - -audio_freq1: rb 2 -audio_freq2: rb 2 -audio_freq3: rb 2 -audio_noise: rb 1 -audio_mix: rb 1 -audio_vol1: rb 1 -audio_vol2: rb 1 -audio_vol3: rb 1 - -audio_control: rb 1 -audio_vol4hw: rb 1 - endif - - if SGM - org $2000 ; Start for variables. - endif -cvb_C: rb 1 -cvb_D: rb 1 -cvb_X: rb 1 -cvb_Y: rb 1 -cvb_#C: rb 2 -cvb_#D: rb 2 -ram_end: diff --git a/controller.rom b/controller.rom deleted file mode 100644 index 55148e0150e2b71842b8a199a8c9d6aaf6f577ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8192 zcmeHJZA@F&89o z47Rdf5n~-rTcE&1Z-i|ieSTl*mD%TA|9}na%54QBPu&<5kcCLV)$V19fRgGTqt7I58=k`-E-<`b)?)JfN*Qn! zNH-_DUAwfJcK6>c%>EQHTh6V3I$!}=NaK}2>cJ0id(~!>R55hr+J3L)q(>x8R$Z-|anPbUSao23 z%o}9Dz_G7{f55|`pb~lKni|2G%v^oF;yX3kC=0qk&6vf19W zsoT{Zb*HHUen1wZJpfbDRI3@>eA)@ozcCd4acJWkbf z>gxh3aa%IlOwcEyoo*yRbAZ6`{X;&CBmsHIEoc-5yvH#3mefIvs>uzn*bpRCh$0AM zMBM@vM$w7XEKuXW`AT}w26A1>ruuSjXiUg$m4;b^xc&nvBAeB*fsVM?!Or5JWnR%&S^h&_ zyZZi0I(1O}^}>hCQ~sB!Fd0=J@@`d+!d1N`4MBK9;g0Zdik+Tjj!K^a*7g!z6#Xwz zw+C6H;RdR{n|dw2w-d}hW?Go}Zf8~Oo1Mg|okhv(8{azu-Z&x-SXwh`NGegI>JhMG zY9H7a)x%&X)j_bcY8dR*p+^5%x_mKtYXdD^Tz+daq-E3Muu0$Gh>am? z*ir6vsH2VwuifGFh_#iicTV~zs5Qemc7p?{qv|NwG4%x47kSA^exO;-6FH9^=c;k| znGH+P;s3{@pP|0zX?@-E6rZNe&CNIFSJDcx*C3`rnK6|clda||fXe#5==$=MAUp@1 znwvj?=OWi)ceS9@>?iODXsv=(&@OfOU!V<9Z6|8mgBoo~!9PW{-h-F?<5asIyyQPa zK|SJx>-#4u{!2&Q^yeh*fBAE5r~_A{Rbs=qSG&I*TO_iw4&8SfixT;|;gw3H*6^%( z&zAS>68V=AEz5i5d9NbxRpz}ddC!seoO$m7q3%5Oou|;yS|fYl{I5{oE3^Tr0d)ua ztmRk3e+)_@hr9$8R7=s`Yi_x3f;$8JZLl zHK7Te?9xe>PO5cMrv1J>zMDZe^a)*u6=T^G2SY^A$vrx0)k#g3_I-{O^GXsw3y~7e z`=L&@XL%<%R?HI0JcVP$yl7%IL`pet zpukIWEYE|MnWmf0SVb4H7Ood>=+gRn0BJi%7rlDht8}qdZ=0q@t+umFqF@)XagAmR z8r{#ad~)E~6OVThJHPx)L8PZSR?I6&{I-jfao$`(q;niA=81_vb&+x|64cF!w8*hy zo}Bo!i&XH-PZlo!PmUGyqKWcuQptJO3cRfx%kw6)A~kgrN0CUq-Ap7$kw`NIk)DoQ zLeR7Bzh$cGE>PbE%G&W*H?gsHga?ujfZY<}1V$CAQvDYw^!Eo3cf($`W4fD^vK^%u zS7Xc)%D{)f+qpmuuEpC~AZi4(Tma)8#*RN5fn=_DEw5b*dv>x+o4F19upfV$mk@Y~ zZ9UoA&GYSPyaeU!^4MKSxOubX#2N zg}`Qc?Ae})e85)-RK%uxh?I})DMZQ%Iv-+t1(JCm%_LTPeADpTvBzye@E2zI6b#r_ zz_5WW9)Qw#8mj;5M7DTkY_o^hfjq%ZwYN}WOKfW|4>0^&25y{x6cEJ|81b-yL~ABv z6%k*I1UyI@$Ycg26d1|C7zyP5M6(qe=xAUha1^1ImQi@Mpv`!kz4<&hH-`+CX-x%8 r1xy7@1xy7@1xy7@1xy7@1xy7@1xy7@1xy7@1xy7@1xyA0ZwmYukfonQ diff --git a/cpuz80.c b/cpuz80.c index f5d75ec..63ff143 100644 --- a/cpuz80.c +++ b/cpuz80.c @@ -1009,7 +1009,14 @@ void cpuz80_node_generate(struct node *node, int decision) cpuz80_2op("LD", "HL", "(frame)"); break; case N_MUSIC: /* Read music playing status */ - cpuz80_2op("LD", "A", "(music_playing)"); + if (node->value == 0) { + cpuz80_2op("LD", "A", "(music_playing)"); + } else if (node->value == 1) { + cpuz80_2op("LD", "A", "(fm_slot)"); + cpuz80_1op("INC", "A"); + } else if (node->value == 2) { + cpuz80_2op("LD", "A", "(fm_enabled)"); + } break; case N_NTSC: /* Read NTSC flag */ cpuz80_2op("LD", "A", "(ntsc)"); diff --git a/cvbasic.c b/cvbasic.c index bcae085..a809973 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -33,7 +33,7 @@ #define DEFAULT_ASM_LIBRARY_PATH "" #endif -#define VERSION "v0.9.2 Mar/06/2026" +#define VERSION "v0.9.2 Mar/12/2026" #define TEMPORARY_ASSEMBLER "cvbasic_temporary.asm" @@ -445,6 +445,9 @@ void bank_finish(void) if (bank_current == 0) { fprintf(output, "BANK_0_FREE:\tEQU $7fff-$\n"); fprintf(output, "\tTIMES $7fff-$ DB $ff\n"); + } else if (bank_current == 7 && option_fm != 0) { + fprintf(output, "BANK_%d_FREE:\tEQU $bd00-$\n", bank_current); + fprintf(output, "\tTIMES $bfff-$ DB $ff\n"); } else { fprintf(output, "BANK_%d_FREE:\tEQU $bfff-$\n", bank_current); fprintf(output, "\tTIMES $bfff-$ DB $ff\n"); @@ -1643,18 +1646,31 @@ struct node *evaluate_level_7(int *type) return tree; } if (strcmp(name, "MUSIC") == 0) { + int c; + get_lex(); if (lex != C_PERIOD) { emit_error("missing period in MUSIC"); } else { get_lex(); } - if (lex != C_NAME || strcmp(name, "PLAYING") != 0) { - emit_error("only allowed MUSIC.PLAYING"); + if (lex != C_NAME) { + emit_error("syntax error in MUSIC"); + c = 0; + } else if (strcmp(name, "PLAYING") == 0) { + get_lex(); + c = 0; + } else if (strcmp(name, "FM_AVAILABLE") == 0 && (machine == MSX || machine == MSX2)) { + get_lex(); + c = 1; + } else if (strcmp(name, "FM_ENABLED") == 0 && (machine == MSX || machine == MSX2)) { + get_lex(); + c = 2; } else { + emit_error("unhandled variable in MUSIC"); get_lex(); } - tree = node_create(N_MUSIC, 0, NULL, NULL); + tree = node_create(N_MUSIC, c, NULL, NULL); *type = TYPE_8; return tree; } @@ -5546,6 +5562,22 @@ void compile_statement(int check_for_else) cpuz80_2op("LD", "A", temp); cpuz80_2op("LD", "(music_mode)", "A"); } + } else if (strcmp(name, "FM") == 0) { + get_lex(); + if (machine != MSX && machine != MSX2) + emit_warning("PLAY FM only allowed for MSX and MSX2"); + if (lex == C_NAME && strcmp(name, "ON") == 0) { + get_lex(); + cpuz80_2op("LD", "A", "1"); + cpuz80_2op("LD", "(fm_enabled)", "A"); + } else if (lex == C_NAME && strcmp(name, "OFF") == 0) { + get_lex(); + cpuz80_1op("CALL", "turn_off_fm"); + cpuz80_1op("XOR", "A"); + cpuz80_2op("LD", "(fm_enabled)", "A"); + } else { + emit_error("syntax error in PLAY FM"); + } } else if (strcmp(name, "INSTRUMENT") == 0) { get_lex(); if (machine != MSX && machine != MSX2) diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 82ca1e5..85bcaea 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -51,6 +51,424 @@ rom_end: db $00 ; Version db $4c ; SMS Export + 32KB for checksum endif + + if MSX + if FM_SUPPORT + ; + ; FM driver + ; + ; by Oscar Toledo G. + ; + ; Creation date: Sep/28/2012. For Mecha-9. + ; Revision date: Mar/07/2026. Adapted for Metro Wars (CVBasic) + ; Revision date: Mar/12/2026. Adapted for release in CVBasic. + ; + + FORG $01FD00 + ORG $BD00 + + ; + ; This code cannot be in the area $4000-$7fff + ; + + ; Subroutines from BIOS MSX +CALSLT: equ $001c ; Inter-slot call (disables interruptions) +;ENASLT: equ $0024 ; Enable slot (H=High-byte address, C=Slot) + + ; Subroutines from OPLL ROM +WRTOPL: equ $4110 +INIOPL: equ $4113 + + ; + ; Play music for FM + ; +music_generate_fm: + ; Fragments of code in caller. + +.0: ld a,(music_timing) + and $3f ; Restarts note time. + ld (music_note_counter),a + push hl + push bc + push de + call fm_rom_switch + pop de + pop bc + ld a,b + cp $3f ; Sustain? + jr z,.1 + ld a,$10 + call play_fm +.1: ld a,c ; Read second voice. + cp $3f ; Sustain? + jr z,.2 + ld b,a + ld a,$11 + call play_fm +.2: ld a,d ; Read third voice. + cp $3f ; Sustain? + jr z,.3 + ld b,a + ld a,$12 + call play_fm +.3: push de + call cartridge_rom_switch + pop de + pop hl + ld a,e ; Read effect. + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + ; + ; Build extras + ; +.6: ld a,(music_drum) ; Read effect. + or a ; Effect happening? + jr z,.7 ; No, jump. + call fm_rom_switch + ld a,(music_drum) ; Read effect. + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + or a + ld de,$0e28 + jr z,.9 + cp 3 + ld de,$0e20 + jr z,.9 + jr .4 + +.5: dec a ; 2 - Short drum. + jr nz,.11 + ld a,(music_counter_4) + or a + ld e,$21 + jr z,.9 + cp 3 + ld e,$20 + jr nz,.4 +.9: ld a,$0e + call write_fm + jr .4 + +.12: cp 2 + jr nz,.9 + ld e,$20 + ld a,$0e + call write_fm + ld e,$28 + jr .9 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + ld e,$28 + or a + jr z,.9 + cp b + jr z,.12 + ld e,$20 + cp 2 + jr z,.9 + dec a + dec a + cp b + jr z,.9 +.4: call cartridge_rom_switch +.7: + ; Increment time for drum. + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + + ; + ; Play note in FM + ; A = Voice ($10 - $11 - $12) + ; B = Instrument + Note. + ; +play_fm: + push bc + push de + ld c,a ; Saves base register. + add a,$10 + ld e,$00 ; Turn off voice if it was turned on. + push bc + call write_fm + pop bc + ld a,b ; Read instrument (bits 7-6) + and $c0 + rlca + rlca + ld hl,fm_inst + add a,l + ld l,a + adc a,h + sub l + ld h,a + ld e,(hl) ; Select instrument. + + ld a,c + add a,$20 + push bc + call write_fm + pop bc + ld a,b ; Read note. + and $3f + ld hl,fm_notes + add a,a ; Index into note table. + add a,l + ld l,a + adc a,h + sub l + ld h,a + ld a,c + ld e,(hl) ; Get low byte. + push bc + push hl + call write_fm + pop hl + pop bc + inc hl + ld e,(hl) ; Get high byte (octave). + ld a,b + cpl + and $c0 ; Is it bass? + jr nz,.1 ; No, jump. + ld a,e + sub 2 ; Lower octave. + ld e,a +.1: ld a,b + and $c0 + cp $40 ; Is it clarinet? + jr nz,$+4 ; No, jump. + inc e ; Higher octave. + inc e + ld a,c + add a,$10 + call write_fm + pop de + pop bc + ret + + ; + ; Detects FM (OPLL) + ; Carry = Set = FM detected. + ; Clear = No FM detected. + ; +detect_fm: + ld bc,$0000 +.1: push bc + ld hl,$fcc1 ; EXPTBL + ld a,l + add a,c + ld l,a + ld a,(hl) + and $80 + or c + call find_fm ; Search in subslots. + pop bc + ret nc ; Jump if something has been found. + inc c + bit 2,c ; Four slots analyzed? + jr z,.1 ; No, jump. + ret + +fm_signature_1: db "APRLOPLL" ; Internal MSX-Music. +fm_signature_2: db "PAC2OPLL" ; FM-Pac cartridge. + +find_fm: + bit 7,a ; Expanded slot? + ld b,1 ; No subslots. + jr z,.1 ; No, jump. + and $f3 + ld b,4 ; Ok, four subslots. +.1: ld c,a +.2: push bc + ld h,$40 + ld a,c + call ENASLT + ld hl,$4018 + push hl + ld de,fm_signature_1 + ld b,8 +.4: ld a,(de) + cp (hl) + jr nz,.5 + inc de + inc hl + djnz .4 +.5: pop hl + jr z,.8 ; Detected? Jump to take note. + ld de,fm_signature_2 + ld b,8 +.6: ld a,(de) + cp (hl) + jr nz,.7 + inc de + inc hl + djnz .6 +.7: jr nz,.3 ; Not detected? Jump to next subslot. +.8: pop bc + ld a,c ; Take note of slot. + ld (fm_slot),a + push bc + ld a,1 ; Enable FM. + ld (fm_enabled),a +.3: + ; Important! The H register should be $40 here. + ld a,(cartridge_slot) + call ENASLT + pop bc + ld a,(fm_enabled) + or a + ret nz + ld a,c + add a,4 + ld c,a + djnz .2 + scf + ret + + ; + ; Init FM + ; +init_fm: + push ix + push iy + call fm_rom_switch + ld hl,$ef00 + call INIOPL + ld hl,.0 + ld b,24 +.1: ld e,(hl) + inc hl + ld a,(hl) + inc hl + call write_fm + djnz .1 + call cartridge_rom_switch + ld a,$30 ; Piano + ld (fm_inst),a + ld a,$50 ; Clarinet + ld (fm_inst+1),a + ld a,$40 ; Flute + ld (fm_inst+2),a + ld a,$e0 ; Acoustic bass + ld (fm_inst+3),a + pop iy + pop ix + ret + +.0: dw $0011 ; Unique programmable instrument (not used) + dw $0111 + dw $0220 + dw $0320 + dw $04ff + dw $05b2 + dw $06f4 + dw $07f4 + dw $0e20 ; Enables percussion mode. + dw $2000 ; Turn off main voices. + dw $2100 + dw $2200 + dw $2300 + dw $2400 + dw $2500 + dw $1620 ; Set up percussion. + dw $1750 + dw $18c0 + dw $2605 + dw $2705 + dw $2801 + dw $3600 ; / Bass Drum (volume for percussion) + dw $3720 ; Hihat / Snare Drum + dw $3800 ; Tom / Top Cymbal + + ; + ; Turn off FM + ; +turn_off_fm: + ld a,(fm_slot) + inc a + ret z + ld a,(fm_enabled) + or a + ret z + call fm_rom_switch + LD A,$10+$10 + LD E,$00 + CALL write_fm + LD A,$11+$10 + LD E,$00 + CALL write_fm + LD A,$12+$10 + LD E,$00 + CALL write_fm + CALL cartridge_rom_switch + RET + + ; Write a FM register + ; A = register + ; E = data +write_fm: + jp WRTOPL + + ; + ; Map FM BIOS 16K in $4000-$7FFF + ; +fm_rom_switch: + di + ld a,(fm_slot) + ld h,$40 + jp ENASLT + + ; + ; Map cartridge in $4000-$7FFF + ; +cartridge_rom_switch: + ld a,(cartridge_slot) + ld h,$40 + call ENASLT + ei + ret + +fm_notes: + ; Silence - 0 + dw 0 + ; Octave 2 - 1 + dw $14ad,$14b7,$14c2,$14cd,$14d9,$14e6 + dw $14f4,$1503,$1512,$1522,$1534,$1546 + ; Octave 3 - 13 + dw $16ad,$16b7,$16c2,$16cd,$16d9,$16e6 + dw $16f4,$1703,$1712,$1722,$1734,$1746 + ; Octave 4 - 25 + dw $18ad,$18b7,$18c2,$18cd,$18d9,$18e6 + dw $18f4,$1903,$1912,$1922,$1934,$1946 + ; Octave 5 - 37 + dw $1aad,$1ab7,$1ac2,$1acd,$1ad9,$1ae6 + dw $1af4,$1b03,$1b12,$1b22,$1b34,$1b46 + ; Octave 6 - 49 + dw $1cad,$1cb7,$1cc2,$1ccd,$1cd9,$1ce6 + dw $1cf4,$1d03,$1d12,$1d22,$1d34,$1d46 + ; Octave 7 - 61 + ; Space for two notes more. + endif + endif + if COLECO+SG1000+SMS+MSX+SVI+SORD+PV2000 org BASE_RAM endif diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 1bda1a5..dc3b403 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -3077,8 +3077,15 @@ MIX_BASE: equ $78 ld e,MIX_BASE call WRTPSG if FM_SUPPORT + if KONAMI + ld a,14 + ld ($8000),a + inc a + ld ($a000),a + else ld a,7 ld ($7000),a + endif ld a,(fm_slot) inc a call nz,init_fm @@ -3162,10 +3169,17 @@ music_generate: ld a,(fm_slot) inc a jp z,.fm1 + if KONAMI + ld a,14 + ld ($8000),a + inc a + ld ($a000),a + else + ld a,7 + ld ($7000),a + endif ld a,(music_note_counter) or a - ld a,$07 - ld ($7000),a jp nz,music_generate_fm.6 ld hl,(music_pointer) .fm15: push hl @@ -3210,8 +3224,17 @@ music_generate: ret .fm19: cp -3 ; Repeat music? - ld a,$07 - ld ($7000),a + push af + if KONAMI + ld a,14 + ld ($8000),a + inc a + ld ($a000),a + else + ld a,7 + ld ($7000),a + endif + pop af jp nz,music_generate_fm.0 ld hl,(music_start) jr .fm15 @@ -4298,8 +4321,15 @@ WRITE_VRAM: equ $1fdf if FM_SUPPORT ld a,$ff ; FM hasn't been discovered. ld (fm_slot),a + if KONAMI + ld a,14 + ld ($8000),a + inc a + ld ($a000),a + else ld a,7 ld ($7000),a + endif call detect_fm endif ld a,($002b) diff --git a/manual.txt b/manual.txt index b32ae15..743169a 100644 --- a/manual.txt +++ b/manual.txt @@ -22,6 +22,11 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version +v0.9.2 Mar/12/2026 o Added OPTION FM. + o Added PLAY INSTRUMENT. + o Added PLAY FM. + o Added MUSIC.FM_ENABLED and MUSIC.FM_AVAILABLE. + v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. o MSX2: It supports MODE 4, extended sprites, @@ -1506,6 +1511,62 @@ The expression parser will take advantage of 8-bit variables and numbers to opti MUSIC.PLAYING Returns zero if music is not currently playing, returns a non-zero value otherwise. + + +>>>>>>>>>>>>>>. FM support for MSX/MSX2 + +CVBasic supports FM synthesis for MSX / MSX2 computers. + +For MSX and MSX2 computers it is needed an external FM cartridge. For MSX2+ computers +the FM support is built-in. + +Any game using FM support must use bank-switching. + +The FM library code will be automatically included in the bank 7, and 768 bytes of +space will be subtracted of the 16K. + + OPTION FM ON + This enables the FM support for your game (Yamaha YM2413) + + MUSIC.FM_AVAILABLE + This indicates with zero if FM isn't available, or non-zero if it is available. + + MUSIC.FM_ENABLED + This indicates with non-zero if the music player is using FM to play music, or + zero if it is playing music using the AY-3-8910 chip. + + PLAY FM ON + PLAY FM OFF + This enables or disables the FM support. Useful for making your game to switch + FM support to PSG and vice-versa. + + PLAY INSTRUMENT voice1,voice2,voice3,voice4 + This selects the FM instruments that will be used for the corresponding + instruments of the music player (piano, clarinet, flute, and bass). + + It should be used before playing another song. + + Bits 3-0 contain the volume for the instrument (0 being the maximum volume, + and 15 almost silent). + + Bits 7-4 contains the instrument number: + + 0 - Programmable (not available currently) + 1 - Violin + 2 - Guitar + 3 - Piano + 4 - Flute + 5 - Clarinet + 6 - Oboe + 7 - Trumpet + 8 - Organ + 9 - Horn + a - Synthesizer + b - Harpsichord + c - Vibraphone + d - Synthesizer bass + e - Wood bass + f - Electric guitar >>>>>>>>>>>>>> Useful VRAM addresses From 5c2ef2fb8277f263f8ef81c837b8c2c47b1cd068 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 12 Mar 2026 13:20:27 -0600 Subject: [PATCH 126/155] MSX/MSX2: Added example music_fm.bas --- examples/music_fm.bas | 307 ++++++++++++++++++++++++++++++++++++++++++ manual.txt | 2 + 2 files changed, 309 insertions(+) create mode 100644 examples/music_fm.bas diff --git a/examples/music_fm.bas b/examples/music_fm.bas new file mode 100644 index 0000000..e8f1be5 --- /dev/null +++ b/examples/music_fm.bas @@ -0,0 +1,307 @@ + rem + rem Test of IntyBASIC music player + rem by Oscar Toledo G. http://nanochess.org + rem Aug/26/2014 + rem + + REM Include useful predefined constants + + OPTION FM ON + + BANK ROM 128 + +main: + V=0 + +wait_key: + CLS + PRINT AT 66,"Press button" + FOR c = 0 TO 60 + WAIT + NEXT c +wait_loop: + IF CONT1.BUTTON THEN GOTO play_1 + IF CONT1.BUTTON2 THEN GOTO play_2 + + GOTO wait_loop + +play_1: + PRINT AT 66,"Bach Invention 8" + PRINT AT 130,"(fragment)" + WAIT + PLAY SIMPLE + ' Harpsichord (see manual) + PLAY INSTRUMENT $B0,$B0,$B0,$B0 + PLAY tune_1 + + ' Sound effect if button touch +repeat: + WAIT + IF CONT1.BUTTON2 THEN V=15 +REM SOUND 2,300,V + IF V>0 THEN V=V-1 + IF MUSIC.PLAYING THEN GOTO repeat + GOTO wait_key + +play_2: + PRINT AT 66,"Mecha-8 Level 4 " + PRINT AT 130,"(fragment)" + WAIT + PLAY FULL + PLAY INSTRUMENT $30,$70,$a0,$30 + PLAY tune_2 +repeat2: + WAIT + IF CONT1.BUTTON THEN PLAY OFF: GOTO wait_key + GOTO repeat2 + + ' Bach Invention 8 (BWV779) + ' Fragment +tune_1: DATA BYTE 7 + MUSIC F4,- + MUSIC S,- + MUSIC A4,- + MUSIC S,- + MUSIC F4,- + MUSIC S,- + MUSIC C5,- + MUSIC S,- + MUSIC F4,- + MUSIC S,- + + MUSIC F5,- + MUSIC S,- + MUSIC E5,F3 + MUSIC D5,S + MUSIC C5,A3 + MUSIC D5,S + MUSIC C5,F3 + MUSIC A4#,S + MUSIC A4,C4 + MUSIC A4#,S + MUSIC A4,F3 + MUSIC G4,S + + MUSIC F4,F4 + MUSIC S,S + MUSIC A4,E4 + MUSIC S,D4 + MUSIC C5,C4 + MUSIC S,D4 + MUSIC A4,C4 + MUSIC S,A3# + MUSIC F5,A3 + MUSIC S,A3# + MUSIC C5,A3 + MUSIC S,G3 + + MUSIC A5,F3 + MUSIC C6,S + MUSIC A5#,A3 + MUSIC C6,S + MUSIC A5,C4 + MUSIC C6,S + MUSIC A5#,A3 + MUSIC C6,S + MUSIC A5,F4 + MUSIC C6,S + MUSIC A5#,C4 + MUSIC C6,S + + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + + MUSIC B4,D3 + MUSIC S,F3 + MUSIC G4,E3 + MUSIC S,F3 + MUSIC D5,D3 + MUSIC S,F3 + MUSIC B4,E3 + MUSIC S,F3 + MUSIC F5,D3 + MUSIC S,F3 + MUSIC D5,E3 + MUSIC S,F3 + + MUSIC G5,B3 + MUSIC A5,S + MUSIC G5,G3 + MUSIC F5,S + MUSIC E5,C4 + MUSIC F5,S + MUSIC E5,G3 + MUSIC D5,S + MUSIC C5,E4 + MUSIC D5,S + MUSIC C5,C4 + MUSIC A4#,S + + MUSIC A4,F4 + MUSIC S,G4 + MUSIC D5,F4 + MUSIC C5,E4 + MUSIC B4,D4 + MUSIC C5,E4 + MUSIC B4,D4 + MUSIC A4,C4 + MUSIC G4,B3 + MUSIC A4,C4 + MUSIC G4,B3 + MUSIC F4,A3 + + MUSIC E4,G3 + MUSIC F4,S + MUSIC E4,C4 + MUSIC D4,B3 + MUSIC C4,A3 + MUSIC S,B3 + MUSIC C5,A3 + MUSIC B4,G3 + MUSIC C5,F3 + MUSIC S,G3 + MUSIC E4,F3 + MUSIC S,E3 + + MUSIC F4,D3 + MUSIC S,E3 + MUSIC C5,D3 + MUSIC S,C3 + MUSIC E4,G3 + MUSIC S,F3 + MUSIC C5,E3 + MUSIC S,F3 + MUSIC D4,G3 + MUSIC S,S + MUSIC B4,G2 + MUSIC S,S + + MUSIC C5,C4 + MUSIC S,S + MUSIC S,S + MUSIC S,S + MUSIC STOP + + ' Mecha-8 level 5: alone + ' Fragment +tune_2: DATA BYTE 5 + MUSIC G5#Y,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC E5,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC D5#,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC E5,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC G5#,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC S,G3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC C5#,G3#,-,M2 + MUSIC -,S,-,M2 + MUSIC G5#,C3#,-,M1 + MUSIC S,S,-,M2 + MUSIC E5,G3#,-,M2 + MUSIC -,S,-,M2 + MUSIC F5#,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,F3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC -,F3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,B2,-,M1 + MUSIC -,S,-,M2 + MUSIC -,F3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,B2,-,M1 + MUSIC -,S,-,M2 + MUSIC -,F3#,-,M1 + MUSIC -,S,-,M2 + MUSIC C5#,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,F3#,-,M1 + MUSIC S,S,-,M2 + MUSIC C5#,B2,-,M1 + MUSIC S,S,-,M2 + MUSIC E5,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC S,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M1 + MUSIC S,S,-,M2 + MUSIC F5#,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC E5,A2,-,M2 + MUSIC S,S,-,M2 + MUSIC D5#,E3,-,M1 + MUSIC S,S,-,M2 + MUSIC S,A2,-,M2 + MUSIC S,S,-,M2 + MUSIC C5,G2#,-,M1 + MUSIC S,S,-,M2 + MUSIC S,D3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,G2#,-,M1 + MUSIC S,S,-,M2 + MUSIC S,D3#,-,M2 + MUSIC S,S,-,M2 + MUSIC S,G2#,-,M1 + MUSIC S,S,-,M2 + MUSIC -,D3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M2 + MUSIC -,D3#,-,M2 + MUSIC -,S,-,M2 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M2 + MUSIC -,D3#,-,M1 + MUSIC -,S,-,M3 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M2 + MUSIC -,D3#,-,M1 + MUSIC -,S,-,M3 + MUSIC -,G2#,-,M1 + MUSIC -,S,-,M1 + MUSIC -,D3#,-,M1 + MUSIC -,S,-,M1 + MUSIC REPEAT diff --git a/manual.txt b/manual.txt index 743169a..82131b8 100644 --- a/manual.txt +++ b/manual.txt @@ -1525,6 +1525,8 @@ Any game using FM support must use bank-switching. The FM library code will be automatically included in the bank 7, and 768 bytes of space will be subtracted of the 16K. +An example is available in the directory examples/music_fm.bas + OPTION FM ON This enables the FM support for your game (Yamaha YM2413) From 8376e276dba46121079aa810aa5c4a57ef9afcb9 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 12 Mar 2026 22:18:39 +0100 Subject: [PATCH 127/155] Fixed typo --- manual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual.txt b/manual.txt index 82131b8..bc025a1 100644 --- a/manual.txt +++ b/manual.txt @@ -666,7 +666,7 @@ The following statements are available: It allows to define the color for each pixel row of a 16x16 sprite. - The data should be represente as DATA BYTE and 16 values for each sprite. + The data should be represented as DATA BYTE and 16 values for each sprite. Each byte contains the color (bits 3-0) From 45eeac9bc6c1768665e860962466091f9d4ec5d3 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 12 Mar 2026 22:27:26 +0100 Subject: [PATCH 128/155] Fixed minor typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5f36882..622d520 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Using CVBasic to compile a Sega SG1000/SC3000 program: cvbasic --sg1000 game.bas game.asm gasm80 game.asm -o game.rom -Using CVBasic to compile a MSX program for 8K RAM (wider compatibility) and 16K RAM: +Using CVBasic to compile an MSX program for 8K RAM (wider compatibility) and 16K RAM: cvbasic --msx game.bas game.asm gasm80 game.asm -o game.rom @@ -130,7 +130,7 @@ Using CVBasic to compile a MSX program for 8K RAM (wider compatibility) and 16K For bank-switched programs the default mapper is ASCII16, but you have the option of using a standard Konami 8K mapper using the -konami switch. -Using CVBasic to compile a MSX2 program for 8K RAM (wider compatibility) and 16K RAM: +Using CVBasic to compile an MSX2 program for 8K RAM (wider compatibility) and 16K RAM: cvbasic --msx2 game.bas game.asm gasm80 game.asm -o game.rom From 23627e1acdf2a10961d10c556b0e4df3ec18c80f Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 12 Mar 2026 17:13:37 -0600 Subject: [PATCH 129/155] SMS: Added FM synthesis support --- cvbasic.c | 21 +-- cvbasic_epilogue.asm | 293 ++++++++++++++++++++++++++---------------- cvbasic_prologue.asm | 47 ++++++- examples/music_fm.bas | 3 +- manual.txt | 12 +- 5 files changed, 246 insertions(+), 130 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index a809973..0c43e38 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -435,6 +435,9 @@ void bank_finish(void) if (bank_current == 0) { fprintf(output, "BANK_0_FREE:\tEQU $3fbf-$\n"); fprintf(output, "\tTIMES $3fbf-$ DB $ff\n"); + } else if (bank_current == 7 && option_fm != 0) { + fprintf(output, "BANK_%d_FREE:\tEQU $7d00-$\n", bank_current); + fprintf(output, "\tTIMES $7fbf-$ DB $ff\n"); } else { fprintf(output, "BANK_%d_FREE:\tEQU $7fbf-$\n", bank_current); fprintf(output, "\tTIMES $7fbf-$ DB $ff\n"); @@ -1660,10 +1663,10 @@ struct node *evaluate_level_7(int *type) } else if (strcmp(name, "PLAYING") == 0) { get_lex(); c = 0; - } else if (strcmp(name, "FM_AVAILABLE") == 0 && (machine == MSX || machine == MSX2)) { + } else if (strcmp(name, "FM_AVAILABLE") == 0 && (machine == MSX || machine == MSX2 || machine == SMS)) { get_lex(); c = 1; - } else if (strcmp(name, "FM_ENABLED") == 0 && (machine == MSX || machine == MSX2)) { + } else if (strcmp(name, "FM_ENABLED") == 0 && (machine == MSX || machine == MSX2 || machine == SMS)) { get_lex(); c = 2; } else { @@ -3575,8 +3578,8 @@ void compile_statement(int check_for_else) emit_error("missing ON/OFF in OPTION WARNINGS"); } } else if (strcmp(name, "FM") == 0) { - if (machine != MSX && machine != MSX2) - emit_warning("OPTION FM only works for MSX/MSX2 platforms"); + if (machine != MSX && machine != MSX2 && machine != SMS) + emit_warning("OPTION FM only works for MSX/MSX2/SMS"); get_lex(); if (lex == C_NAME && strcmp(name, "ON") == 0) { get_lex(); @@ -5564,8 +5567,8 @@ void compile_statement(int check_for_else) } } else if (strcmp(name, "FM") == 0) { get_lex(); - if (machine != MSX && machine != MSX2) - emit_warning("PLAY FM only allowed for MSX and MSX2"); + if (machine != MSX && machine != MSX2 && machine != SMS) + emit_warning("PLAY FM only allowed for MSX/MSX2/SMS"); if (lex == C_NAME && strcmp(name, "ON") == 0) { get_lex(); cpuz80_2op("LD", "A", "1"); @@ -5580,8 +5583,8 @@ void compile_statement(int check_for_else) } } else if (strcmp(name, "INSTRUMENT") == 0) { get_lex(); - if (machine != MSX && machine != MSX2) - emit_warning("PLAY INSTRUMENT only allowed for MSX and MSX2"); + if (machine != MSX && machine != MSX2 && machine != SMS) + emit_warning("PLAY INSTRUMENT only allowed for MSX/MSX2/SMS"); type = evaluate_expression(1, TYPE_8, 0); if (target == CPU_Z80) cpuz80_2op("LD", "(fm_inst)", "A"); @@ -7008,8 +7011,8 @@ int main(int argc, char *argv[]) fprintf(output, "MSX:\tequ %d\n", c); if (c) { fprintf(output, "KONAMI:\tequ %d\n", bank_konami); - fprintf(output, "FM_SUPPORT:\tequ %d\n", option_fm); } + fprintf(output, "FM_SUPPORT:\tequ %d\n", option_fm); fprintf(output, "SGM:\tequ %d\n", (machine == COLECOVISION_SGM) ? 1 : 0); fprintf(output, "SVI:\tequ %d\n", (machine == SVI) ? 1 : 0); fprintf(output, "SORD:\tequ %d\n", (machine == SORD) ? 1 : 0); diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 85bcaea..1000cfc 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -55,9 +55,9 @@ rom_end: if MSX if FM_SUPPORT ; - ; FM driver + ; FM driver for MSX ; - ; by Oscar Toledo G. + ; by Oscar Toledo G. (nanochess) ; ; Creation date: Sep/28/2012. For Mecha-9. ; Revision date: Mar/07/2026. Adapted for Metro Wars (CVBasic) @@ -67,10 +67,6 @@ rom_end: FORG $01FD00 ORG $BD00 - ; - ; This code cannot be in the area $4000-$7fff - ; - ; Subroutines from BIOS MSX CALSLT: equ $001c ; Inter-slot call (disables interruptions) ;ENASLT: equ $0024 ; Enable slot (H=High-byte address, C=Slot) @@ -79,6 +75,183 @@ CALSLT: equ $001c ; Inter-slot call (disables interruptions) WRTOPL: equ $4110 INIOPL: equ $4113 + ; + ; Detects FM (OPLL) + ; Carry = Set = FM detected. + ; Clear = No FM detected. + ; +msx_detect_fm: + ld bc,$0000 +.1: push bc + ld hl,$fcc1 ; EXPTBL + ld a,l + add a,c + ld l,a + ld a,(hl) + and $80 + or c + call msx_find_fm ; Search in subslots. + pop bc + ret nc ; Jump if something has been found. + inc c + bit 2,c ; Four slots analyzed? + jr z,.1 ; No, jump. + ret + +msx_fm_signature_1: db "APRLOPLL" ; Internal MSX-Music. +msx_fm_signature_2: db "PAC2OPLL" ; FM-Pac cartridge. + +msx_find_fm: + bit 7,a ; Expanded slot? + ld b,1 ; No subslots. + jr z,.1 ; No, jump. + and $f3 + ld b,4 ; Ok, four subslots. +.1: ld c,a +.2: push bc + ld h,$40 + ld a,c + call ENASLT + ld hl,$4018 + push hl + ld de,msx_fm_signature_1 + ld b,8 +.4: ld a,(de) + cp (hl) + jr nz,.5 + inc de + inc hl + djnz .4 +.5: pop hl + jr z,.8 ; Detected? Jump to take note. + ld de,msx_fm_signature_2 + ld b,8 +.6: ld a,(de) + cp (hl) + jr nz,.7 + inc de + inc hl + djnz .6 +.7: jr nz,.3 ; Not detected? Jump to next subslot. +.8: pop bc + ld a,c ; Take note of slot. + ld (fm_slot),a + push bc + ld a,1 ; Enable FM. + ld (fm_enabled),a +.3: + ; Important! The H register should be $40 here. + ld a,(cartridge_slot) + call ENASLT + pop bc + ld a,(fm_enabled) + or a + ret nz + ld a,c + add a,4 + ld c,a + djnz .2 + scf + ret + + ; Write a FM register + ; A = register + ; E = data +write_fm: + jp WRTOPL + + ; + ; Map FM BIOS 16K in $4000-$7FFF + ; +fm_rom_switch: + di + ld a,(fm_slot) + ld h,$40 + jp ENASLT + + ; + ; Map cartridge in $4000-$7FFF + ; +cartridge_rom_switch: + ld a,(cartridge_slot) + ld h,$40 + call ENASLT + ei + ret + + endif + endif + + if SMS + if FM_SUPPORT + ; + ; FM driver for Sega Master System. + ; + ; by Oscar Toledo G. (nanochess) + ; + ; Creation date: Sep/28/2012. For Mecha-9. + FORG $01FD00 + ORG $7D00 + + ; + ; Detect FM (OPLL) + ; +sms_detect_fm: + ld a,($c000) + or $04 + out ($3e),a + ld bc,$0700 +.1: ld a,b + and $01 + out ($f2),a + ld e,a + in a,($f2) + and $07 + cp e + jr nz,.2 + inc c +.2: djnz .1 + ld a,c + cp $07 + jr z,.3 + xor a +.3: and 1 + out ($f2),a + ld (fm_enabled),a + dec a ; For compatibility. + ld (fm_slot),a + ld a,($c000) + out ($3e),a + ret + + ; Write a FM register + ; A = register + ; E = data +write_fm: + out ($f0),a + ld a,e + out ($f1),a + ex (sp),hl + ex (sp),hl + ret + +fm_rom_switch: + di + ret + +cartridge_rom_switch: + ei + ret + + endif + endif + + if MSX+SMS + if FM_SUPPORT + ; + ; This code cannot be in the area $4000-$7fff + ; + ; ; Play music for FM ; @@ -264,85 +437,6 @@ play_fm: pop bc ret - ; - ; Detects FM (OPLL) - ; Carry = Set = FM detected. - ; Clear = No FM detected. - ; -detect_fm: - ld bc,$0000 -.1: push bc - ld hl,$fcc1 ; EXPTBL - ld a,l - add a,c - ld l,a - ld a,(hl) - and $80 - or c - call find_fm ; Search in subslots. - pop bc - ret nc ; Jump if something has been found. - inc c - bit 2,c ; Four slots analyzed? - jr z,.1 ; No, jump. - ret - -fm_signature_1: db "APRLOPLL" ; Internal MSX-Music. -fm_signature_2: db "PAC2OPLL" ; FM-Pac cartridge. - -find_fm: - bit 7,a ; Expanded slot? - ld b,1 ; No subslots. - jr z,.1 ; No, jump. - and $f3 - ld b,4 ; Ok, four subslots. -.1: ld c,a -.2: push bc - ld h,$40 - ld a,c - call ENASLT - ld hl,$4018 - push hl - ld de,fm_signature_1 - ld b,8 -.4: ld a,(de) - cp (hl) - jr nz,.5 - inc de - inc hl - djnz .4 -.5: pop hl - jr z,.8 ; Detected? Jump to take note. - ld de,fm_signature_2 - ld b,8 -.6: ld a,(de) - cp (hl) - jr nz,.7 - inc de - inc hl - djnz .6 -.7: jr nz,.3 ; Not detected? Jump to next subslot. -.8: pop bc - ld a,c ; Take note of slot. - ld (fm_slot),a - push bc - ld a,1 ; Enable FM. - ld (fm_enabled),a -.3: - ; Important! The H register should be $40 here. - ld a,(cartridge_slot) - call ENASLT - pop bc - ld a,(fm_enabled) - or a - ret nz - ld a,c - add a,4 - ld c,a - djnz .2 - scf - ret - ; ; Init FM ; @@ -350,8 +444,10 @@ init_fm: push ix push iy call fm_rom_switch + if MSX ld hl,$ef00 call INIOPL + endif ld hl,.0 ld b,24 .1: ld e,(hl) @@ -421,31 +517,6 @@ turn_off_fm: CALL cartridge_rom_switch RET - ; Write a FM register - ; A = register - ; E = data -write_fm: - jp WRTOPL - - ; - ; Map FM BIOS 16K in $4000-$7FFF - ; -fm_rom_switch: - di - ld a,(fm_slot) - ld h,$40 - jp ENASLT - - ; - ; Map cartridge in $4000-$7FFF - ; -cartridge_rom_switch: - ld a,(cartridge_slot) - ld h,$40 - call ENASLT - ei - ret - fm_notes: ; Silence - 0 dw 0 @@ -490,7 +561,7 @@ cursor: rb 2 lfsr: rb 2 - if MSX + if MSX+SMS cartridge_slot: rb 1 fm_slot: diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index dc3b403..7aff5e9 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -3056,6 +3056,13 @@ music_init: if MEMOTECH in a,($03) endif + if FM_SUPPORT + ld a,7 + ld ($fffe),a + ld a,(fm_slot) + inc a + call nz,init_fm + endif endif if COLECO+SG1000+SMS+MSX+SVI+SORD+MEMOTECH+PV2000 MIX_BASE: equ $b8 @@ -3161,14 +3168,14 @@ music_generate: ld a,$ff ld (audio_vol4hw),a - if MSX - if FM_SUPPORT + if FM_SUPPORT ld a,(fm_enabled) or a jp z,.fm1 ld a,(fm_slot) inc a jp z,.fm1 + if MSX if KONAMI ld a,14 ld ($8000),a @@ -3178,6 +3185,11 @@ music_generate: ld a,7 ld ($7000),a endif + endif + if SMS + ld a,7 + ld ($fffe),a + endif ld a,(music_note_counter) or a jp nz,music_generate_fm.6 @@ -3225,6 +3237,7 @@ music_generate: .fm19: cp -3 ; Repeat music? push af + if MSX if KONAMI ld a,14 ld ($8000),a @@ -3234,13 +3247,17 @@ music_generate: ld a,7 ld ($7000),a endif + endif + if SMS + ld a,7 + ld ($fffe),a + endif pop af jp nz,music_generate_fm.0 ld hl,(music_start) jr .fm15 .fm1: - endif endif ld a,(music_note_counter) @@ -4044,6 +4061,13 @@ START: if SVI+SG1000+SMS im 1 endif + if SMS + ld a,7 + ld ($fffe),a + call sms_detect_fm + ld a,1 + ld ($fffe),a + endif if MEMOTECH Z80_CTC: equ $08 endif @@ -4197,11 +4221,17 @@ Z80_CTC: equ $28 endif if MSX+SVI+SMS ld ix,(lfsr) + if SMS + ld iy,(fm_slot) + endif ld hl,BASE_RAM ld de,BASE_RAM+1 ld bc,RAM_SIZE-1 ld (hl),0 ldir + if SMS + ld (fm_slot),iy + endif ld (lfsr),ix endif if COLECO+SG1000+SORD+PENCIL+PV2000 @@ -4330,7 +4360,16 @@ WRITE_VRAM: equ $1fdf ld a,7 ld ($7000),a endif - call detect_fm + call msx_detect_fm + if KONAMI + ld a,2 + ld ($8000),a + inc a + ld ($a000),a + else + ld a,1 + ld ($7000),a + endif endif ld a,($002b) cpl diff --git a/examples/music_fm.bas b/examples/music_fm.bas index e8f1be5..afa130d 100644 --- a/examples/music_fm.bas +++ b/examples/music_fm.bas @@ -1,7 +1,8 @@ rem rem Test of IntyBASIC music player rem by Oscar Toledo G. http://nanochess.org - rem Aug/26/2014 + rem Aug/26/2014 + rem Mar/12/2026. For FM synthesis in MSX/MSX2 and Sega Master System. rem REM Include useful predefined constants diff --git a/manual.txt b/manual.txt index bc025a1..82c1a1b 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Feb/17/2026 +Last revision: Mar/12/2026 >>>>>>>>>>>>>> Legal notice @@ -22,7 +22,8 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.2 Mar/12/2026 o Added OPTION FM. +v0.9.2 Mar/12/2026 o FM synthesis for MSX, MSX2, and Sega Master System. + o Added OPTION FM. o Added PLAY INSTRUMENT. o Added PLAY FM. o Added MUSIC.FM_ENABLED and MUSIC.FM_AVAILABLE. @@ -1513,9 +1514,10 @@ The expression parser will take advantage of 8-bit variables and numbers to opti value otherwise. ->>>>>>>>>>>>>>. FM support for MSX/MSX2 +>>>>>>>>>>>>>>. FM support for MSX/MSX2/SMS -CVBasic supports FM synthesis for MSX / MSX2 computers. +CVBasic supports FM synthesis for MSX/MSX2 computers, and Sega Master System consoles +with FM card. For MSX and MSX2 computers it is needed an external FM cartridge. For MSX2+ computers the FM support is built-in. @@ -1535,7 +1537,7 @@ An example is available in the directory examples/music_fm.bas MUSIC.FM_ENABLED This indicates with non-zero if the music player is using FM to play music, or - zero if it is playing music using the AY-3-8910 chip. + zero if it is playing music using the AY-3-8910 chip (or SN76489 in SMS) PLAY FM ON PLAY FM OFF From f29f068786e1e54a301217a545a0268fca8f3a1c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 12 Mar 2026 17:30:19 -0600 Subject: [PATCH 130/155] SMS: Adjustments --- cvbasic_epilogue.asm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 1000cfc..51b5c79 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -189,7 +189,9 @@ cartridge_rom_switch: ; ; by Oscar Toledo G. (nanochess) ; - ; Creation date: Sep/28/2012. For Mecha-9. + ; Creation date: Sep/28/2012. For MSX. + ; Revision date: Aug/16/2013. Adapted to Sega Master System. + ; Revision date: Mar/12/2026. Adapted to CVBasic. FORG $01FD00 ORG $7D00 From 9fea0b5710bd74c7f6aecd5286bd4152497f79e9 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 12 Mar 2026 19:11:05 -0600 Subject: [PATCH 131/155] FM: Indications added to manual about initialization --- manual.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/manual.txt b/manual.txt index 82c1a1b..9edc29b 100644 --- a/manual.txt +++ b/manual.txt @@ -1532,6 +1532,10 @@ An example is available in the directory examples/music_fm.bas OPTION FM ON This enables the FM support for your game (Yamaha YM2413) + With FM support, CVBasic will check automatically at startup for the FM chip, + and if detected it will enabled it automatically for music playing (a default + set of instruments in prepared, compatible with PSG songs) + MUSIC.FM_AVAILABLE This indicates with zero if FM isn't available, or non-zero if it is available. From 6fe7c771cf585b3dd6e53a0faf7df84b3e19c9ca Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 12 Mar 2026 19:15:16 -0600 Subject: [PATCH 132/155] FM: Added further notes about fallback --- manual.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/manual.txt b/manual.txt index 9edc29b..fcdb6cc 100644 --- a/manual.txt +++ b/manual.txt @@ -1533,8 +1533,11 @@ An example is available in the directory examples/music_fm.bas This enables the FM support for your game (Yamaha YM2413) With FM support, CVBasic will check automatically at startup for the FM chip, - and if detected it will enabled it automatically for music playing (a default - set of instruments in prepared, compatible with PSG songs) + and if detected it will enable it automatically for music playing (default + instruments are prepared) + + If no FM is detected, CVBasic will fall gracefully back to the SN76489 or + AY-3-8910 music playing. MUSIC.FM_AVAILABLE This indicates with zero if FM isn't available, or non-zero if it is available. @@ -1548,11 +1551,14 @@ An example is available in the directory examples/music_fm.bas This enables or disables the FM support. Useful for making your game to switch FM support to PSG and vice-versa. + Turning on FM without the chip won't cause any effect, and the music playing + will be still through the PSG chip. + PLAY INSTRUMENT voice1,voice2,voice3,voice4 This selects the FM instruments that will be used for the corresponding instruments of the music player (piano, clarinet, flute, and bass). - It should be used before playing another song. + It should be used before playing a song. Bits 3-0 contain the volume for the instrument (0 being the maximum volume, and 15 almost silent). From eef77896dbd304e728b98a39a52a205573abcdd0 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 23 Mar 2026 21:32:16 -0600 Subject: [PATCH 133/155] Z80: Optimized 16-bit multiplication to use a lot fewer cycles in most cases --- cvbasic_prologue.asm | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 7aff5e9..738c14a 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -935,18 +935,30 @@ update_sprite: ; Fast 16-bit multiplication. _mul16: + or a + sbc hl,de + add hl,de + jr nc,$+3 + ex de,hl ; Smallest operand in DE. + ld b,h ld c,l - ld a,16 ld hl,0 .1: srl d rr e - jr nc,.2 + jp nc,$+4 add hl,bc -.2: sla c + sla c rl b - dec a + srl d + rr e + jp nc,$+4 + add hl,bc + sla c + rl b + ld a,d + or e jp nz,.1 ret From 937c3e68cdb09fa849eaf7a3b21be0feb55d0833 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 23 Mar 2026 23:50:43 -0600 Subject: [PATCH 134/155] Added optimization notes --- cvbasic_prologue.asm | 48 ++++++++++++++++++++++---------------------- manual.txt | 6 ++++++ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 738c14a..ea4fc1c 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -935,31 +935,31 @@ update_sprite: ; Fast 16-bit multiplication. _mul16: - or a - sbc hl,de - add hl,de - jr nc,$+3 - ex de,hl ; Smallest operand in DE. - - ld b,h - ld c,l - ld hl,0 + or a ; 5 + sbc hl,de ; 17 + add hl,de ; 12 + jr nc,$+3 ; 13/8 + ex de,hl ; 5 Smallest operand in DE. + + ld b,h ; 5 + ld c,l ; 5 + ld hl,0 ; 11 .1: - srl d - rr e - jp nc,$+4 - add hl,bc - sla c - rl b - srl d - rr e - jp nc,$+4 - add hl,bc - sla c - rl b - ld a,d - or e - jp nz,.1 + srl d ; 10 + rr e ; 10 + jp nc,$+4 ; 11 + add hl,bc ; 12 + sla c ; 10 + rl b ; 10 + srl d ; 10 + rr e ; 10 + jp nc,$+4 ; 11 + add hl,bc ; 12 + sla c ; 10 + rl b ; 10 + ld a,d ; 5 + or e ; 5 + jp nz,.1 ; 11 ret ; 16-bit signed modulo. diff --git a/manual.txt b/manual.txt index fcdb6cc..bb19147 100644 --- a/manual.txt +++ b/manual.txt @@ -27,6 +27,12 @@ v0.9.2 Mar/12/2026 o FM synthesis for MSX, MSX2, and Sega Master System. o Added PLAY INSTRUMENT. o Added PLAY FM. o Added MUSIC.FM_ENABLED and MUSIC.FM_AVAILABLE. + o Z80: Optimization in multiple array access in expressions. + o Z80: Avoid constant reload. + o Z80: Optimization IF with 8-bit AND, and multiplication by 128. + o Z80: Speed up of block copy to screen and VRAM fill. + o Z80: Optimized 16-bit multiplication (before always 1277 cycles, + now minimum of 191 cycles and maximum 1244 cycles) v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. From 164ac95f18799d2a6b53208a75f805bb11688846 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Wed, 25 Mar 2026 18:43:55 -0600 Subject: [PATCH 135/155] Further optimization of 16-bit multiplication and division, all platforms --- README.md | 1 + cvbasic_6502_prologue.asm | 24 ++++----- cvbasic_nes_prologue.asm | 24 ++++----- cvbasic_prologue.asm | 105 ++++++++++++++++++++++++++++---------- examples/test4.bas | 85 ++++++++++++++++++++++++++++++ 5 files changed, 181 insertions(+), 58 deletions(-) create mode 100644 examples/test4.bas diff --git a/README.md b/README.md index 622d520..dfec7a0 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ The following files compose the compiler: examples/test2.bas Arithmetic test. examples/test3.bas Shows usage of SELECT CASE / END CASE examples/test3_sms.bas Shows usage of SELECT CASE / END CASE (Sega Master System) + examples/test4.bas Benchmark and test of multiplication/division examples/varptr.bas VARPTR example for redefining graphics. examples/varptr_sms.bas VARPTR example for redefining graphics (Sega Master System) examples/vgm.bas VGM audio player for SN76489. diff --git a/cvbasic_6502_prologue.asm b/cvbasic_6502_prologue.asm index 4e44ad7..cf7e498 100644 --- a/cvbasic_6502_prologue.asm +++ b/cvbasic_6502_prologue.asm @@ -14,6 +14,8 @@ ; with flicker flag). ; Revision date: Oct/15/2024. Added LDIRMV. ; Revision date: Nov/12/2024. Saves the VDP status. + ; Revision date: Mar/25/2026. Faster _mul16 (using Y in loop) and _div16 + ; (avoids update using registers) ; CPU 6502 @@ -680,7 +682,7 @@ _mul16: PHA LDA #0 STA result - STA result+1 + TAY LDX #15 .1: LSR temp2+1 @@ -690,15 +692,14 @@ _mul16: CLC ADC temp STA result - LDA result+1 + TYA ADC temp+1 - STA result+1 + TAY .2: ASL temp ROL temp+1 DEX BPL .1 LDA result - LDY result+1 RTS ; 16-bit signed modulo. @@ -801,20 +802,13 @@ _div16: LDA result SEC SBC temp - STA result + TAY LDA result+1 SBC temp+1 + BCC .3 + STY result STA result+1 - BCS .3 - LDA result - ADC temp - STA result - LDA result+1 - ADC temp+1 - STA result+1 - CLC -.3: - DEX +.3: DEX BPL .2 ROL temp2 ROL temp2+1 diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index a63c84e..2433156 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -12,6 +12,8 @@ ; Revision date: Aug/25/2025. Added support for 256K and 512K ROM. ; Revision date: Aug/26/2025. Added support for CHRRAM selection. ; Revision date: Feb/16/2026. Relocated PPUBUF. + ; Revision date: Mar/25/2026. Faster _mul16 (using Y in loop) and _div16 + ; (avoids update using registers) ; CPU 6502 @@ -410,7 +412,7 @@ _mul16: PHA LDA #0 STA result - STA result+1 + TAY LDX #15 .1: LSR temp2+1 @@ -420,15 +422,14 @@ _mul16: CLC ADC temp STA result - LDA result+1 + TYA ADC temp+1 - STA result+1 + TAY .2: ASL temp ROL temp+1 DEX BPL .1 LDA result - LDY result+1 RTS ; 16-bit signed modulo. @@ -531,20 +532,13 @@ _div16: LDA result SEC SBC temp - STA result + TAY LDA result+1 SBC temp+1 + BCC .3 + STY result STA result+1 - BCS .3 - LDA result - ADC temp - STA result - LDA result+1 - ADC temp+1 - STA result+1 - CLC -.3: - DEX +.3: DEX BPL .2 ROL temp2 ROL temp2+1 diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index ea4fc1c..9cdafd2 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -933,7 +933,22 @@ update_sprite: endif ret - ; Fast 16-bit multiplication. + ; + ; Fast 16-bit multiplication by Oscar Toledo G. + ; Input: + ; HL = Operand 1. + ; DE = Operand 2. + ; Output: + ; HL = HL x DE. + ; + ; This is a trick I've discovered. + ; 1. The smallest operand goes into DE. + ; The biggest operand goes into BC. + ; HL becomes zero. + ; 2. If D is non-zero, calculate H = D x C with 8-bit arithmetic. + ; B can be ignored as this routine doesn't generate a 24-bit result. + ; 3. Calculate HL = HL + E x BC with early exit as it shifts E to the right. + ; _mul16: or a ; 5 sbc hl,de ; 17 @@ -944,23 +959,56 @@ _mul16: ld b,h ; 5 ld c,l ; 5 ld hl,0 ; 11 -.1: - srl d ; 10 - rr e ; 10 + ld a,d + or a ; High-byte is zero? + jp z,.2 ; Yes, jump. + xor a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + add a,a ; 5 + sla d ; 10 + jp nc,$+4 ; 11 + add a,c ; 5 + ld h,a ; 5 +.2: ; +.3: srl e ; 10 jp nc,$+4 ; 11 add hl,bc ; 12 + ret z ; 6/12 sla c ; 10 rl b ; 10 - srl d ; 10 - rr e ; 10 + srl e ; 10 jp nc,$+4 ; 11 add hl,bc ; 12 + ret z ; 6/12 sla c ; 10 rl b ; 10 - ld a,d ; 5 - or e ; 5 - jp nz,.1 ; 11 - ret + jp .3 ; 11 ; 16-bit signed modulo. ; hl = hl % de @@ -1012,21 +1060,7 @@ _neg16: ; Fast 16-bit division. ; hl = hl / de _div16: - ld b,h - ld c,l - ld hl,0 - ld a,16 -.1: - rl c - rl b - adc hl,hl - sbc hl,de - jp nc,.2 - add hl,de -.2: - ccf - dec a - jp nz,.1 + call _mod16 rl c rl b ld h,b @@ -1038,16 +1072,31 @@ _mod16: ld b,h ld c,l ld hl,0 - ld a,16 + + ld a,b + or a + ld a,8 + jr nz,.1 + rrca + ld b,c + ld c,0 .1: rl c rl b adc hl,hl sbc hl,de - jp nc,.2 + jp nc,$+4 add hl,de -.2: ccf + + rl c + rl b + adc hl,hl + sbc hl,de + jp nc,$+4 + add hl,de + ccf + dec a jp nz,.1 ret diff --git a/examples/test4.bas b/examples/test4.bas new file mode 100644 index 0000000..239e31f --- /dev/null +++ b/examples/test4.bas @@ -0,0 +1,85 @@ + ' + ' Benchmark and multiplication/division routines test. + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Mar/25/2026. + ' + + #time = FRAME + FOR #c = 1 TO 65534 + #d = $0001 * #c + IF FRAME - #time >= 60 THEN EXIT FOR + NEXT #c + PRINT AT $0002,<.5>#c," muls $0001 in 1 second" + #time = FRAME + FOR #c = 1 TO 65534 + #d = $00ff * #c + IF FRAME - #time >= 60 THEN EXIT FOR + NEXT #c + PRINT AT $0022,<.5>#c," muls $00ff in 1 second" + #time = FRAME + FOR #c = 1 TO 65534 + #d = $8000 * #c + IF FRAME - #time >= 60 THEN EXIT FOR + NEXT #c + PRINT AT $0042,<.5>#c," muls $8000 in 1 second" + #time = FRAME + FOR #c = 1 TO 65534 + #d = $aa55 * #c + IF FRAME - #time >= 60 THEN EXIT FOR + NEXT #c + PRINT AT $0062,<.5>#c," muls $aa55 in 1 second" + + #time = FRAME + FOR #c = 1 TO 65534 + #d = $00ff / #c + IF FRAME - #time >= 60 THEN EXIT FOR + NEXT #c + PRINT AT $00C2,#c," divs $00ff in 1 second." + + #time = FRAME + FOR #c = 1 TO 65534 + #d = $FFFF / #c + IF FRAME - #time >= 60 THEN EXIT FOR + NEXT #c + PRINT AT $00e2,#c," divs $ffff in 1 second." + + #e = $0101 + FOR #c = 1 TO 65000 STEP 101 + #d = $0101 * #c + PRINT AT $0122,"$0101 * ",#c, " = ",<.5>#d + IF #d <> #e THEN PRINT AT $0142,"bad ",#c + #e = #e + $0101 * 101 + NEXT #c + + #e = $0100 + FOR #c = 1 TO 65000 STEP 101 + #d = $0100 * #c + PRINT AT $0162,"$0100 * ",#c, " = ",<.5>#d + IF #d <> #e THEN PRINT AT $0182,"bad ",#c + #e = #e + $0100 * 101 + NEXT #c + + #e = $0001 + FOR #c = 1 TO 65000 STEP 101 + #d = $0001 * #c + PRINT AT $01A2,"$0001 * ",#c, " = ",<.5>#d + IF #d <> #e THEN PRINT AT $01C2,"bad ",#c + #e = #e + $0001 * 101 + NEXT #c + + #e = $0007 + FOR #c = 1 TO 1000 + #d = #e / 7 + PRINT AT $01e2,#e, " / $0007 = ",<.5>#d + IF #d <> #c THEN PRINT AT $0202,"bad ",#c + #e = #e + 7 + NEXT #c + + WHILE 1: WEND + + ' For testing NES code generation. +' CHRROM 0 + From 6181de9b9fb48656571950268bf56e04f1464947 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 29 Mar 2026 19:14:59 -0600 Subject: [PATCH 136/155] 6502: 28% speed up of 16-bit multiplication. Removed stack unwinding for 16-bit mul, div, and mod --- cpu6502.c | 37 +++++++++++++----- cvbasic_6502_prologue.asm | 81 +++++++++++---------------------------- cvbasic_nes_prologue.asm | 80 +++++++++++--------------------------- cvbasic_prologue.asm | 1 + 4 files changed, 73 insertions(+), 126 deletions(-) diff --git a/cpu6502.c b/cpu6502.c index 4511095..85062b9 100644 --- a/cpu6502.c +++ b/cpu6502.c @@ -1552,8 +1552,6 @@ void cpu6502_node_generate(struct node *node, int decision) cpu6502_noop("TYA"); cpu6502_noop("PHA"); cpu6502_node_generate(node->left, 0); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); stack = 1; } } else { @@ -1579,13 +1577,13 @@ void cpu6502_node_generate(struct node *node, int decision) cpu6502_noop("TYA"); cpu6502_noop("PHA"); cpu6502_node_generate(node->right, 0); - cpu6502_1op("STA", "temp"); - cpu6502_1op("STY", "temp+1"); stack = 1; } } if (node->type == N_OR16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_1op("ORA", "temp+1"); cpu6502_noop("TAY"); @@ -1608,6 +1606,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_XOR16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_1op("EOR", "temp+1"); cpu6502_noop("TAY"); @@ -1630,6 +1630,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_AND16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_1op("AND", "temp+1"); cpu6502_noop("TAY"); @@ -1652,6 +1654,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_EQUAL16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_noop("TAY"); cpu6502_noop("PLA"); @@ -1688,6 +1692,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_NOTEQUAL16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_noop("TAY"); cpu6502_noop("PLA"); @@ -1724,6 +1730,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_LESS16 || node->type == N_GREATER16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_noop("TAY"); cpu6502_noop("PLA"); @@ -1747,6 +1755,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_LESSEQUAL16 || node->type == N_GREATEREQUAL16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_noop("TAY"); cpu6502_noop("PLA"); @@ -1771,6 +1781,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_PLUS16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_noop("TAY"); cpu6502_noop("PLA"); @@ -1792,6 +1804,8 @@ void cpu6502_node_generate(struct node *node, int decision) } } else if (node->type == N_MINUS16) { if (stack) { + cpu6502_1op("STA", "temp"); + cpu6502_1op("STY", "temp+1"); cpu6502_noop("PLA"); cpu6502_noop("TAY"); cpu6502_noop("PLA"); @@ -1812,14 +1826,17 @@ void cpu6502_node_generate(struct node *node, int decision) cpu6502_noop("TXA"); } } else { - if (!stack) { - cpu6502_noop("PHA"); - cpu6502_noop("TYA"); - cpu6502_noop("PHA"); - cpu6502_1op("LDA", temp); - cpu6502_1op("LDY", temp2); + if (stack) { cpu6502_1op("STA", "temp"); cpu6502_1op("STY", "temp+1"); + cpu6502_noop("PLA"); + cpu6502_noop("TAY"); + cpu6502_noop("PLA"); + } else { + cpu6502_1op("LDX", temp); + cpu6502_1op("STX", "temp"); + cpu6502_1op("LDX", temp2); + cpu6502_1op("STX", "temp+1"); } if (node->type == N_MUL16) { cpu6502_1op("JSR", "_mul16"); diff --git a/cvbasic_6502_prologue.asm b/cvbasic_6502_prologue.asm index cf7e498..f791141 100644 --- a/cvbasic_6502_prologue.asm +++ b/cvbasic_6502_prologue.asm @@ -16,6 +16,9 @@ ; Revision date: Nov/12/2024. Saves the VDP status. ; Revision date: Mar/25/2026. Faster _mul16 (using Y in loop) and _div16 ; (avoids update using registers) + ; Revision date: Mar/29/2026. Avoids unwinding stack for _mul16, _div16, _div16s, + ; _mod16, and _mod16s. Optimized _mul16 in two + ; loops (28% speed-up) ; CPU 6502 @@ -668,25 +671,15 @@ _peek16: ; 16-bit multiplication. _mul16: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 LDA #0 STA result TAY - LDX #15 + ; Shift low-byte of multiplier + LDX #7 .1: - LSR temp2+1 - ROR temp2 + LSR temp2 BCC .2 LDA result CLC @@ -699,23 +692,25 @@ _mul16: ROL temp+1 DEX BPL .1 + ; Shift high-byte of multiplier (temp is zero here) + TYA + LDX #7 +.3: + LSR temp2+1 + BCC .4 + CLC + ADC temp+1 +.4: ASL temp+1 + DEX + BPL .3 + TAY LDA result RTS ; 16-bit signed modulo. _mod16s: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 LDY temp2+1 PHP BPL .1 @@ -740,18 +735,8 @@ _mod16s: ; 16-bit signed division. _div16s: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 LDA temp+1 EOR temp2+1 PHP @@ -777,18 +762,8 @@ _div16s: RTS _div16: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 .1: LDA #0 STA result @@ -817,18 +792,8 @@ _div16: RTS _mod16: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 .1: LDA #0 STA result diff --git a/cvbasic_nes_prologue.asm b/cvbasic_nes_prologue.asm index 2433156..108fc39 100644 --- a/cvbasic_nes_prologue.asm +++ b/cvbasic_nes_prologue.asm @@ -14,6 +14,8 @@ ; Revision date: Feb/16/2026. Relocated PPUBUF. ; Revision date: Mar/25/2026. Faster _mul16 (using Y in loop) and _div16 ; (avoids update using registers) + ; Revision date: Mar/29/2026. Avoids unwinding stack for _mul16, _div16, _div16s, + ; _mod16, and _mod16s. ; CPU 6502 @@ -398,25 +400,15 @@ _peek16: ; 16-bit multiplication. _mul16: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 LDA #0 STA result TAY - LDX #15 + ; Shift low-byte of multiplier + LDX #7 .1: - LSR temp2+1 - ROR temp2 + LSR temp2 BCC .2 LDA result CLC @@ -429,23 +421,25 @@ _mul16: ROL temp+1 DEX BPL .1 + ; Shift high-byte of multiplier (temp is zero here) + TYA + LDX #7 +.3: + LSR temp2+1 + BCC .4 + CLC + ADC temp+1 +.4: ASL temp+1 + DEX + BPL .3 + TAY LDA result RTS ; 16-bit signed modulo. _mod16s: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 LDY temp2+1 PHP BPL .1 @@ -470,18 +464,8 @@ _mod16s: ; 16-bit signed division. _div16s: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 LDA temp+1 EOR temp2+1 PHP @@ -507,18 +491,8 @@ _div16s: RTS _div16: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 .1: LDA #0 STA result @@ -547,18 +521,8 @@ _div16: RTS _mod16: - PLA - STA result - PLA - STA result+1 - PLA - STA temp2+1 - PLA STA temp2 - LDA result+1 - PHA - LDA result - PHA + STY temp2+1 .1: LDA #0 STA result diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 9cdafd2..64d7e37 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1073,6 +1073,7 @@ _mod16: ld c,l ld hl,0 + ; Save cycles if top byte is zero. ld a,b or a ld a,8 From 667f1024005baa11a3cc59ed6cbcdb8efc3e07a7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 2 Apr 2026 22:33:48 -0600 Subject: [PATCH 137/155] Updated list of games developed with CVBasic --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dfec7a0..a35d603 100644 --- a/README.md +++ b/README.md @@ -282,18 +282,28 @@ There are some very good examples of games developed with CVBasic. * Colecovania demo by Skywaffle. Video at [https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl](https://www.youtube.com/watch?v=ixlAEZ0GSis&ab_channel=MatthewKiehl) +* Crackpots by Eric Damain. Available from [https://forums.atariage.com/topic/388119-crackpots/](https://forums.atariage.com/topic/388119-crackpots/) + * Donkey.BAS by Claus Bækkel. Available for purchase from [https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/](https://forums.atariage.com/topic/366153-donkeybas-game-coded-in-cvbasic-0500/) +* Dragon's Descent by Revontuli. Demo available from [https://forums.atariage.com/topic/388152-dragons-descent-for-the-colecovision/](https://forums.atariage.com/topic/388152-dragons-descent-for-the-colecovision/) + * Duocide by Jess Ragan. Demo available from [https://forums.atariage.com/topic/379738-duocide-the-side-switching-shooter/](https://forums.atariage.com/topic/379738-duocide-the-side-switching-shooter/) +* Eye Brawls by Jess Ragan. Demo available from [https://forums.atariage.com/topic/387711-eye-brawls-the-rev-eye-val/](https://forums.atariage.com/topic/387711-eye-brawls-the-rev-eye-val/) + * Gorilla.BAS by nanochess. Available from [https://forums.atariage.com/topic/370716-gorillabas-for-colecovision/](https://forums.atariage.com/topic/370716-gorillabas-for-colecovision/) * Gun Fight by Eric Damain. Video at [https://forums.atariage.com/topic/379102-gun-fight-dev-log-cvbasic/](https://forums.atariage.com/topic/379102-gun-fight-dev-log-cvbasic/) +* Hamurabi by Eric Damain. Available from [https://forums.atariage.com/topic/380392-hamurabi-dev-log-cvbasic/](https://forums.atariage.com/topic/380392-hamurabi-dev-log-cvbasic/) + * Jurl by Tonsomo Entertainment. Available from [https://tonsomo.itch.io/jurl-colecovision-edition](https://tonsomo.itch.io/jurl-colecovision-edition) * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) +* Metro Wars by nanochess (MSX2). ROM available for download from [https://www.msxdev.org/2026/03/08/msxdev25-36-metro-wars/](https://www.msxdev.org/2026/03/08/msxdev25-36-metro-wars/) + * Monkey Moon by nanochess, example from the book **Programming Games for Colecovision**. Available from [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249) * Operation Hibernation by Jess Ragan. Available from [https://forums.atariage.com/topic/383365-operation-hibernation-nearing-completion/](https://forums.atariage.com/topic/383365-operation-hibernation-nearing-completion/) @@ -302,12 +312,14 @@ There are some very good examples of games developed with CVBasic. * Rogue-like Wip by Skywaffle. Available from [https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/](https://forums.atariage.com/topic/372717-colecovision-rogue-like-wip/) -* Shamus by nanochess. Available from [https://forums.atariage.com/topic/383531-shamus-for-colecovision/](https://forums.atariage.com/topic/383531-shamus-for-colecovision/) - * Solar Fox 2 by Jess Ragan. Available from [https://forums.atariage.com/topic/382881-solar-fox-2-is-finished-link-inside/](https://forums.atariage.com/topic/382881-solar-fox-2-is-finished-link-inside/) * Sub Hunt by Eric Damain. Demo videos [https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/](https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/) +* SWOPEM by chalkyw64 (MSX). Available from [https://forums.atariage.com/topic/387521-swopem-a-simple-match3-game-for-msx-and-colecovision/](https://forums.atariage.com/topic/387521-swopem-a-simple-match3-game-for-msx-and-colecovision/) + +* Taz by Eric Damain. Demo available from [https://forums.atariage.com/topic/388119-crackpots/](https://forums.atariage.com/topic/388119-crackpots/) + * Whack'em Smack'em Byron by Jess Ragan. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) ### Supporting the developer From 3b36b94aa698336d732163f93a005d91562ef13d Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Tue, 7 Apr 2026 16:03:22 -0600 Subject: [PATCH 138/155] Added 32-bit Z80 square root routine for future tests --- others/sqrt.asm | 163 +++++++++++++++++++++++++++++++++++++++++++ others/test_sqrt.bas | 20 ++++++ 2 files changed, 183 insertions(+) create mode 100644 others/sqrt.asm create mode 100644 others/test_sqrt.bas diff --git a/others/sqrt.asm b/others/sqrt.asm new file mode 100644 index 0000000..4955171 --- /dev/null +++ b/others/sqrt.asm @@ -0,0 +1,163 @@ + ; + ; Z80 integer 32-bit square root + ; + ; by Oscar Toledo G. + ; + ; Creation date: Apr/07/2026. + ; + ; Based on code from https://stackoverflow.com/questions/15557667/square-root-by-bit-shift + ; + ; Input: + ; dehl = number + ; + ; Output: + ; hl = root. + ; +isqrt: + ld a,d + or e + or h + or l + ret z + + exx + ld hl,0 + ld de,0 + exx + ld ix,.bit +.0: + ld a,d + sub (ix+3) + jr nz,.1 + ld a,e + sub (ix+2) + jr nz,.1 + ld a,h + sub (ix+1) + jr nz,.1 + ld a,l + sub (ix+0) +.1: jr z,.2 + jr c,.2 + inc ix + inc ix + inc ix + inc ix + jp .0 + +.2: ld a,ixl + cp .bit+16*4 + jr z,.3 + exx + push de + push hl + ld a,l + add a,(ix+0) + ld l,a + ld a,h + adc a,(ix+1) + ld h,a + ld a,e + adc a,(ix+2) + ld e,a + ld a,d + adc a,(ix+3) + ld d,a + exx + ld a,l + exx + sub l + exx + ld a,h + exx + sbc a,h + exx + ld a,e + exx + sbc a,e + exx + ld a,d + exx + sbc a,d + exx + jp c,.5 + ld a,l + exx + sub l + exx + ld l,a + ld a,h + exx + sbc a,h + exx + ld h,a + ld a,e + exx + sbc a,e + exx + ld e,a + ld a,d + exx + sbc a,d + pop hl + pop de + exx + ld d,a + + exx + srl d + rr e + rr h + rr l + ld a,l + add a,(ix+0) + ld l,a + ld a,h + adc a,(ix+1) + ld h,a + ld a,e + adc a,(ix+2) + ld e,a + ld a,d + adc a,(ix+3) + ld d,a + exx + jp .4 + +.5: + exx + pop hl + pop de + srl d + rr e + rr h + rr l + exx +.4: + inc ix + inc ix + inc ix + inc ix + jp .2 +.3: + exx + ret + +.bit: + dw $0000,$4000 + dw $0000,$1000 + dw $0000,$0400 + dw $0000,$0100 + dw $0000,$0040 + dw $0000,$0010 + dw $0000,$0004 + dw $0000,$0001 + dw $4000,$0000 + dw $1000,$0000 + dw $0400,$0000 + dw $0100,$0000 + dw $0040,$0000 + dw $0010,$0000 + dw $0004,$0000 + dw $0001,$0000 + diff --git a/others/test_sqrt.bas b/others/test_sqrt.bas new file mode 100644 index 0000000..e115f21 --- /dev/null +++ b/others/test_sqrt.bas @@ -0,0 +1,20 @@ + ' + ' Test Z80 integer square root + ' + ' by Oscar Toledo G. + ' + ' Creation date: Apr/07/2026. + ' + + PRINT AT 33, USR sqrt(16384) + PRINT AT 65, USR sqrt(10000) + PRINT AT 97, USR sqrt(100) + + WHILE 1: WEND + +ASM SQRT: +ASM LD DE,0 +ASM CALL isqrt +ASM RET + + ASM INCLUDE "sqrt.asm" From 31a059c4ae17d257f626ab570b890fc626a64fd4 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 30 May 2026 10:09:38 -0600 Subject: [PATCH 139/155] Added links to CVAddict's Toolkit and Amy's CVPaint Studio --- README.md | 11 ++++++++++- cvbasic_prologue.asm | 14 +++++++------- manual.txt | 8 ++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a35d603..e8c005a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CVBasic compiler v0.9.1 +# CVBasic compiler v0.9.2 *(c) Copyright 2024-2026 Óscar Toledo Gutiérrez* *https://nanochess.org/* @@ -339,6 +339,15 @@ All the games in the book will compile for **all** the platforms, except Sega Ma * [Programming Games for Colecovision, PDF ebook, 250 pages](https://nanochess.org/store.html) +### Toolkits + +Several utilities which can be used with CVBasic have emerged for graphics design, music, and sound effects. + +* Amy's CVPaint Studio [https://amypurple.github.io/AmysCVPaintStudio/](https://amypurple.github.io/AmysCVPaintStudio/) + +* Kamshaft's CV Toolkit, including Sprite Tool, Tile Creator, Sound Creator, and Music Tracker [https://cvaddict.com/tools/](https://cvaddict.com/tools/) + + ### Acknowledgments Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, Atarius Maximus, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, Revontuli, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 64d7e37..81f1251 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1378,7 +1378,7 @@ define_sprite_color: add hl,hl ; x2 add hl,hl ; x4 add hl,hl ; x8 - ld h,$40/2 + ld h,$f8/2 add hl,hl ; x16 ex de,hl di @@ -1425,13 +1425,13 @@ mode_4: call vdp_generic_mode ld bc,$000a ; Reg. 10 (high bits of color table) call WRTVDP - ; The value $84 seems logical but it makes colors + ; The value $f4 seems logical but it makes colors ; for sprites 0-7 replicate in sprites 8-15, ; 16-23, and 24-31. Not described in Yamaha docs, ; but emulated by OpenMSX and BlueMSX. - ld bc,$8705 ; $4200 for sprite attribute table... - call WRTVDP ; ...so sprite colors appear at $4000-$41ff. - ld bc,$000b ; Reg. 11 (high bits of sprite attribute table) + ld bc,$f705 ; $fa00 for sprite attribute table... + call WRTVDP ; ...so sprite colors appear at $f800-$f9ff. + ld bc,$010b ; Reg. 11 (high bits of sprite attribute table) call WRTVDP ld hl,($0004) inc h @@ -1586,7 +1586,7 @@ vdp_generic_sprites: ld hl,$1b00 ld a,$d1 jr z,$+6 - ld h,$42 + ld h,$fa ld a,$e0 ld bc,$0080 call FILVRM @@ -1808,7 +1808,7 @@ nmi_handler: ld hl,$1b00 jr z,$+4 .10: - ld h,$42 + ld h,$fa call SETWRT ld hl,sprites .7: diff --git a/manual.txt b/manual.txt index bb19147..9aeb8c8 100644 --- a/manual.txt +++ b/manual.txt @@ -1688,7 +1688,15 @@ CoolCV emulator https://forums.atariage.com/topic/240800-coolcv-emulator-for-mac-os-x-linux-windows-and-raspberry/ +Amy's CVPaint Studio + + https://amypurple.github.io/AmysCVPaintStudio/ + +Kamshaft's CV Toolkit, including Sprite Tool, Tile Creator, Sound Creator, and Music Tracker + + https://cvaddict.com/tools/ + >>>>>>>>>>>>>> Acknowledgments Thanks to following members of Atariage for contributing valuable suggestions: From 3cf35fb1d5ced8dcc4e1c6e18bee4555e68b631c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 6 Jun 2026 14:01:57 -0600 Subject: [PATCH 140/155] Added support for PALETTE in --msx mode. --- cvbasic.c | 22 ++- cvbasic_epilogue.asm | 325 ++++++++++++++++++++++--------------------- cvbasic_prologue.asm | 159 +++++++++++++++------ manual.txt | 6 +- 4 files changed, 306 insertions(+), 206 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 0c43e38..76cca25 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5056,8 +5056,8 @@ void compile_statement(int check_for_else) struct node *source; get_lex(); - if (machine != SMS && machine != NES && machine != MSX2) - emit_error("PALETTE is only available on SMS/NES/Famicom/MSX2"); + if (machine != SMS && machine != NES && machine != MSX && machine != MSX2) + emit_error("PALETTE is only available on SMS/NES/Famicom/MSX/MSX2"); if (lex == C_NAME && strcmp(name, "LOAD") == 0) { get_lex(); if (lex != C_NAME) { @@ -5067,7 +5067,7 @@ void compile_statement(int check_for_else) node_generate(source, 0); node_delete(source); } else { - if (machine == SMS || machine == MSX2) { + if (machine == SMS || machine == MSX2 || machine == MSX) { strcpy(temp, LABEL_PREFIX); strcat(temp, name); cpuz80_2op("LD", "HL", temp); @@ -5092,7 +5092,7 @@ void compile_statement(int check_for_else) } } else if (lex == C_NAME && strcmp(name, "DEFAULT") == 0) { get_lex(); - if (machine != MSX2 && machine != SMS) + if (machine != MSX2 && machine != SMS && machine != MSX) emit_error("PALETTE DEFAULT is only available in MSX2/SMS"); generic_call("palette_default"); } else { @@ -5107,10 +5107,15 @@ void compile_statement(int check_for_else) cpu6502_1op("STA", "PPUBUF,X"); cpu6502_1op("LDA", "#$7f"); cpu6502_1op("STA", "PPUBUF+1,X"); - } else if (machine == MSX2) { + } else if (machine == MSX2 || machine == MSX) { generic_interrupt_disable(); cpuz80_2op("LD", "B", "A"); cpuz80_2op("LD", "C", "$10"); + if (machine == MSX) { + cpuz80_2op("LD", "A", "($002d)"); + cpuz80_1op("OR", "A"); /* Detect MSX1 and jump to avoid */ + cpuz80_2op("JR", "Z", "$+5"); + } cpuz80_1op("CALL", "WRTVDP"); } if (lex != C_COMMA) @@ -5128,7 +5133,12 @@ void compile_statement(int check_for_else) cpu6502_noop("INX"); cpu6502_noop("INX"); cpu6502_1op("STX", "ppu_pointer"); - } else if (machine == MSX2) { + } else if (machine == MSX2 || machine == MSX) { + if (machine == MSX) { + cpuz80_2op("LD", "A", "($002d)"); + cpuz80_1op("OR", "A"); /* Detect MSX1 and jump to avoid */ + cpuz80_2op("JR", "Z", "$+8"); + } cpuz80_2op("LD", "A", "L"); cpuz80_2op("OUT", "(VDP+2)", "A"); cpuz80_2op("LD", "A", "H"); diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 51b5c79..90ac8cc 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -195,47 +195,47 @@ cartridge_rom_switch: FORG $01FD00 ORG $7D00 - ; - ; Detect FM (OPLL) - ; -sms_detect_fm: - ld a,($c000) - or $04 - out ($3e),a - ld bc,$0700 -.1: ld a,b - and $01 - out ($f2),a - ld e,a - in a,($f2) - and $07 - cp e - jr nz,.2 - inc c -.2: djnz .1 - ld a,c - cp $07 - jr z,.3 - xor a -.3: and 1 - out ($f2),a + ; + ; Detect FM (OPLL) + ; +sms_detect_fm: + ld a,($c000) + or $04 + out ($3e),a + ld bc,$0700 +.1: ld a,b + and $01 + out ($f2),a + ld e,a + in a,($f2) + and $07 + cp e + jr nz,.2 + inc c +.2: djnz .1 + ld a,c + cp $07 + jr z,.3 + xor a +.3: and 1 + out ($f2),a ld (fm_enabled),a - dec a ; For compatibility. - ld (fm_slot),a - ld a,($c000) - out ($3e),a - ret - + dec a ; For compatibility. + ld (fm_slot),a + ld a,($c000) + out ($3e),a + ret + ; Write a FM register ; A = register ; E = data write_fm: - out ($f0),a - ld a,e - out ($f1),a - ex (sp),hl - ex (sp),hl - ret + out ($f0),a + ld a,e + out ($f1),a + ex (sp),hl + ex (sp),hl + ret fm_rom_switch: di @@ -254,122 +254,122 @@ cartridge_rom_switch: ; This code cannot be in the area $4000-$7fff ; - ; + ; ; Play music for FM - ; -music_generate_fm: + ; +music_generate_fm: ; Fragments of code in caller. - -.0: ld a,(music_timing) - and $3f ; Restarts note time. - ld (music_note_counter),a + +.0: ld a,(music_timing) + and $3f ; Restarts note time. + ld (music_note_counter),a push hl push bc - push de + push de call fm_rom_switch pop de - pop bc - ld a,b - cp $3f ; Sustain? - jr z,.1 - ld a,$10 - call play_fm -.1: ld a,c ; Read second voice. - cp $3f ; Sustain? - jr z,.2 - ld b,a - ld a,$11 - call play_fm -.2: ld a,d ; Read third voice. - cp $3f ; Sustain? - jr z,.3 - ld b,a - ld a,$12 - call play_fm + pop bc + ld a,b + cp $3f ; Sustain? + jr z,.1 + ld a,$10 + call play_fm +.1: ld a,c ; Read second voice. + cp $3f ; Sustain? + jr z,.2 + ld b,a + ld a,$11 + call play_fm +.2: ld a,d ; Read third voice. + cp $3f ; Sustain? + jr z,.3 + ld b,a + ld a,$12 + call play_fm .3: push de call cartridge_rom_switch - pop de - pop hl - ld a,e ; Read effect. - ld (music_drum),a - xor a - ld (music_counter_4),a - inc hl - inc hl - inc hl - ld a,(music_timing) - and $c0 - jr nz,.14 - inc hl -.14: ld (music_pointer),hl - ; - ; Build extras - ; -.6: ld a,(music_drum) ; Read effect. - or a ; Effect happening? - jr z,.7 ; No, jump. - call fm_rom_switch - ld a,(music_drum) ; Read effect. - dec a ; 1 - Long drum. - jr nz,.5 - ld a,(music_counter_4) - or a - ld de,$0e28 - jr z,.9 - cp 3 - ld de,$0e20 - jr z,.9 - jr .4 - -.5: dec a ; 2 - Short drum. - jr nz,.11 - ld a,(music_counter_4) - or a - ld e,$21 - jr z,.9 - cp 3 - ld e,$20 - jr nz,.4 -.9: ld a,$0e - call write_fm - jr .4 - -.12: cp 2 - jr nz,.9 - ld e,$20 - ld a,$0e - call write_fm - ld e,$28 - jr .9 - -.11: ;dec a ; 3 - Roll. - ;jp nz,.4 - ld a,(music_timing) - and $3e - rrca - ld b,a - ld a,(music_counter_4) - ld e,$28 - or a - jr z,.9 - cp b - jr z,.12 - ld e,$20 - cp 2 - jr z,.9 - dec a - dec a - cp b - jr z,.9 -.4: call cartridge_rom_switch -.7: - ; Increment time for drum. - ld hl,music_counter_4 - inc (hl) - ld hl,music_note_counter - dec (hl) - ret - + pop de + pop hl + ld a,e ; Read effect. + ld (music_drum),a + xor a + ld (music_counter_4),a + inc hl + inc hl + inc hl + ld a,(music_timing) + and $c0 + jr nz,.14 + inc hl +.14: ld (music_pointer),hl + ; + ; Build extras + ; +.6: ld a,(music_drum) ; Read effect. + or a ; Effect happening? + jr z,.7 ; No, jump. + call fm_rom_switch + ld a,(music_drum) ; Read effect. + dec a ; 1 - Long drum. + jr nz,.5 + ld a,(music_counter_4) + or a + ld de,$0e28 + jr z,.9 + cp 3 + ld de,$0e20 + jr z,.9 + jr .4 + +.5: dec a ; 2 - Short drum. + jr nz,.11 + ld a,(music_counter_4) + or a + ld e,$21 + jr z,.9 + cp 3 + ld e,$20 + jr nz,.4 +.9: ld a,$0e + call write_fm + jr .4 + +.12: cp 2 + jr nz,.9 + ld e,$20 + ld a,$0e + call write_fm + ld e,$28 + jr .9 + +.11: ;dec a ; 3 - Roll. + ;jp nz,.4 + ld a,(music_timing) + and $3e + rrca + ld b,a + ld a,(music_counter_4) + ld e,$28 + or a + jr z,.9 + cp b + jr z,.12 + ld e,$20 + cp 2 + jr z,.9 + dec a + dec a + cp b + jr z,.9 +.4: call cartridge_rom_switch +.7: + ; Increment time for drum. + ld hl,music_counter_4 + inc (hl) + ld hl,music_note_counter + dec (hl) + ret + ; ; Play note in FM ; A = Voice ($10 - $11 - $12) @@ -419,19 +419,19 @@ play_fm: pop bc inc hl ld e,(hl) ; Get high byte (octave). - ld a,b - cpl - and $c0 ; Is it bass? - jr nz,.1 ; No, jump. - ld a,e - sub 2 ; Lower octave. - ld e,a -.1: ld a,b - and $c0 - cp $40 ; Is it clarinet? - jr nz,$+4 ; No, jump. - inc e ; Higher octave. - inc e + ld a,b + cpl + and $c0 ; Is it bass? + jr nz,.1 ; No, jump. + ld a,e + sub 2 ; Lower octave. + ld e,a +.1: ld a,b + and $c0 + cp $40 ; Is it clarinet? + jr nz,$+4 ; No, jump. + inc e ; Higher octave. + inc e ld a,c add a,$10 call write_fm @@ -579,6 +579,17 @@ mode: ; bit 2: No sprite flicker. ; bit 3: Single charset mode. ; bit 4: MSX2 sprites. + ; bit 5: MSX2 extended modes (MODE 5-8) + if MSX&2 +cls_size: + rb 2 ; Screen length for CLS +msx2_mode: + rb 1 ; Type of color for mode. +msx2_fg_color: + rb 1 ; Current foreground color. +msx2_bk_color: + rb 1 ; Current background color. + endif flicker: rb 1 joy1_data: diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 81f1251..e7ab126 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -46,6 +46,8 @@ ; access. ; Revision date: Feb/26/2026. Faster CPYBLK, LDIRVM3, and FILVRM. ; Revision date: Mar/09/2026. Corrections on joystick read for MSX. + ; Revision date: May/30/2026. Modified CLS and DEFINE SPRITE for MSX2 + ; extended video modes. ; ; @@ -370,22 +372,22 @@ LDIRMV: ret LDIRVM: - EX DE,HL - CALL SETWRT - EX DE,HL - DEC BC - INC C - LD A,B - LD B,C + EX DE,HL + CALL SETWRT + EX DE,HL + DEC BC + INC C + LD A,B + LD B,C INC A - LD C,A + LD C,A .1: LD A,(HL) ; 7 8 LD (VDP),A ; 13 14 INC HL ; 6 7 - DJNZ .1 ; 13 14 - DEC C ; 4 5 - JP NZ,.1 ; 10 11 + DJNZ .1 ; 13 14 + DEC C ; 4 5 + JP NZ,.1 ; 10 11 RET else ; Normal platforms with VDP connected via ports (IORQ) @@ -527,15 +529,15 @@ LDIRMV: ret LDIRVM: - ex de,hl - call SETWRT - ex de,hl - dec bc - inc c - ld a,b - ld b,c - inc a - ld c,VDP + ex de,hl + call SETWRT + ex de,hl + dec bc + inc c + ld a,b + ld b,c + inc a + ld c,VDP .1: if MSX&2 otir ; 23 cycles per byte. @@ -547,11 +549,11 @@ LDIRVM: nop ; SG1000 is 3.58 mhz, but SC3000 is 4 mhz. nop endif - outi ; 18 + outi ; 18 jp nz,.1 ; 11 - endif - dec a - jp nz,.1 + endif + dec a + jp nz,.1 ret endif @@ -571,6 +573,22 @@ LDIRVM3: ret endif + ; Fill big buffers in 256-byte increments to avoid music pauses. +FILVRM2: + push af + push bc + push hl + call nmi_off + call FILVRM + call nmi_on + pop hl + pop bc + pop af + inc h + dec b + jp nz,FILVRM2 + ret + DISSCR: call nmi_off ld bc,$a201 @@ -668,6 +686,43 @@ cls: ei ret else + if MSX&2 + ld a,(mode) + and $20 + jr z,.2 + ld hl,$0000 + ld (cursor),hl + ld bc,(cls_size) + ld a,(msx2_mode) + cp 2 + jp z,FILVRM2 + dec a + ld a,(msx2_bk_color) + jp z,.3 + ; Extend 4-bit color to 8-bit. + ld b,a + rlca + rlca + rlca + rlca + or b + jp FILVRM2 + ; Extend 2-bit color to 8-bit. +.3: + and $03 + ld b,a + rlca + rlca + or b + ld b,a + rlca + rlca + rlca + rlca + or b + ret +.2: + endif ld hl,$1800 ld (cursor),hl ld bc,$0300 @@ -786,6 +841,7 @@ print_char: pop hl ret + ; Support routine for DEFINE CHAR. define_char: ex de,hl ld l,a @@ -827,6 +883,7 @@ define_char: jp nmi_on endif + ; Support routine for DEFINE COLOR. define_color: if SMS ret @@ -852,6 +909,7 @@ define_color: jp nmi_on endif + ; Support routine for DEFINE SPRITE. define_sprite: ex de,hl ld l,a @@ -874,7 +932,15 @@ define_sprite: if SMS set 1,h else + if MSX&2 + ld a,(mode) + and $20 ; Extended video modes? + ld h,$07 ; $3800 for MODE 0-4. + jr z,$+4 ; No, jump. + ld h,$1c ; $f000 for MODE 5-8. + else ld h,$07 + endif endif add hl,hl ; x8 add hl,hl ; x16 @@ -1347,10 +1413,13 @@ font_bitmaps: db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f endif - if MSX&2 + if MSX palette_default: ld hl,msx2_default_palette palette_load: + ld a,($002d) + or a + ret z ld bc,$0010 di call WRTVDP @@ -1362,7 +1431,9 @@ palette_load: msx2_default_palette: dw $000,$000,$611,$733,$117,$327,$151,$627 dw $171,$373,$661,$664,$411,$265,$555,$777 + endif + if MSX&2 define_sprite_color: ex de,hl add a,a ; x2 @@ -1420,6 +1491,9 @@ mode_4: ld hl,mode res 3,(hl) set 4,(hl) + if MSX&2 + res 5,(hl) + endif ld bc,$0400 ; Normal mode but with enhanced sprites enabled. ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode @@ -1439,12 +1513,10 @@ mode_4: ld bc,$0300 call LDIRVM3 call nmi_on - call nmi_off ld hl,$2000 ld bc,$1800 ld a,$f0 - call FILVRM - call nmi_on + call FILVRM2 call cls jp vdp_generic_sprites endif @@ -1549,6 +1621,9 @@ mode_0: ld hl,mode res 3,(hl) res 4,(hl) + if MSX&2 + res 5,(hl) + endif ld bc,$0200 ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode @@ -1572,12 +1647,10 @@ mode_0: ld bc,$0300 call LDIRVM3 call nmi_on - call nmi_off ld hl,$2000 ld bc,$1800 ld a,$f0 - call FILVRM - call nmi_on + call FILVRM2 call cls vdp_generic_sprites: call nmi_off @@ -1602,20 +1675,21 @@ mode_1: ld hl,mode res 3,(hl) res 4,(hl) + if MSX&2 + res 5,(hl) + endif ld bc,$0200 ld de,$ff03 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode + call nmi_on ld hl,$0000 ld bc,$1800 xor a - call FILVRM - call nmi_on - call nmi_off + call FILVRM2 ld hl,$2000 ld bc,$1800 ld a,$f0 - call FILVRM - call nmi_on + call FILVRM2 ld hl,$1800 .1: call nmi_off ld b,32 @@ -1633,6 +1707,9 @@ mode_2: ld hl,mode set 3,(hl) res 4,(hl) + if MSX&2 + res 5,(hl) + endif ld bc,$0000 ld de,$8000 ; $2000 for color table, $0000 for bitmaps. call vdp_generic_mode @@ -1656,12 +1733,10 @@ mode_2: ld bc,$0300 call LDIRVM call nmi_on - call nmi_off ld hl,$2000 ld bc,$0020 ld a,$f0 - call FILVRM - call nmi_on + call FILVRM2 call cls jp vdp_generic_sprites endif @@ -3252,10 +3327,10 @@ music_generate: ld a,7 ld ($fffe),a endif - ld a,(music_note_counter) + ld a,(music_note_counter) or a - jp nz,music_generate_fm.6 - ld hl,(music_pointer) + jp nz,music_generate_fm.6 + ld hl,(music_pointer) .fm15: push hl if CVBASIC_BANK_SWITCHING ld a,(music_bank) diff --git a/manual.txt b/manual.txt index 9aeb8c8..a821446 100644 --- a/manual.txt +++ b/manual.txt @@ -27,6 +27,7 @@ v0.9.2 Mar/12/2026 o FM synthesis for MSX, MSX2, and Sega Master System. o Added PLAY INSTRUMENT. o Added PLAY FM. o Added MUSIC.FM_ENABLED and MUSIC.FM_AVAILABLE. + o Allows using PALETTE on MSX games, but only applies on MSX2. o Z80: Optimization in multiple array access in expressions. o Z80: Avoid constant reload. o Z80: Optimization IF with 8-bit AND, and multiplication by 128. @@ -950,7 +951,10 @@ The following statements are available: PALETTE LOAD VARPTR array_data_byte(0) PALETTE DEFAULT - For MSX2: + For MSX/MSX2: + + Using this in --msx mode won't have effects. It is for allowing MSX1 games + to look better in MSX2. Sets a single palette register (0-15) to the color. Color bits are specified in a word as 0000 0GGG 0RRR 0BBB (three bits each for From 5c037feeed12a8c126d2a8a2fd8722881dd13424 Mon Sep 17 00:00:00 2001 From: polluks2 <74630735+polluks2@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:10:29 +0200 Subject: [PATCH 141/155] Fixed tolower --- cvbasic.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 76cca25..017b5ac 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -6835,8 +6835,8 @@ int main(int argc, char *argv[]) ** Extra options. */ extra_ram = 0; - if (argv[c][0] == '-' && tolower(argv[c][1]) == 'r' && tolower(argv[c][2] == 'a') && - tolower(argv[c][3] == 'm') && argv[c][4] == '1' && argv[c][5] == '6' && + if (argv[c][0] == '-' && tolower(argv[c][1]) == 'r' && tolower(argv[c][2]) == 'a' && + tolower(argv[c][3]) == 'm' && argv[c][4] == '1' && argv[c][5] == '6' && argv[c][6] == '\0') { c++; if (machine == MSX || machine == MSX2) { @@ -6847,8 +6847,8 @@ int main(int argc, char *argv[]) } } bank_konami = 0; - if (argv[c][0] == '-' && tolower(argv[c][1]) == 'k' && tolower(argv[c][2] == 'o') && - tolower(argv[c][3] == 'n') && tolower(argv[c][4]) == 'a' && tolower(argv[c][5]) == 'm' && tolower(argv[c][6]) == 'i' && + if (argv[c][0] == '-' && tolower(argv[c][1]) == 'k' && tolower(argv[c][2]) == 'o' && + tolower(argv[c][3]) == 'n' && tolower(argv[c][4]) == 'a' && tolower(argv[c][5]) == 'm' && tolower(argv[c][6]) == 'i' && argv[c][7] == '\0') { c++; if (machine == MSX || machine == MSX2) { @@ -6861,8 +6861,8 @@ int main(int argc, char *argv[]) cpm_option = 0; if (machine == EINSTEIN) cpm_option = 1; /* Forced */ - if (argv[c][0] == '-' && tolower(argv[c][1]) == 'c' && tolower(argv[c][2] == 'p') && - tolower(argv[c][3] == 'm') && argv[c][4] == '\0') { + if (argv[c][0] == '-' && tolower(argv[c][1]) == 'c' && tolower(argv[c][2]) == 'p' && + tolower(argv[c][3]) == 'm' && argv[c][4] == '\0') { c++; if (machine == MEMOTECH || machine == NABU) { cpm_option = 1; @@ -6872,8 +6872,8 @@ int main(int argc, char *argv[]) } } small_rom = 0; - if (argv[c][0] == '-' && tolower(argv[c][1]) == 'r' && tolower(argv[c][2] == 'o') && - tolower(argv[c][3] == 'm') && argv[c][4] == '1' && argv[c][5] == '6' && + if (argv[c][0] == '-' && tolower(argv[c][1]) == 'r' && tolower(argv[c][2]) == 'o' && + tolower(argv[c][3]) == 'm' && argv[c][4] == '1' && argv[c][5] == '6' && argv[c][6] == '\0') { c++; if (machine == CREATIVISION) { From 663e9d252221527f0b9c2f72dad0fbd40b1b7f61 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 14 Jun 2026 15:42:00 -0600 Subject: [PATCH 142/155] Solved bugs in SMS build for FM, and non-detected buttons for 2nd controller --- cvbasic_prologue.asm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index e7ab126..b8eefb5 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -48,6 +48,8 @@ ; Revision date: Mar/09/2026. Corrections on joystick read for MSX. ; Revision date: May/30/2026. Modified CLS and DEFINE SPRITE for MSX2 ; extended video modes. + ; Revision date: Jun/14/2026. Corrected bug in SMS button handling for + ; second controller. ; ; @@ -2190,10 +2192,10 @@ nmi_handler: res 1,a bit 2,l jr nz,$+4 - res 4,a + res 6,a bit 3,l jr nz,$+4 - res 5,a + res 7,a cpl ld (joy2_data),a @@ -4199,9 +4201,11 @@ START: im 1 endif if SMS + if FM_SUPPORT ld a,7 ld ($fffe),a call sms_detect_fm + endif ld a,1 ld ($fffe),a endif From 4b9e6031aebde628e4e4dc84ffd589d1f4aafb4e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 14 Jun 2026 17:03:38 -0600 Subject: [PATCH 143/155] Solved bug in frame rate when using the spinner/roller controller (Colecovision) --- cvbasic.c | 8 ++++-- cvbasic_prologue.asm | 65 +++++++++++++++++++++++-------------------- examples/demo.bas | 1 + examples/demo_nes.bas | 1 + examples/demo_sms.bas | 1 + examples/spinner.bas | 29 +++++++++++++++++-- 6 files changed, 69 insertions(+), 36 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 017b5ac..1620205 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3814,10 +3814,12 @@ void compile_statement(int check_for_else) generic_call("cls"); } else if (strcmp(name, "WAIT") == 0) { get_lex(); - if (machine == SORD || machine == CREATIVISION || machine == NES || machine == EINSTEIN || machine == TI994A) + if (machine == SORD || machine == EINSTEIN || machine == CREATIVISION || machine == NES || machine == TI994A) { generic_call("wait"); - else - cpuz80_noop("HALT"); + } else { + /*cpuz80_noop("HALT");*/ + cpuz80_noop("DB $76+COLECO_SPINNER*$59"); + } } else if (strcmp(name, "OUT") == 0) { struct node *port; struct node *value; diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index b8eefb5..0641008 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -49,7 +49,9 @@ ; Revision date: May/30/2026. Modified CLS and DEFINE SPRITE for MSX2 ; extended video modes. ; Revision date: Jun/14/2026. Corrected bug in SMS button handling for - ; second controller. + ; second controller. Alternate frame wait + ; routine when Colecovision used with + ; spinner. ; ; @@ -103,7 +105,11 @@ JOY2: equ $ff-$22*(SG1000+SMS) dw 0 dw START + if COLECO_SPINNER + jp wait + else jp 0 ; rst $08 + endif jp 0 ; rst $10 jp 0 ; rst $18 jp 0 ; rst $20 @@ -2048,15 +2054,15 @@ nmi_handler: ld a,$07 out ($de),a ld b,$ff - in a,(JOY1) + in a,(JOY1) ; Port $dc ld h,a - in a,(JOY2) + in a,(JOY2) ; Port $de ld l,a in a,($de) - cp 7 - jp nz,.sg1000 + cp 7 ; SC3000 keyboard? + jp nz,.sg1000 ; No, jump. - ld a,$00 + ld a,$00 ; Row 0 out ($de),a in a,($dc) rra @@ -2066,7 +2072,7 @@ nmi_handler: rra ld c,8 jr nc,.sg1 - ld a,$01 + ld a,$01 ; Row 1 out ($de),a in a,($dc) rra @@ -2076,7 +2082,7 @@ nmi_handler: rra ld c,9 jr nc,.sg1 - ld a,$02 + ld a,$02 ; Row 2 out ($de),a in a,($dc) rra @@ -2086,7 +2092,7 @@ nmi_handler: rra ld c,0 jr nc,.sg1 - ld a,$03 + ld a,$03 ; Row 3 out ($de),a in a,($dc) bit 4,a @@ -2095,13 +2101,13 @@ nmi_handler: rra ld c,4 jr nc,.sg1 - ld a,$04 + ld a,$04 ; Row 4 out ($de),a in a,($dc) rra ld c,5 jr nc,.sg1 - ld a,$05 + ld a,$05 ; Row 5 out ($de),a in a,($dc) bit 6,a @@ -2110,7 +2116,7 @@ nmi_handler: rra ld c,6 jr nc,.sg1 - ld a,$06 + ld a,$06 ; Row 6 out ($de),a in a,($dc) rra @@ -2154,22 +2160,22 @@ nmi_handler: jr nz,$+4 res 5,h .sg1000: - bit 0,h + bit 0,h ; Port A - Up jr nz,$+4 res 0,b - bit 1,h + bit 1,h ; Port A - Down jr nz,$+4 res 2,b - bit 2,h + bit 2,h ; Port A - Left jr nz,$+4 res 3,b - bit 3,h + bit 3,h ; Port A - Right jr nz,$+4 res 1,b - bit 4,h + bit 4,h ; Port A - TL jr nz,$+4 res 6,b - bit 5,h + bit 5,h ; Port A - TR jr nz,$+4 res 7,b ld a,b @@ -2177,23 +2183,23 @@ nmi_handler: ld (joy1_data),a ld a,$ff - bit 6,h + bit 6,h ; Port B - Up jr nz,$+4 res 0,a - bit 7,h + bit 7,h ; Port B - Down jr nz,$+4 res 2,a - bit 0,l + bit 0,l ; Port B - Left jr nz,$+4 res 3,a - bit 1,l + bit 1,l ; Port B - Right jr nz,$+4 res 1,a - bit 2,l + bit 2,l ; Port B - TL jr nz,$+4 res 6,a - bit 3,l + bit 3,l ; Port B - TR jr nz,$+4 res 7,a cpl @@ -3139,13 +3145,13 @@ keyboard_handler: ei reti endif - if SORD + if SORD+(COLECO&COLECO_SPINNER) wait: - ld de,(frame) + ld a,(frame) + ld d,a .1: - ld hl,(frame) - or a - sbc hl,de + ld a,(frame) + cp d jr z,.1 ret endif @@ -3159,7 +3165,6 @@ wait: ld (vdp_status),a jp nmi_handler endif - ; ; The music player code comes from my ; game Princess Quest for Colecovision (2012) diff --git a/examples/demo.bas b/examples/demo.bas index 127efb7..c3f96f1 100644 --- a/examples/demo.bas +++ b/examples/demo.bas @@ -2,6 +2,7 @@ ' Demo of graphics for CVBasic ' ' by Oscar Toledo G. + ' https://nanochess.org/ ' ' Creation date: Mar/08/2024. ' Revision date: Aug/06/2024. Added endless loop. diff --git a/examples/demo_nes.bas b/examples/demo_nes.bas index 565b4b9..7e61325 100644 --- a/examples/demo_nes.bas +++ b/examples/demo_nes.bas @@ -2,6 +2,7 @@ ' Demo of graphics for CVBasic ' ' by Oscar Toledo G. + ' https://nanochess.org/ ' ' Creation date: Mar/08/2024. ' Revision date: Aug/06/2024. Added endless loop. diff --git a/examples/demo_sms.bas b/examples/demo_sms.bas index 65c686c..2461634 100644 --- a/examples/demo_sms.bas +++ b/examples/demo_sms.bas @@ -2,6 +2,7 @@ ' Demo of graphics for CVBasic ' ' by Oscar Toledo G. + ' https://nanochess.org/ ' ' Creation date: Mar/08/2024. ' Revision date: Aug/06/2024. Added endless loop. diff --git a/examples/spinner.bas b/examples/spinner.bas index b594178..2a080ab 100644 --- a/examples/spinner.bas +++ b/examples/spinner.bas @@ -12,16 +12,39 @@ PRINT AT 36,"Happy face!" + PRINT AT 98,"CONT1.SPINNER max.per frame" + + PRINT AT 162,"CONT2.SPINNER max.per frame" + x = 120 y = 88 + + max_x = 0 + max_y = 0 + + counter = 0 game_loop: WAIT - WAIT + IF counter = 60 THEN + counter = 0 + PRINT AT 130,<3>max_x + PRINT AT 194,<3>max_y + END IF + + counter = counter + 1 + + #dx = CONT1.SPINNER + #dy = CONT2.SPINNER + mx = ABS(#dx) + my = ABS(#dy) + IF mx > max_x THEN max_x = mx + IF my > max_y THEN max_y = my + SPRITE 0, y - 1, x, 0, 10 - x = x + CONT1.SPINNER - y = y - CONT2.SPINNER + x = x + #dx + y = y - #dy GOTO game_loop From 748e2167fe08533212c952d4d7e51a3498d68d76 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 14 Jun 2026 17:08:05 -0600 Subject: [PATCH 144/155] Adjusted WAIT statement --- cvbasic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 1620205..7aee149 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -3816,9 +3816,10 @@ void compile_statement(int check_for_else) get_lex(); if (machine == SORD || machine == EINSTEIN || machine == CREATIVISION || machine == NES || machine == TI994A) { generic_call("wait"); + } else if (machine == COLECOVISION || machine == COLECOVISION_SGM) { + cpuz80_noop("DB $76+COLECO_SPINNER*$59"); /* HALT or RST $08 */ } else { - /*cpuz80_noop("HALT");*/ - cpuz80_noop("DB $76+COLECO_SPINNER*$59"); + cpuz80_noop("HALT"); } } else if (strcmp(name, "OUT") == 0) { struct node *port; From e73f3bbb056c86acabe005549f8a0a346b1deff6 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sat, 20 Jun 2026 22:41:18 -0600 Subject: [PATCH 145/155] Added VGM player for NES --- examples/vgm_nes.bas | 92 ++++++++++++++++++++++++++++++++++++++++++++ manual.txt | 36 ++++++++++------- 2 files changed, 114 insertions(+), 14 deletions(-) create mode 100644 examples/vgm_nes.bas diff --git a/examples/vgm_nes.bas b/examples/vgm_nes.bas new file mode 100644 index 0000000..2d3479b --- /dev/null +++ b/examples/vgm_nes.bas @@ -0,0 +1,92 @@ + ' + ' Mini VGM player for CVBasic + ' + ' This handles only NES APU VGM files + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Jun/20/2026. + ' + + ON FRAME GOSUB vgm_play + + PRINT AT 33,"VGM playing..." + + ' + ' Start playing a VGM song. + ' + #vgm_song = VARPTR vgm_music(0) + GOSUB vgm_start + + ' + ' Does nothing except to show the current playing pointer. + ' + WHILE 1 + WAIT + PRINT AT 65,#vgm_pointer," " + WEND + + ' + ' Start playing a VGM song. + ' Input: #vgm_song = pointer to song. + ' +vgm_start: PROCEDURE + #vgm_end = #vgm_song + (PEEK(#vgm_song + 4) + (PEEK(#vgm_song + 5) * 256)) + IF PEEK(#vgm_song + 8) < $50 THEN + #vgm_pointer = #vgm_song + 64 + ELSE + #vgm_pointer = #vgm_song + $34 + (PEEK(#vgm_song + 52) + (PEEK(#vgm_song + 53) * 256)) + END IF + + END + + ' + ' This routine is called on each video frame to play the next audio data. + ' +vgm_play: PROCEDURE + IF #vgm_pointer = 0 THEN RETURN + + IF #vgm_pointer >= #vgm_end THEN #vgm_pointer = 0: RETURN + + WHILE 1 + vgm_byte = PEEK(#vgm_pointer) + #vgm_pointer = #vgm_pointer + 1 + IF vgm_byte = $b4 THEN + vgm_reg = PEEK(#vgm_pointer) + #vgm_pointer = #vgm_pointer + 1 + IF vgm_reg >= $20 AND vgm_reg <= $3E THEN vgm_reg = vgm_reg + $60 + IF vgm_reg = $3f THEN vgm_reg = $23 + POKE $4000 + vgm_reg, PEEK(#vgm_pointer) + #vgm_pointer = #vgm_pointer + 1 + ' ELSEIF vgm_byte = $a0 THEN + ' #vgm_pointer = #vgm_pointer + 2 ' Ignore YM2149 (AY-3-8910) + ' ELSEIF vgm_byte = $51 THEN + ' #vgm_pointer = #vgm_pointer + 2 ' Ignore YM2413 (VRC7) + ELSEIF vgm_byte = $61 THEN + #vgm_pointer = #vgm_pointer + 2 + EXIT WHILE + ELSEIF vgm_byte = $62 THEN + EXIT WHILE + ELSEIF vgm_byte = $63 THEN + EXIT WHILE + ELSEIF vgm_byte = $66 THEN + #vgm_pointer = 0 + POKE $4000,0 + POKE $4004,0 + POKE $4008,0 + POKE $400C,0 + EXIT WHILE + END IF + WEND + END + + ' + ' You can download VGM music from: + ' https://vgmrips.net/packs/chip/nes-apu + ' + ' You need to decompress the file, and inside each file is compressed with gzip, + ' so you need to decompress again each file. + ' +vgm_music: + ASM INCBIN "stage.vgm" diff --git a/manual.txt b/manual.txt index a821446..573563a 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Mar/12/2026 +Last revision: Jun/14/2026 >>>>>>>>>>>>>> Legal notice @@ -22,18 +22,25 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.2 Mar/12/2026 o FM synthesis for MSX, MSX2, and Sega Master System. +v0.9.2 Jun/14/2026 o FM synthesis for MSX, MSX2, and Sega Master System. o Added OPTION FM. o Added PLAY INSTRUMENT. o Added PLAY FM. o Added MUSIC.FM_ENABLED and MUSIC.FM_AVAILABLE. - o Allows using PALETTE on MSX games, but only applies on MSX2. - o Z80: Optimization in multiple array access in expressions. + o Allows using PALETTE on MSX games, but only applies + on MSX2. + o Z80: Optimization in multiple array access in + expressions. o Z80: Avoid constant reload. - o Z80: Optimization IF with 8-bit AND, and multiplication by 128. + o Z80: Optimization IF with 8-bit AND, and + multiplication by 128. o Z80: Speed up of block copy to screen and VRAM fill. - o Z80: Optimized 16-bit multiplication (before always 1277 cycles, - now minimum of 191 cycles and maximum 1244 cycles) + o Z80: Optimized 16-bit multiplication (before always + 1277 cycles, now minimum of 191 cycles and maximum + 1244 cycles) + o SMS: Solved bug reading buttons for 2nd controller. + o Colecovision: Solved bug of faster frame rate when + using spinners. v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. @@ -62,20 +69,21 @@ v0.9.0 Aug/26/2025 o Added support for NES/Famicom using --nes o TI-99/4A: Solved bug in SELECT CASE. o TI-99/4A: Solved bug in DEFINE COLOR PLETTER. o TI-99/4A: Optimizes more operations with constants. - o TI-99/4A: Added more optimization using register labeling, - saves many bytes, and speeds up. + o TI-99/4A: Added more optimization using register + labeling, saves many bytes, and speeds up. v0.8.0 Apr/26/2025 o Added support for Sega Master System using --sms o Added support for VDP.STATUS (for reading VDP status) o Added SELECT CASE / END SELECT - o Added support for CHR$ in PRINT (for portable printing of - arbitrary characters in the current cursor position) + o Added support for CHR$ in PRINT (for portable printing + of arbitrary characters in the current cursor position) o Added SCROLL statement for Sega Master System. o Added BORDER flags for Sega Master System. o Added PALETTE statement for Sega Master System. - o Adapted BITMAP, SCREEN, and SPRITE for Sega Master System. - o Optimizes code using directly DI/EI instructions in Z80 - platforms if possible. + o Adapted BITMAP, SCREEN, and SPRITE for Sega Master + System. + o Optimizes code using directly DI/EI instructions in + Z80 platforms if possible. v0.7.1 Oct/15/2024 o Added support for NABU PC using --nabu (with -cpm option) o Added support for USR/CALL with up to 5 arguments (only Z80) From b07fa0fb7f6df394cb42c22538546518b4c2dd26 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Sun, 21 Jun 2026 15:28:08 -0600 Subject: [PATCH 146/155] Added note about NES VGM player --- README.md | 1 + manual.txt | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e8c005a..0d5bcd6 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ The following files compose the compiler: examples/varptr_sms.bas VARPTR example for redefining graphics (Sega Master System) examples/vgm.bas VGM audio player for SN76489. examples/vgm_ay.bas VGM audio player for AY-3-8910. + examples/vgm_nes.bas VGM audio player for NES/Famicom. examples/viboritas.bas Game example. examples/viboritas_msx2.bas Game example (MSX2) examples/viboritas_nes.bas Game example (NES/Famicom) diff --git a/manual.txt b/manual.txt index 573563a..1925679 100644 --- a/manual.txt +++ b/manual.txt @@ -5,7 +5,7 @@ http://nanochess.org/ First developed: Feb/27/2024 -Last revision: Jun/14/2026 +Last revision: Jun/20/2026 >>>>>>>>>>>>>> Legal notice @@ -22,7 +22,7 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.2 Jun/14/2026 o FM synthesis for MSX, MSX2, and Sega Master System. +v0.9.2 Jun/20/2026 o FM synthesis for MSX, MSX2, and Sega Master System. o Added OPTION FM. o Added PLAY INSTRUMENT. o Added PLAY FM. @@ -41,6 +41,7 @@ v0.9.2 Jun/14/2026 o FM synthesis for MSX, MSX2, and Sega Master System. o SMS: Solved bug reading buttons for 2nd controller. o Colecovision: Solved bug of faster frame rate when using spinners. + o Added example vgm_nes.bas v0.9.1 Feb/17/2026 o Added support for MSX2 using --msx2 o MSX2: It supports the PALETTE statement. From 246f6e43570c6427dd934bee8c4077c5f03761d4 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 22 Jun 2026 15:20:04 -0600 Subject: [PATCH 147/155] Added links to more games made with CVBasic --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d5bcd6..5d0a6fa 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,10 @@ There are some very good examples of games developed with CVBasic. * Airlock II game by OriginalJohn. Demo available from [https://forums.atariage.com/topic/379104-cvbasic-airlock-ii-in-progress/](https://forums.atariage.com/topic/379104-cvbasic-airlock-ii-in-progress/) +* astronave by Haranni. Demo available from [https://forums.atariage.com/topic/381647-astronave/](https://forums.atariage.com/topic/381647-astronave/) + +* Barbarricade by Jess Ragan. Demo available from [https://forums.atariage.com/topic/390220-barbarricade-the-brick-breaking-game-where-the-bricks-break-you/](https://forums.atariage.com/topic/390220-barbarricade-the-brick-breaking-game-where-the-bricks-break-you/) + * Beachhead by Eric Damain. Demo screenshots [https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/](https://forums.atariage.com/topic/373822-beach-head-dev-log-cvbasic/) * Boom by Atarius Maximus for NES/Famicom. Also in the _contrib_ directory. [https://forums.atariage.com/topic/384096-colecovision-fantalicious-basic-compiler-cvbasic-v090-now-with-nesfamicom-support/page/2/#findComment-5769427](https://forums.atariage.com/topic/384096-colecovision-fantalicious-basic-compiler-cvbasic-v090-now-with-nesfamicom-support/page/2/#findComment-5769427) @@ -299,6 +303,8 @@ There are some very good examples of games developed with CVBasic. * Hamurabi by Eric Damain. Available from [https://forums.atariage.com/topic/380392-hamurabi-dev-log-cvbasic/](https://forums.atariage.com/topic/380392-hamurabi-dev-log-cvbasic/) +* Jewels by DannyVdH. Available from [https://forums.atariage.com/topic/390921-jewels-game-build-in-adam-emulator-plugin-tools-cvbasic-new-graphics-editor/](https://forums.atariage.com/topic/390921-jewels-game-build-in-adam-emulator-plugin-tools-cvbasic-new-graphics-editor/) + * Jurl by Tonsomo Entertainment. Available from [https://tonsomo.itch.io/jurl-colecovision-edition](https://tonsomo.itch.io/jurl-colecovision-edition) * Manhole by Eric Damain. Available from [https://electric-dreams.itch.io/manhole-for-colecovision](https://electric-dreams.itch.io/manhole-for-colecovision) @@ -307,6 +313,8 @@ There are some very good examples of games developed with CVBasic. * Monkey Moon by nanochess, example from the book **Programming Games for Colecovision**. Available from [https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249](https://forums.atariage.com/topic/365456-the-mystery-of-monkey-moon/#findComment-5478249) +* Oil Panic by Eric Damain. Availabel from [https://forums.atariage.com/topic/390270-another-gw-adaptation-oil-panic/](https://forums.atariage.com/topic/390270-another-gw-adaptation-oil-panic/) + * Operation Hibernation by Jess Ragan. Available from [https://forums.atariage.com/topic/383365-operation-hibernation-nearing-completion/](https://forums.atariage.com/topic/383365-operation-hibernation-nearing-completion/) * Pipe Dreams by visrealm. Available from [https://forums.atariage.com/topic/382747-pipe-dreams-clone-for-the-colecovision-and-others-cvbasic/](https://forums.atariage.com/topic/382747-pipe-dreams-clone-for-the-colecovision-and-others-cvbasic/) @@ -315,11 +323,15 @@ There are some very good examples of games developed with CVBasic. * Solar Fox 2 by Jess Ragan. Available from [https://forums.atariage.com/topic/382881-solar-fox-2-is-finished-link-inside/](https://forums.atariage.com/topic/382881-solar-fox-2-is-finished-link-inside/) +* Space Taxi by Eric Damain. Available from [https://forums.atariage.com/topic/388538-hey-taxi/](https://forums.atariage.com/topic/388538-hey-taxi/) + * Sub Hunt by Eric Damain. Demo videos [https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/](https://forums.atariage.com/topic/374259-sub-hunt-dev-log-cvbasic/) * SWOPEM by chalkyw64 (MSX). Available from [https://forums.atariage.com/topic/387521-swopem-a-simple-match3-game-for-msx-and-colecovision/](https://forums.atariage.com/topic/387521-swopem-a-simple-match3-game-for-msx-and-colecovision/) -* Taz by Eric Damain. Demo available from [https://forums.atariage.com/topic/388119-crackpots/](https://forums.atariage.com/topic/388119-crackpots/) +* Taz by Eric Damain. Demo available from [https://electric-dreams.itch.io/taz](https://electric-dreams.itch.io/taz) + +* Warren Cave by Eric Damain. Demo available from [https://forums.atariage.com/topic/389458-a-text-adventure-game-test-cvbasic/](https://forums.atariage.com/topic/389458-a-text-adventure-game-test-cvbasic/) * Whack'em Smack'em Byron by Jess Ragan. Available from [https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961](https://forums.atariage.com/topic/364885-whack-em-smack-em-byron-dev-log/page/3/#findComment-5483961) From 029378efd726061d54de8b6e2c6138ab3794fc04 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 22 Jun 2026 16:59:53 -0600 Subject: [PATCH 148/155] Updated game list --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5d0a6fa..be49b5b 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,8 @@ There are some very good examples of games developed with CVBasic. * Airlock II game by OriginalJohn. Demo available from [https://forums.atariage.com/topic/379104-cvbasic-airlock-ii-in-progress/](https://forums.atariage.com/topic/379104-cvbasic-airlock-ii-in-progress/) +* Akalabeth by nanochess. Video available at [https://www.youtube.com/watch?v=Shry64lalDU](https://www.youtube.com/watch?v=Shry64lalDU) + * astronave by Haranni. Demo available from [https://forums.atariage.com/topic/381647-astronave/](https://forums.atariage.com/topic/381647-astronave/) * Barbarricade by Jess Ragan. Demo available from [https://forums.atariage.com/topic/390220-barbarricade-the-brick-breaking-game-where-the-bricks-break-you/](https://forums.atariage.com/topic/390220-barbarricade-the-brick-breaking-game-where-the-bricks-break-you/) From 93f83fd0f73474a87afb124d3f4822209995994e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 2 Jul 2026 23:22:24 -0600 Subject: [PATCH 149/155] Solved bug in MODE 2 initialization --- cvbasic_prologue.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 0641008..3ba064d 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1744,7 +1744,7 @@ mode_2: ld hl,$2000 ld bc,$0020 ld a,$f0 - call FILVRM2 + call FILVRM call cls jp vdp_generic_sprites endif From 4186229e996033dd7c04a1cf600773d457e466c7 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Fri, 3 Jul 2026 10:41:23 -0600 Subject: [PATCH 150/155] Solved bug in PALETTE for MSX1 (reported by an3ss) --- cvbasic.c | 10 +++++----- manual.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index 7aee149..b2ab4df 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5125,7 +5125,7 @@ void compile_statement(int check_for_else) emit_error("missing comma in PALETTE"); else get_lex(); - type = evaluate_expression(1, (machine == MSX2 ? TYPE_16 : TYPE_8), 0); + type = evaluate_expression(1, ((machine == MSX2 || machine == MSX) ? TYPE_16 : TYPE_8), 0); if (machine == SMS) { cpuz80_2op("OUT", "(VDP)", "A"); generic_interrupt_enable(); @@ -6790,10 +6790,10 @@ int main(int argc, char *argv[]) fprintf(stderr, "\n"); fprintf(stderr, " It will return a zero error code if compilation was\n"); fprintf(stderr, " successful, or non-zero otherwise.\n\n"); - fprintf(stderr, "Many thanks to acadiel, Albert, abeker, aotta, artrag, atari2600land,\n"); - fprintf(stderr, "carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan,\n"); - fprintf(stderr, "Kamshaft, Kiwi, MADrigal, pixelboy, Revontuli, SiRioKD, Tarzilla,\n"); - fprintf(stderr, "Tony Cruise, tursilion, visrealm, wavemotion, and youki.\n"); + fprintf(stderr, "Many thanks to acadiel, Albert, abeker, an3ss, aotta, artrag,\n"); + fprintf(stderr, "atari2600land, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic,\n"); + fprintf(stderr, "Jess Ragan, Kamshaft, Kiwi, MADrigal, pixelboy, Revontuli, SiRioKD,\n"); + fprintf(stderr, "Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki.\n"); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } diff --git a/manual.txt b/manual.txt index 1925679..ca8efea 100644 --- a/manual.txt +++ b/manual.txt @@ -1264,7 +1264,7 @@ The following statements are available: is not specified thereafter. Notice that the instrument waveforms can be altered - by modifying the cvbasic_epilogue.asm file for your + by modifying the cvbasic_prologue.asm file for your program. Notice the bass instrument reduces two octaves your From 0b250162bbc28f48cfd57206d2a84ed33760912d Mon Sep 17 00:00:00 2001 From: Howard Uman Date: Fri, 10 Jul 2026 17:09:28 -0400 Subject: [PATCH 151/155] update to latest version of cvbasic --- cvbasic.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++-- manual.txt | 46 ++++++++++++++++++++++- 2 files changed, 150 insertions(+), 4 deletions(-) diff --git a/cvbasic.c b/cvbasic.c index b2ab4df..f3cfb1d 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -426,6 +426,13 @@ void emit_warning(char *string) fprintf(stderr, "Warning: %s at line %d (%s)\n", string, current_line, current_file); } +/* + ** Emit info + */ +void emit_info(char *string) +{ + fprintf(stderr, "INFO: %s at line %d (%s)\n", string, current_line, current_file); +} /* ** Finish a bank */ @@ -626,7 +633,13 @@ struct constant *constant_add(char *name) } new_one->value = 0; strcpy(new_one->name, name); - previous = &constant_hash[label_hash_value(name)]; + char *c = new_one->name; + while (*c) + { + if (isalpha(*c)) *c = toupper(*c); + c++; + } + previous = &constant_hash[label_hash_value(new_one->name)]; new_one->next = *previous; *previous = new_one; return new_one; @@ -6456,7 +6469,8 @@ void compile_basic(void) struct label *label; int label_exists; char *p; - + int skip = 0; + int ppcDepth = 0; current_line = 0; while (fgets(line, sizeof(line) - 1, input)) { current_line++; @@ -6478,6 +6492,88 @@ void compile_basic(void) label_exists = 0; label = NULL; get_lex(); + + /* pre-processor #IF, #ELSE, #ENDIF + * currently supports a single level + */ + if (lex == C_NAME && name[0] == '#') { + int inv = 0; + if ((strcmp(name, "#IF") == 0) || + (strcmp(name, "#ELIF") == 0)) { + if (name[1] == 'I') /* #IF */ + { + if (ppcDepth) { + emit_error("Nested #IF not supported"); + } + } else { /* #ELIF */ + if (!ppcDepth) { + emit_error("#ELIF without matching #IF"); + } + if (ppcDepth < 0 || !skip) { + ppcDepth = -1; + skip = 1; + continue; + } + } + get_lex(); + if (lex == C_NAME) { + if (strcmp(name, "NOT") == 0) { + get_lex(); + inv = -1; + } + } + ppcDepth = 1; + if (lex == C_NAME) { + struct constant *c = constant_search(name); + skip = (!c || (c->value == 0)); + } else if (lex == C_NUM) { + skip = (value == 0); + } + get_lex(); + if (lex != C_END) { + emit_error("Extra characters"); + } + } else if (strcmp(name, "#ENDIF") == 0) { + if (!ppcDepth) { + emit_error("#ENDIF without matching #IF"); + } + ppcDepth = 0; + skip = 0; + continue; + } else if (strcmp(name, "#ELSE") == 0) { + if (ppcDepth > 0) { + skip = !skip; + } else if (ppcDepth < 0) { + skip = 1; + } else { + emit_error("Unexpected #ELSE. No matching #IF"); + } + continue; + } + + if (inv) skip = !skip; + + } + + if (skip) continue; + + if (lex == C_NAME && name[0] == '#') { + if (strcmp(name, "#INFO") == 0) { + get_lex(); + emit_info(name); + continue; + } else if (strcmp(name, "#WARN") == 0) { + get_lex(); + emit_warning(name); + continue; + } else if (strcmp(name, "#ERROR") == 0) { + get_lex(); + emit_error(name); + continue; + } + } + + if (lex == C_LABEL) { if (value == 0) strcpy(global_label, name); @@ -6833,7 +6929,13 @@ int main(int argc, char *argv[]) pencil = 0; } bytes_used = 0; - + + /* adding machine constants*/ + { + struct constant *mnc = constant_add(consoles[machine].name); + mnc->value = 1; + } + /* ** Extra options. */ diff --git a/manual.txt b/manual.txt index ca8efea..4b97c6e 100644 --- a/manual.txt +++ b/manual.txt @@ -14,7 +14,7 @@ This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages or loss arising from the use of this software. -It is prohibited to modify, decompile, disassemble or reverse engineer this +It is prohibited to modify, decompile, disassemble or reverse engineer this software. All trademarks are property of their respective owners. @@ -1532,6 +1532,50 @@ The expression parser will take advantage of 8-bit variables and numbers to opti Returns zero if music is not currently playing, returns a non-zero value otherwise. +>>>>>>>>>>>>>> Preprocessor + +The preprocessor can be used to confitionnaly include or exclude +CVBasic code from being compiled. This can be useful for including +platform-dependant user instructions or to enable or disable +diagnostics displays. + + #IF [NOT] constant + [statement] + [statement] + #ELSE + [statement] + [statement] + #ENDIF + +Unlike regular IF-THEN-ELSE statements, the excluded code is not +compiled at all so will not take up additional space in your compiled +rom image. + +One of the following pre-defined constants will be available and +set to equal 1 depending on the build target chosen: + + COLECOVISION, SG1000, MSX, SGM, SVI, SORD, MEMOTECH, CREATIVISION, + PENCIL, EINSTEIN, PV2000, TI994A, NABU, SMS + +These can be used to include or exclude CVBasic code for a given +target platform. eg: + + #IF TI994A + CONST BANKSIZE=8 + #ELSE + CONST BANKSIZE=16 + #ENDIF + +Compile-time logging: + + #INFO string + Output an information message at compile time. + + #WARN string + Output a warning message at compile time. + + #ERROR string + Output an error message and halt compilation at compile time. >>>>>>>>>>>>>>. FM support for MSX/MSX2/SMS From e58b19342bd0aedb371f9fdbe82f18216d52802e Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 16 Jul 2026 15:59:54 -0600 Subject: [PATCH 152/155] Added PLAY INSTRUMENT VARPTR. Corrected bug in TI-99/4A comparisons plus AND/OR, misoptimized R0 to R1 --- cpu9900.c | 50 ++++++++++++++++++++++---------------- cvbasic.c | 57 +++++++++++++++++++++++++------------------- cvbasic_epilogue.asm | 28 ++++++++++++++++++++++ manual.txt | 11 ++++++++- 4 files changed, 101 insertions(+), 45 deletions(-) diff --git a/cpu9900.c b/cpu9900.c index ac24028..f23272e 100644 --- a/cpu9900.c +++ b/cpu9900.c @@ -1209,12 +1209,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jeq", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_NOTEQUAL8) { cpu9900_2op("cb", temp, "r0"); @@ -1227,12 +1228,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jne", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_LESS8 || node->type == N_GREATER8) { cpu9900_2op("cb", "r0", temp); @@ -1245,12 +1247,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jl", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_LESSEQUAL8 || node->type == N_GREATEREQUAL8) { cpu9900_2op("cb", "r0", temp); @@ -1263,12 +1266,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jhe", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); /* Cannot be $+4 */ cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); /* To avoid optimizing seto r0 -> r1 */ } } else if (node->type == N_PLUS8) { cpu9900_2op("ab", temp, "r0"); @@ -1415,12 +1419,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op((node->type == N_EQUAL16 ? "jeq" : "jne"), temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } break; } @@ -1445,15 +1450,16 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); if (node->type == N_LESS16) cpu9900_1op("jl", temp); else if (node->type == N_GREATER16) cpu9900_1op("jh", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } break; } @@ -1648,12 +1654,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jeq", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_NOTEQUAL16) { cpu9900_2op("c", "r0", temp); @@ -1666,12 +1673,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jne", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_LESS16 || node->type == N_GREATER16) { cpu9900_2op("c", "r0", temp); @@ -1684,12 +1692,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jl", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_LESSEQUAL16 || node->type == N_GREATEREQUAL16) { cpu9900_2op("c", "r0", temp); @@ -1702,12 +1711,13 @@ void cpu9900_node_generate(struct node *node, int decision) cpu9900_label(temp + 100); } else { sprintf(temp, INTERNAL_PREFIX "%d", next_local++); + sprintf(temp + 100, INTERNAL_PREFIX "%d", next_local++); cpu9900_1op("jhe", temp); cpu9900_1op("clr", "r0"); - cpu9900_1op("jmp", "$+4"); + cpu9900_1op("jmp", temp + 100); cpu9900_label(temp); cpu9900_1op("seto", "r0"); - cpu9900_empty(); + cpu9900_label(temp + 100); } } else if (node->type == N_PLUS16) { cpu9900_2op("a", temp, "r0"); diff --git a/cvbasic.c b/cvbasic.c index b2ab4df..402d2dc 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -5598,30 +5598,39 @@ void compile_statement(int check_for_else) get_lex(); if (machine != MSX && machine != MSX2 && machine != SMS) emit_warning("PLAY INSTRUMENT only allowed for MSX/MSX2/SMS"); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_Z80) - cpuz80_2op("LD", "(fm_inst)", "A"); - if (lex != C_COMMA) - emit_error("missing comma"); - else - get_lex(); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_Z80) - cpuz80_2op("LD", "(fm_inst+1)", "A"); - if (lex != C_COMMA) - emit_error("missing comma"); - else - get_lex(); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_Z80) - cpuz80_2op("LD", "(fm_inst+2)", "A"); - if (lex != C_COMMA) - emit_error("missing comma"); - else - get_lex(); - type = evaluate_expression(1, TYPE_8, 0); - if (target == CPU_Z80) - cpuz80_2op("LD", "(fm_inst+3)", "A"); + if (lex == C_NAME && strcmp(name, "VARPTR") == 0) { + struct node *source = NULL; + + source = evaluate_save_expression(1, TYPE_16); /* CPU address (variable) */ + node_generate(source, 0); + cpuz80_1op("CALL", "program_fm"); + node_delete(source); + } else { + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst)", "A"); + if (lex != C_COMMA) + emit_error("missing comma"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst+1)", "A"); + if (lex != C_COMMA) + emit_error("missing comma"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst+2)", "A"); + if (lex != C_COMMA) + emit_error("missing comma"); + else + get_lex(); + type = evaluate_expression(1, TYPE_8, 0); + if (target == CPU_Z80) + cpuz80_2op("LD", "(fm_inst+3)", "A"); + } } else { struct label *label; diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 90ac8cc..67f5ab8 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -22,6 +22,7 @@ ; Revision date: Feb/03/2025. Round final ROM size to 8K multiples. ; Revision date: Feb/05/2026. Added support for spinners and roller controller ; (Colecovision). + ; Revision date: Jul/14/2026. Added program_fm. ; rom_end: @@ -439,6 +440,31 @@ play_fm: pop bc ret + ; + ; Program FM instrument + ; +program_fm: + push ix + push iy + ld de,fm_data + ld bc,8 + ldir + call fm_rom_switch + ld hl,fm_data + xor a +.1: push af + ld e,(hl) + call write_fm + inc hl + pop af + inc a + cp $08 + jr nz,.1 + call cartridge_rom_switch + pop iy + pop ix + ret + ; ; Init FM ; @@ -572,6 +598,8 @@ fm_enabled: rb 1 fm_inst: rb 4 +fm_data: + rb 8 endif mode: rb 1 ; bit 0: NMI disabled. diff --git a/manual.txt b/manual.txt index ca8efea..fe1d97b 100644 --- a/manual.txt +++ b/manual.txt @@ -1584,7 +1584,7 @@ An example is available in the directory examples/music_fm.bas Bits 7-4 contains the instrument number: - 0 - Programmable (not available currently) + 0 - Programmable (see PLAY INSTRUMENT VARPTR) 1 - Violin 2 - Guitar 3 - Piano @@ -1602,6 +1602,15 @@ An example is available in the directory examples/music_fm.bas f - Electric guitar + PLAY INSTRUMENT VARPTR fm_data(0) + This loads the only programmable instrument. + + For example: + + fm_data: + DATA BYTE $31,$11,$0e,$20,$d9,$b2,$11,$f4 ' Piano 1 + + >>>>>>>>>>>>>> Useful VRAM addresses Currently CVBasic handles in its own the bitmap, color and sprites tables. From 699589d9fdd65c44e367ae7c6309e18261fe1310 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Mon, 20 Jul 2026 13:37:30 -0600 Subject: [PATCH 153/155] Added example fm_instruments.bas --- cvbasic_epilogue.asm | 76 ++++--- cvbasic_prologue.asm | 16 ++ examples/fm_instruments.bas | 394 ++++++++++++++++++++++++++++++++++++ 3 files changed, 445 insertions(+), 41 deletions(-) create mode 100644 examples/fm_instruments.bas diff --git a/cvbasic_epilogue.asm b/cvbasic_epilogue.asm index 67f5ab8..e13f8e0 100644 --- a/cvbasic_epilogue.asm +++ b/cvbasic_epilogue.asm @@ -23,6 +23,7 @@ ; Revision date: Feb/05/2026. Added support for spinners and roller controller ; (Colecovision). ; Revision date: Jul/14/2026. Added program_fm. + ; Revision date: Jul/20/2026. Moved program_fm to cvbasic_prologue.asm. ; rom_end: @@ -158,6 +159,8 @@ msx_find_fm: ; Write a FM register ; A = register ; E = data +write_fm_zero: + ld e,0 write_fm: jp WRTOPL @@ -268,6 +271,22 @@ music_generate_fm: push bc push de call fm_rom_switch + ld a,(fm_new) + or a ; New programmed instrument. + jr z,.8 + xor a + ld (fm_new),a + ld hl,fm_data + xor a +.10: push af + ld e,(hl) + call write_fm + inc hl + pop af + inc a + cp $08 + jr nz,.10 +.8: pop de pop bc ld a,b @@ -381,9 +400,8 @@ play_fm: push de ld c,a ; Saves base register. add a,$10 - ld e,$00 ; Turn off voice if it was turned on. push bc - call write_fm + call write_fm_zero ; Turn off voice if it was turned on. pop bc ld a,b ; Read instrument (bits 7-6) and $c0 @@ -440,31 +458,6 @@ play_fm: pop bc ret - ; - ; Program FM instrument - ; -program_fm: - push ix - push iy - ld de,fm_data - ld bc,8 - ldir - call fm_rom_switch - ld hl,fm_data - xor a -.1: push af - ld e,(hl) - call write_fm - inc hl - pop af - inc a - cp $08 - jr nz,.1 - call cartridge_rom_switch - pop iy - pop ix - ret - ; ; Init FM ; @@ -485,14 +478,10 @@ init_fm: call write_fm djnz .1 call cartridge_rom_switch - ld a,$30 ; Piano - ld (fm_inst),a - ld a,$50 ; Clarinet - ld (fm_inst+1),a - ld a,$40 ; Flute - ld (fm_inst+2),a - ld a,$e0 ; Acoustic bass - ld (fm_inst+3),a + ld hl,.2 + ld de,fm_inst + ld bc,4 + ldir pop iy pop ix ret @@ -522,6 +511,12 @@ init_fm: dw $3720 ; Hihat / Snare Drum dw $3800 ; Tom / Top Cymbal +.2: + db $30 ; Piano. + db $50 ; Clarinet. + db $40 ; Flute. + db $e0 ; Clarinet bass. + ; ; Turn off FM ; @@ -534,14 +529,11 @@ turn_off_fm: ret z call fm_rom_switch LD A,$10+$10 - LD E,$00 - CALL write_fm + CALL write_fm_zero LD A,$11+$10 - LD E,$00 - CALL write_fm + CALL write_fm_zero LD A,$12+$10 - LD E,$00 - CALL write_fm + CALL write_fm_zero CALL cartridge_rom_switch RET @@ -598,6 +590,8 @@ fm_enabled: rb 1 fm_inst: rb 4 +fm_new: + rb 1 fm_data: rb 8 endif diff --git a/cvbasic_prologue.asm b/cvbasic_prologue.asm index 3ba064d..fd4f859 100644 --- a/cvbasic_prologue.asm +++ b/cvbasic_prologue.asm @@ -1421,6 +1421,22 @@ font_bitmaps: db $70,$70,$20,$f8,$20,$70,$50,$00 ; $7f endif + if MSX+SMS + if FM_SUPPORT + ; + ; Program FM instrument + ; +program_fm: + ld de,fm_data + ld bc,8 + ldir + ld a,1 + ld (fm_new),a + ; Cannot load instrument here, as it could imply bank switching. + ret + endif + endif + if MSX palette_default: ld hl,msx2_default_palette diff --git a/examples/fm_instruments.bas b/examples/fm_instruments.bas new file mode 100644 index 0000000..037e06f --- /dev/null +++ b/examples/fm_instruments.bas @@ -0,0 +1,394 @@ + ' + ' Test of FM instruments + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Jul/14/2026. + ' + + ' Enable ASCII16 or Sega Mapper in emulation. + + BANK ROM 128 ' Required to enable FM. + + OPTION FM ON ' Required to integrate FM support. + + ' + ' This requires a MSX2+ or Sega Master System with FM extension (Japanese) + ' + PLAY INSTRUMENT $00,$00,$00,$00 ' All voices using user-defined instrument. + + debounce = 15 + + instrument = 0 + + PLAY FULL + + IF MUSIC.FM_ENABLED THEN + PRINT AT 2,"Ready to play FM..." + END IF + +game_loop: + PRINT AT 66,"Instrument: ",<2>instrument + DEFINE VRAM $1866, 24, VARPTR names(instrument * 24) + PRINT AT 162,"Press button to play" + + WAIT + c = CONT + IF debounce THEN debounce = debounce - 1: c = 0 + IF c AND 1 THEN + debounce = 15 + IF instrument = 0 THEN instrument = 63 ELSE instrument = instrument - 1 + END IF + IF c AND 4 THEN + debounce = 15 + IF instrument = 63 THEN instrument = 0 ELSE instrument = instrument + 1 + END IF + IF c AND 64 THEN + debounce = 15 + PLAY INSTRUMENT VARPTR fm_instruments(instrument * 8) ' Define instrument. + PLAY music_simple + END IF + IF c AND 128 THEN + debounce = 15 + PLAY INSTRUMENT VARPTR fm_instruments(instrument * 8) ' Define instrument. + PLAY music_bach + END IF + GOTO game_loop + +music_simple: + DATA BYTE 16 + MUSIC C4,-,-,- + MUSIC D4,-,-,- + MUSIC E4,-,-,- + MUSIC F4,-,-,- + MUSIC G4,-,-,- + MUSIC A4,-,-,- + MUSIC B4,-,-,- + MUSIC C5,-,-,- + MUSIC -,-,-,- + MUSIC STOP + + ' Bach Invention 8 (BWV779) + ' Fragment +music_bach: DATA BYTE 7 + MUSIC F4,- + MUSIC S,- + MUSIC A4,- + MUSIC S,- + MUSIC F4,- + MUSIC S,- + MUSIC C5,- + MUSIC S,- + MUSIC F4,- + MUSIC S,- + + MUSIC F5,- + MUSIC S,- + MUSIC E5,F3 + MUSIC D5,S + MUSIC C5,A3 + MUSIC D5,S + MUSIC C5,F3 + MUSIC A4#,S + MUSIC A4,C4 + MUSIC A4#,S + MUSIC A4,F3 + MUSIC G4,S + + MUSIC F4,F4 + MUSIC S,S + MUSIC A4,E4 + MUSIC S,D4 + MUSIC C5,C4 + MUSIC S,D4 + MUSIC A4,C4 + MUSIC S,A3# + MUSIC F5,A3 + MUSIC S,A3# + MUSIC C5,A3 + MUSIC S,G3 + + MUSIC A5,F3 + MUSIC C6,S + MUSIC A5#,A3 + MUSIC C6,S + MUSIC A5,C4 + MUSIC C6,S + MUSIC A5#,A3 + MUSIC C6,S + MUSIC A5,F4 + MUSIC C6,S + MUSIC A5#,C4 + MUSIC C6,S + + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + MUSIC F5,A3 + MUSIC A5,C4 + MUSIC G5,A3# + MUSIC A5,C4 + + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + MUSIC D5,F3 + MUSIC F5,A3 + MUSIC E5,G3 + MUSIC F5,A3 + + MUSIC B4,D3 + MUSIC S,F3 + MUSIC G4,E3 + MUSIC S,F3 + MUSIC D5,D3 + MUSIC S,F3 + MUSIC B4,E3 + MUSIC S,F3 + MUSIC F5,D3 + MUSIC S,F3 + MUSIC D5,E3 + MUSIC S,F3 + + MUSIC G5,B3 + MUSIC A5,S + MUSIC G5,G3 + MUSIC F5,S + MUSIC E5,C4 + MUSIC F5,S + MUSIC E5,G3 + MUSIC D5,S + MUSIC C5,E4 + MUSIC D5,S + MUSIC C5,C4 + MUSIC A4#,S + + MUSIC A4,F4 + MUSIC S,G4 + MUSIC D5,F4 + MUSIC C5,E4 + MUSIC B4,D4 + MUSIC C5,E4 + MUSIC B4,D4 + MUSIC A4,C4 + MUSIC G4,B3 + MUSIC A4,C4 + MUSIC G4,B3 + MUSIC F4,A3 + + MUSIC E4,G3 + MUSIC F4,S + MUSIC E4,C4 + MUSIC D4,B3 + MUSIC C4,A3 + MUSIC S,B3 + MUSIC C5,A3 + MUSIC B4,G3 + MUSIC C5,F3 + MUSIC S,G3 + MUSIC E4,F3 + MUSIC S,E3 + + MUSIC F4,D3 + MUSIC S,E3 + MUSIC C5,D3 + MUSIC S,C3 + MUSIC E4,G3 + MUSIC S,F3 + MUSIC C5,E3 + MUSIC S,F3 + MUSIC D4,G3 + MUSIC S,S + MUSIC B4,G2 + MUSIC S,S + + MUSIC C5,C4 + MUSIC S,S + MUSIC S,S + MUSIC S,S + MUSIC STOP + + ' + ' Editing waveforms (an editor could be made): + ' + ' Register: + ' 7 6 5 4 3 2 1 0 + ' 0 AM(M) VIB(M) EGT(M) KSR(M) Multiple(M) + ' 1 AM(C) VIB(C) EGT(C) KSR(C) Multiple(C) + ' 2 KSL(M) Total LEVEL MODULATOR + ' 3 KSL(C) Unused DC DM Feedback + ' 4 Attack (M) Decay (M) + ' 5 Attack (C) Decay (C) + ' 6 Sustain (M) Release (M) + ' 7 Sustain (C) Release (C) + ' + + ' + ' Extracted from the FM-PAC ROM for Sony HB-F1XDJ by nanochess. Jul/14/2026. + ' + ' The original ROM entries are 32-byte wide, I ran an automatic processor + ' to get the following data in register order. + ' + ' Register: + ' 0 = rom[16] + ' 1 = rom[24] + ' 2 = rom[17] + ' 3 = (rom[25] & ~0x07) | ((rom[10] >> 1) & 7) Feedback (preserves KSL(C)) + ' 4 = rom[18] + ' 5 = rom[26] + ' 6 = rom[19] + ' 7 = rom[27] + ' + ' The ROM also contains entries 8-byte wide, but these have a + ' fixed 0x20 value in byte 3, and this renders it unusable. + ' + ' This data is important as there aren't references of instruments + ' settings for YM2413 in Internet (not even in the datasheet). + ' + ' Probably all original Japanese composing software for MSX2+ + ' referred to the instruments ROM or allowed some alteration on + ' values, but it was early 1990s and without Internet probably + ' this data was forgotten. + ' +fm_instruments: + DATA BYTE $31, $11, $0e, $05, $d9, $b2, $11, $f4 ' 0: Piano 1 + DATA BYTE $30, $10, $0f, $04, $d9, $b2, $10, $f3 ' 1: Piano 2 + DATA BYTE $61, $61, $12, $07, $b4, $56, $14, $17 ' 2: Violin + DATA BYTE $61, $31, $20, $07, $6c, $43, $18, $26 ' 3: Flute 1 + DATA BYTE $a2, $30, $a0, $07, $88, $54, $14, $06 ' 4: Clarinet + DATA BYTE $31, $34, $20, $05, $72, $56, $0a, $1c ' 5: Oboe + DATA BYTE $31, $71, $16, $07, $51, $52, $26, $24 ' 6: Trumpet + DATA BYTE $34, $30, $37, $06, $50, $30, $76, $06 ' 7: Pipe organ + DATA BYTE $17, $52, $18, $05, $88, $d9, $66, $24 ' 8: Xylophone + DATA BYTE $e1, $63, $0a, $06, $fc, $f8, $28, $29 ' 9: Organ + DATA BYTE $02, $41, $15, $05, $a3, $a3, $75, $05 ' 10: Guitar + DATA BYTE $19, $53, $0c, $06, $c7, $f5, $11, $03 ' 11: Santool 1 + DATA BYTE $23, $43, $0f, $07, $dd, $bf, $4a, $05 ' 12: Electric piano 1 + DATA BYTE $03, $09, $11, $0e, $d2, $b4, $f4, $f5 ' 13: Clavicode 1 + DATA BYTE $01, $00, $06, $1e, $a3, $e2, $f4, $f4 ' 14: Harpsicode 1 + DATA BYTE $01, $01, $11, $0e, $c0, $b4, $01, $f6 ' 15: Harpsicode 2 + DATA BYTE $f9, $f1, $24, $06, $95, $d1, $e5, $f2 ' 16: Vibraphone + DATA BYTE $13, $11, $0c, $06, $fc, $d2, $33, $83 ' 17: Koto 1 + DATA BYTE $01, $10, $0e, $07, $ca, $e6, $44, $24 ' 18: Taiko + DATA BYTE $e0, $f4, $1b, $87, $11, $f0, $04, $08 ' 19: Engine 1 + DATA BYTE $ff, $70, $19, $07, $50, $1f, $05, $01 ' 20: UFO + DATA BYTE $13, $11, $11, $07, $fa, $f2, $21, $f4 ' 21: Synthesizer bell + DATA BYTE $a6, $42, $10, $0d, $fb, $b9, $11, $02 ' 22: Chime + DATA BYTE $40, $31, $89, $06, $c7, $f9, $14, $04 ' 23: Synthesizer bass + DATA BYTE $42, $44, $0b, $06, $94, $b0, $33, $f6 ' 24: Synthesizer + DATA BYTE $01, $03, $0b, $07, $ba, $d9, $25, $06 ' 25: Synthesizer percussion + DATA BYTE $40, $00, $00, $07, $fa, $d9, $37, $04 ' 26: Synthesizer rhythm + DATA BYTE $02, $03, $09, $07, $cb, $ff, $39, $06 ' 27: Harm drum + DATA BYTE $18, $11, $09, $05, $f8, $f5, $26, $26 ' 28: Cowbell + DATA BYTE $0b, $04, $09, $07, $f0, $f5, $01, $27 ' 29: Close hi-hat + DATA BYTE $40, $40, $07, $07, $d0, $d6, $01, $27 ' 30: Snare drum + DATA BYTE $00, $01, $07, $06, $cb, $e3, $36, $25 ' 31: Bass drum + DATA BYTE $11, $11, $08, $04, $fa, $b2, $20, $f4 ' 32: Piano 3 + DATA BYTE $11, $11, $11, $00, $c0, $b2, $01, $f4 ' 33: Electric piano 2 + DATA BYTE $19, $53, $15, $07, $e7, $95, $21, $03 ' 34: Santool 2 + DATA BYTE $30, $70, $19, $07, $42, $62, $26, $24 ' 35: Brass + DATA BYTE $62, $71, $25, $07, $64, $43, $12, $26 ' 36: Flute 2 + DATA BYTE $21, $03, $0b, $05, $90, $d4, $02, $f5 ' 37: Clavicode 2 + DATA BYTE $01, $03, $0a, $05, $90, $a4, $03, $f5 ' 38: Clavicode 3 + DATA BYTE $43, $53, $0e, $85, $b5, $e9, $84, $04 ' 39: Koto 2 + DATA BYTE $34, $30, $26, $06, $50, $30, $76, $06 ' 40: Pipe organ 2 + DATA BYTE $73, $33, $5a, $06, $99, $f5, $14, $15 ' 41: PohdsPLA + DATA BYTE $73, $13, $16, $05, $f9, $f5, $33, $03 ' 42: RohdsPRA + DATA BYTE $61, $21, $15, $07, $76, $54, $23, $06 ' 43: Orch L + DATA BYTE $63, $70, $1b, $07, $75, $4b, $45, $15 ' 44: Orch R + DATA BYTE $61, $a1, $0a, $05, $76, $54, $12, $07 ' 45: Synthesizer violin + DATA BYTE $61, $78, $0d, $0d, $85, $f2, $14, $03 ' 46: Synthesizer organ + DATA BYTE $31, $71, $15, $07, $b6, $f9, $03, $26 ' 47: Synthesizer bass + DATA BYTE $61, $71, $0d, $05, $75, $f2, $18, $03 ' 48: Tube + DATA BYTE $03, $0c, $14, $06, $a7, $fc, $13, $15 ' 49: Shamisen + DATA BYTE $13, $32, $80, $03, $20, $85, $03, $af ' 50: Magical + DATA BYTE $f1, $31, $17, $05, $23, $40, $14, $09 ' 51: Huwawa + DATA BYTE $f0, $74, $17, $47, $5a, $43, $06, $fc ' 52: Wander flat + DATA BYTE $20, $71, $0d, $06, $c1, $d5, $56, $06 ' 53: Hardrock + DATA BYTE $30, $32, $06, $06, $40, $40, $04, $74 ' 54: Machine + DATA BYTE $30, $32, $03, $03, $40, $40, $04, $74 ' 55: Machine V + DATA BYTE $01, $08, $0d, $07, $78, $f8, $7f, $f9 ' 56: Comic + DATA BYTE $c8, $c0, $0b, $05, $76, $f7, $11, $f9 ' 57: SE-Comic + DATA BYTE $49, $40, $0b, $07, $b4, $f9, $ff, $05 ' 58: SE-Laser + DATA BYTE $cd, $42, $0c, $06, $a2, $f0, $00, $01 ' 59: SE-Noise + DATA BYTE $51, $42, $13, $07, $13, $10, $42, $01 ' 60: SE-Star 1 + DATA BYTE $51, $42, $13, $07, $13, $10, $42, $01 ' 61: SE-Star 2 + DATA BYTE $30, $34, $12, $06, $23, $70, $26, $02 ' 62: Engine 2 + DATA BYTE $00, $00, $ff, $f8, $00, $00, $ff, $ff ' 63: Silence + +names: + DATA BYTE " Piano 1" + DATA BYTE " Piano 2" + DATA BYTE " Violin" + DATA BYTE " Flute 1" + DATA BYTE " Clarinet" + DATA BYTE " Oboe" + DATA BYTE " Trumpet" + DATA BYTE " Pipe organ" + DATA BYTE " Xylophone" + DATA BYTE " Organ" + DATA BYTE " Guitar" + DATA BYTE " Santool 1" + DATA BYTE " Electric piano 1" + DATA BYTE " Clavicode 1" + DATA BYTE " Harpsicode 1" + DATA BYTE " Harpsicode 2" + DATA BYTE " Vibraphone" + DATA BYTE " Koto 1" + DATA BYTE " Taiko" + DATA BYTE " Engine 1" + DATA BYTE " UFO" + DATA BYTE " Synthesizer bell" + DATA BYTE " Chime" + DATA BYTE " Synthesizer bass" + DATA BYTE " Synthesizer" + DATA BYTE " Synthesizer percussion" + DATA BYTE " Synthesizer rhythm" + DATA BYTE " Harm drum" + DATA BYTE " Cowbell" + DATA BYTE " Close hi-hat" + DATA BYTE " Snare drum" + DATA BYTE " Bass drum" + DATA BYTE " Piano 3" + DATA BYTE " Electric piano 2" + DATA BYTE " Santool 2" + DATA BYTE " Brass" + DATA BYTE " Flute 2" + DATA BYTE " Clavicode 2" + DATA BYTE " Clavicode 3" + DATA BYTE " Koto 2" + DATA BYTE " Pipe organ 2" + DATA BYTE " PohdsPLA" + DATA BYTE " RohdsPRA" + DATA BYTE " Orch L" + DATA BYTE " Orch R" + DATA BYTE " Synthesizer violin" + DATA BYTE " Synthesizer organ" + DATA BYTE " Synthesizer bass" + DATA BYTE " Tube" + DATA BYTE " Shamisen" + DATA BYTE " Magical" + DATA BYTE " Huwawa" + DATA BYTE " Wander flat" + DATA BYTE " Hardrock" + DATA BYTE " Machine" + DATA BYTE " Machine V" + DATA BYTE " Comic" + DATA BYTE " SE-Comic" + DATA BYTE " SE-Laser" + DATA BYTE " SE-Noise" + DATA BYTE " SE-Star 1" + DATA BYTE " SE-Star 2" + DATA BYTE " Engine 2" + DATA BYTE " Silence" \ No newline at end of file From 22fbae19b7276725e623115dce70015fa245de21 Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 23 Jul 2026 10:45:17 -0600 Subject: [PATCH 154/155] Updated preprocessor to repository coding style --- README.md | 4 +- cvbasic.c | 124 ++++++++++++++++++++++----------------------- cvbasic.h | 1 + examples/test5.bas | 28 ++++++++++ 4 files changed, 93 insertions(+), 64 deletions(-) create mode 100644 examples/test5.bas diff --git a/README.md b/README.md index be49b5b..7b2eac0 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ The following files compose the compiler: examples/test3.bas Shows usage of SELECT CASE / END CASE examples/test3_sms.bas Shows usage of SELECT CASE / END CASE (Sega Master System) examples/test4.bas Benchmark and test of multiplication/division + examples/test5.bas Example of using the preprocessor examples/varptr.bas VARPTR example for redefining graphics. examples/varptr_sms.bas VARPTR example for redefining graphics (Sega Master System) examples/vgm.bas VGM audio player for SN76489. @@ -365,4 +366,5 @@ Several utilities which can be used with CVBasic have emerged for graphics desig ### Acknowledgments -Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, Atarius Maximus, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, Revontuli, SiRioKD, Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki. +Thanks to the following members of Atariage for contributing valuable suggestions: abeker, acadiel, aotta, ARTRAG, atari2600land, Atarius Maximus, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic, Jess Ragan, Kamshaft, Kiwi, pixelboy, Revontuli, SiRioKD, Tarzilla, Tony Cruise, tursilion, unhuman, + visrealm, wavemotion, and youki. diff --git a/cvbasic.c b/cvbasic.c index ebcb399..a768963 100644 --- a/cvbasic.c +++ b/cvbasic.c @@ -57,56 +57,56 @@ enum cpu_target target; struct console consoles[TOTAL_TARGETS] = { /* RAM STACK Size VDP R VDP W PSG */ {"colecovision","", "Standard Colecovision (1K RAM)", - "Colecovision", + "Colecovision", "COLECOVISION", 0x7000, 0x7400, 0x0400, 0xbe, 0xbe, 0xff, 0, CPU_Z80}, {"sg1000", "", "Sega SG-1000/SC-3000 (1K RAM)", - "Sega SG-1000/SC-3000", + "Sega SG-1000/SC-3000", "SG1000", 0xc000, 0xc400, 0x0400, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, {"msx", "-ram16", "MSX (8K RAM), use -ram16 for 16K of RAM,\n use -konami for Konami mapper instead of ASCII16", - "MSX", + "MSX", "MSX", 0xe000, 0xf380, 0x1380, 0x98, 0x98, 0, 1, CPU_Z80}, {"sgm", "", "Colecovision with Opcode's Super Game Module", - "Colecovision with SGM", + "Colecovision with SGM", "SGM", 0x7c00, 0x8000, 0x5c00, 0xbe, 0xbe, 0xff, 0, CPU_Z80}, /* Note: Real RAM at 0x2000 */ {"svi", "", "Spectravideo SVI-318/328 (16K of RAM)", - "Spectravideo SVI-318/328", + "Spectravideo SVI-318/328", "SVI", 0xc000, 0xf000, 0x3000, 0x80, 0x84, 0, 1, CPU_Z80}, {"sord", "", "Sord M5 (1K RAM)", - "Sord M5", + "Sord M5", "SORD", 0x7080, 0x7080, 0x0380, 0x10, 0x10, 0x20, 1, CPU_Z80}, {"memotech","-cpm", "Memotech MTX (64K RAM), generates .run files, use -cpm for .com files", - "Memotech MTX", + "Memotech MTX", "MEMOTECH", 0, 0xa000, 0, 0x01, 0x01, 0x06, 1, CPU_Z80}, {"creativision","-rom16","Vtech Creativision (Dick Smith's Wizzard/Laser 2001), 6502+1K RAM.", - "Creativision/Wizzard", + "Creativision/Wizzard", "CREATIVISION", 0x0050, 0x017f, 0x0400, 0, 0, 0, 1, CPU_6502}, {"pencil", "", "Soundic/Hanimex Pencil II (2K RAM)", - "Soundic Pencil II", + "Soundic Pencil II", "PENCIL", 0x7000, 0x7800, 0x0800, 0xbe, 0xbe, 0xff, 0, CPU_Z80}, {"einstein","", "Tatung Einstein, generates .com files", - "Tatung Einstein", + "Tatung Einstein", "EINSTEIN", 0, 0xa000, 0, 0x08, 0x08, 0, 0, CPU_Z80}, {"pv2000", "", "Casio PV-2000", - "Casio PV-2000", + "Casio PV-2000", "PV2000", 0x7600, 0x8000, 0x0a00,0x4000, 0x4000, 0x40, 0, CPU_Z80}, {"ti994a", "", "Texas Instruments TI-99/4A (32K RAM). Support by tursilion", - "TI-99/4A (support by tursilion)", + "TI-99/4A (support by tursilion)", "TI994A", 0x2080, 0x4000, 0x1f80, 0x8800, 0x8c00,0xff, 1, CPU_9900}, {"nabu", "-cpm", "NABU PC (64K RAM)", - "Nabu PC", + "Nabu PC", "NABU", 0, 0xe000, 0, 0xa0, 0xa0, 0, 1, CPU_Z80}, /* ** For Sega Master System the stack cannot start at $e000, because ** when using Bank Switching writing to $fffd-$ffff destroys $dffd-$dfff */ {"sms", "", "Sega Master System (8K RAM)", - "Sega Master System", + "Sega Master System", "SMS", 0xc000, 0xdff0, 0x1ff0, 0xbe, 0xbe, 0x7f, 1, CPU_Z80}, {"nes", "", "NES/Famicom (2K RAM)", - "NES/Famicom", + "NES/Famicom", "NES", 0x0050, 0x01ff, 0x0800, 0, 0, 0, 1, CPU_6502}, {"msx2", "-ram16", "MSX2 (8K RAM), use -ram16 for 16K of RAM,\n use -konami for Konami mapper instead of ASCII16", - "MSX2", + "MSX2", "MSX2", 0xe000, 0xf380, 0x1380, 0x98, 0x98, 0, 1, CPU_Z80}, }; @@ -633,12 +633,6 @@ struct constant *constant_add(char *name) } new_one->value = 0; strcpy(new_one->name, name); - char *c = new_one->name; - while (*c) - { - if (isalpha(*c)) *c = toupper(*c); - c++; - } previous = &constant_hash[label_hash_value(new_one->name)]; new_one->next = *previous; *previous = new_one; @@ -6479,7 +6473,8 @@ void compile_basic(void) int label_exists; char *p; int skip = 0; - int ppcDepth = 0; + int if_depth = 0; + current_line = 0; while (fgets(line, sizeof(line) - 1, input)) { current_line++; @@ -6502,24 +6497,24 @@ void compile_basic(void) label = NULL; get_lex(); - /* pre-processor #IF, #ELSE, #ENDIF - * currently supports a single level + /* + ** C-style preprocessor #IF, #ELSE, #ENDIF + ** Currently supports a single nesting level. */ if (lex == C_NAME && name[0] == '#') { int inv = 0; - if ((strcmp(name, "#IF") == 0) || - (strcmp(name, "#ELIF") == 0)) { - if (name[1] == 'I') /* #IF */ - { - if (ppcDepth) { + + if (strcmp(name, "#IF") == 0 || strcmp(name, "#ELIF") == 0) { + if (name[1] == 'I') { /* #IF */ + if (if_depth) { emit_error("Nested #IF not supported"); } } else { /* #ELIF */ - if (!ppcDepth) { + if (!if_depth) { emit_error("#ELIF without matching #IF"); } - if (ppcDepth < 0 || !skip) { - ppcDepth = -1; + if (if_depth < 0 || !skip) { + if_depth = -1; skip = 1; continue; } @@ -6531,9 +6526,10 @@ void compile_basic(void) inv = -1; } } - ppcDepth = 1; + if_depth = 1; if (lex == C_NAME) { struct constant *c = constant_search(name); + skip = (!c || (c->value == 0)); } else if (lex == C_NUM) { skip = (value == 0); @@ -6543,35 +6539,35 @@ void compile_basic(void) emit_error("Extra characters"); } } else if (strcmp(name, "#ENDIF") == 0) { - if (!ppcDepth) { + if (!if_depth) { emit_error("#ENDIF without matching #IF"); } - ppcDepth = 0; + if_depth = 0; skip = 0; - continue; + continue; } else if (strcmp(name, "#ELSE") == 0) { - if (ppcDepth > 0) { + if (if_depth > 0) { skip = !skip; - } else if (ppcDepth < 0) { + } else if (if_depth < 0) { skip = 1; } else { emit_error("Unexpected #ELSE. No matching #IF"); } continue; } - - if (inv) skip = !skip; - + if (inv) + skip = !skip; } - if (skip) continue; + if (skip) + continue; if (lex == C_NAME && name[0] == '#') { if (strcmp(name, "#INFO") == 0) { get_lex(); emit_info(name); continue; - } else if (strcmp(name, "#WARN") == 0) { + } else if (strcmp(name, "#WARNING") == 0) { get_lex(); emit_warning(name); continue; @@ -6863,6 +6859,7 @@ int main(int argc, char *argv[]) int cpm_option; int pencil; char hex; + struct constant *machine_constant; actual = time(0); date = localtime(&actual); @@ -6898,7 +6895,8 @@ int main(int argc, char *argv[]) fprintf(stderr, "Many thanks to acadiel, Albert, abeker, an3ss, aotta, artrag,\n"); fprintf(stderr, "atari2600land, carlsson, chalkyw64, CrazyBoss, drfloyd, gemintronic,\n"); fprintf(stderr, "Jess Ragan, Kamshaft, Kiwi, MADrigal, pixelboy, Revontuli, SiRioKD,\n"); - fprintf(stderr, "Tarzilla, Tony Cruise, tursilion, visrealm, wavemotion, and youki.\n"); + fprintf(stderr, "Tarzilla, Tony Cruise, tursilion, unhuman, visrealm, wavemotion,\n"); + fprintf(stderr, "and youki.\n"); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } @@ -6939,12 +6937,6 @@ int main(int argc, char *argv[]) } bytes_used = 0; - /* adding machine constants*/ - { - struct constant *mnc = constant_add(consoles[machine].name); - mnc->value = 1; - } - /* ** Extra options. */ @@ -6957,7 +6949,7 @@ int main(int argc, char *argv[]) extra_ram = 8192; } else { fprintf(stderr, "-ram16 option only applies to MSX/MSX2.\n"); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } } bank_konami = 0; @@ -6969,7 +6961,7 @@ int main(int argc, char *argv[]) bank_konami = 1; } else { fprintf(stderr, "-konami option only applies to MSX/MSX2.\n"); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } } cpm_option = 0; @@ -6982,7 +6974,7 @@ int main(int argc, char *argv[]) cpm_option = 1; } else { fprintf(stderr, "-cpm option only applies to Memotech or NABU.\n"); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } } small_rom = 0; @@ -6994,10 +6986,16 @@ int main(int argc, char *argv[]) small_rom = 1; } else { fprintf(stderr, "-rom16 option only applies to Creativision.\n"); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } } + /* + ** Create machine constant + */ + machine_constant = constant_add(consoles[machine].constant);; + machine_constant->value = 1; + /* ** Passed-in constants */ @@ -7013,7 +7011,7 @@ int main(int argc, char *argv[]) break; if (!isalnum(ch) && ch != '_' && ch != '#' && ch != '=') { fprintf(stderr, "%s name includes invalid characters.\n", argv[c]); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } if (ch == '=') { *p = '\0'; @@ -7032,7 +7030,7 @@ int main(int argc, char *argv[]) } if (d == NULL) { fprintf(stderr, "%s missing assignment. Syntax: -DCONST=123 -D#BIGCONST=12345\n", argv[c]); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } c++; } @@ -7045,14 +7043,14 @@ int main(int argc, char *argv[]) input = fopen(current_file, "r"); if (input == NULL) { fprintf(stderr, "Couldn't open '%s' source file.\n", current_file); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } c++; output = fopen(TEMPORARY_ASSEMBLER, "w"); if (output == NULL) { fprintf(stderr, "Couldn't open '%s' temporary file.\n", TEMPORARY_ASSEMBLER); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } bank_switching = 0; option_explicit = 0; @@ -7087,7 +7085,7 @@ int main(int argc, char *argv[]) output = fopen(argv[c], "w"); if (output == NULL) { fprintf(stderr, "Couldn't open '%s' output file.\n", argv[2]); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } c++; @@ -7200,7 +7198,7 @@ int main(int argc, char *argv[]) prologue = fopen(path, "r"); if (prologue == NULL) { fprintf(stderr, "Unable to open '%s'.\n", path); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } while (fgets(line, sizeof(line) - 1, prologue)) { p = line; @@ -7242,7 +7240,7 @@ int main(int argc, char *argv[]) input = fopen(TEMPORARY_ASSEMBLER, "r"); if (input == NULL) { fprintf(stderr, "Unable to reopen '%s'.\n", TEMPORARY_ASSEMBLER); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } while (fgets(line, sizeof(line) - 1, input)) { fputs(line, output); @@ -7262,7 +7260,7 @@ int main(int argc, char *argv[]) prologue = fopen(path, "r"); if (prologue == NULL) { fprintf(stderr, "Unable to open '%s'.\n", path); - exit(EXIT_FAILURE+1); + exit(EXIT_FAILURE + 1); } while (fgets(line, sizeof(line) - 1, prologue)) { fputs(line, output); diff --git a/cvbasic.h b/cvbasic.h index e7f5151..8be2517 100644 --- a/cvbasic.h +++ b/cvbasic.h @@ -59,6 +59,7 @@ struct console { char *options; /* Options */ char *description; /* Description (for usage guide) */ char *canonical; /* Canonical name */ + char *constant; /* CONST name */ int base_ram; /* Where the RAM starts */ int stack; /* Where the stack will start */ int memory_size; /* Memory available */ diff --git a/examples/test5.bas b/examples/test5.bas new file mode 100644 index 0000000..6b929e6 --- /dev/null +++ b/examples/test5.bas @@ -0,0 +1,28 @@ + ' + ' C-style preprocessor test + ' + ' by Oscar Toledo G. + ' https://nanochess.org/ + ' + ' Creation date: Jul/23/2026. + ' + + ' You can use the platform constant (equivalent to the compilation option), + ' or a constant provided via command-line, or a constant defined inside + ' the program. + +#if COLECOVISION + PRINT AT 33,"Compiled for Colecovision" +#endif + +#if SGM + PRINT AT 65,"Compiled for SGM" +#endif + +#if COLECOVISION + PRINT AT 97,"This is a Colecovision" +#else + PRINT AT 97,"This isn't a Colecovision" +#endif + + WHILE 1: WEND From 26e9803d0e6c583b171c57f2c300c403a9bc3f4c Mon Sep 17 00:00:00 2001 From: Oscar Toledo Date: Thu, 23 Jul 2026 11:03:49 -0600 Subject: [PATCH 155/155] Updated manual for preprocessor --- manual.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/manual.txt b/manual.txt index dbe9802..eec1d70 100644 --- a/manual.txt +++ b/manual.txt @@ -22,11 +22,12 @@ All trademarks are property of their respective owners. >>>>>>>>>>>>>> Changes in this version -v0.9.2 Jun/20/2026 o FM synthesis for MSX, MSX2, and Sega Master System. +v0.9.2 Jul/23/2026 o FM synthesis for MSX, MSX2, and Sega Master System. o Added OPTION FM. o Added PLAY INSTRUMENT. o Added PLAY FM. o Added MUSIC.FM_ENABLED and MUSIC.FM_AVAILABLE. + o Added C-style preprocessor (contributed by visrealm) o Allows using PALETTE on MSX games, but only applies on MSX2. o Z80: Optimization in multiple array access in @@ -1534,10 +1535,10 @@ The expression parser will take advantage of 8-bit variables and numbers to opti >>>>>>>>>>>>>> Preprocessor -The preprocessor can be used to confitionnaly include or exclude +The preprocessor can be used to conditionaly include or exclude CVBasic code from being compiled. This can be useful for including -platform-dependant user instructions or to enable or disable -diagnostics displays. +platform-dependent code or to enable and disable diagnostics +displays. #IF [NOT] constant [statement] @@ -1548,7 +1549,7 @@ diagnostics displays. #ENDIF Unlike regular IF-THEN-ELSE statements, the excluded code is not -compiled at all so will not take up additional space in your compiled +compiled at all so it won't take up additional space in your compiled rom image. One of the following pre-defined constants will be available and @@ -1571,12 +1572,13 @@ Compile-time logging: #INFO string Output an information message at compile time. - #WARN string + #WARNING string Output a warning message at compile time. #ERROR string Output an error message and halt compilation at compile time. + >>>>>>>>>>>>>>. FM support for MSX/MSX2/SMS CVBasic supports FM synthesis for MSX/MSX2 computers, and Sega Master System consoles