diff --git a/package-lock.json b/package-lock.json index f371ddf4..7cd08009 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "8bitworkshop", - "version": "3.10.2", + "version": "3.11.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "8bitworkshop", - "version": "3.10.2", + "version": "3.11.0", "license": "GPL-3.0", "dependencies": { "@types/chroma-js": "^2.1.3", @@ -66,25 +66,98 @@ "optional": true }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "devOptional": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "devOptional": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "devOptional": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "devOptional": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "devOptional": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "devOptional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "devOptional": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "optional": true, "dependencies": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -92,77 +165,77 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "optional": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "optional": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "optional": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "optional": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "optional": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "devOptional": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "devOptional": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -241,9 +314,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "optional": true, "bin": { "parser": "bin/babel-parser.js" @@ -253,33 +326,33 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "optional": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "optional": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -288,13 +361,13 @@ } }, "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "optional": true, "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2624,9 +2697,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "optional": true, "engines": { "node": "*" @@ -6903,79 +6976,139 @@ "optional": true }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "devOptional": true, "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "devOptional": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "devOptional": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "devOptional": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "devOptional": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "devOptional": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "devOptional": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "devOptional": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "optional": true, "requires": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "optional": true }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "optional": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "optional": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "optional": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "optional": true }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "devOptional": true }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "devOptional": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -7038,48 +7171,48 @@ } }, "@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "optional": true }, "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "optional": true, "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "optional": true, "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "optional": true, "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -8931,9 +9064,9 @@ "devOptional": true }, "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "optional": true }, "get-intrinsic": { diff --git a/package.json b/package.json index 52765556..308e13ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "8bitworkshop", - "version": "3.10.2", + "version": "3.11.0", "author": "Steven Hugg", "category": "Development", "description": "8bitworkshop.com retro programming IDE", diff --git a/presets/vcs/vcslib/bcd.h b/presets/vcs/vcslib/bcd.h new file mode 100644 index 00000000..3c923c8d --- /dev/null +++ b/presets/vcs/vcslib/bcd.h @@ -0,0 +1,19 @@ + +#ifndef _BCD_H +#define _BCD_H + +#define BCD_ADD(a,b) { \ + int _temp = (b); \ + asm("sed"); \ + (a) += _temp; \ + asm("cld"); \ + } + +#define BCD_SUB(a,b) { \ + int _temp = (b); \ + asm("sed"); \ + (a) -= _temp; \ + asm("cld"); \ + } + +#endif diff --git a/presets/vcs/vcslib/bitmap48.ca65 b/presets/vcs/vcslib/bitmap48.ca65 new file mode 100644 index 00000000..099f99a7 --- /dev/null +++ b/presets/vcs/vcslib/bitmap48.ca65 @@ -0,0 +1,115 @@ + +.include "vcs-ca65.inc" +.importzp tmp1, tmp2 +.import _reset_sprites +.import Return + +.export _bitmap48_kernel +.export _bitmap48_setup +.export _bitmap48_setaddress +.export _bitmap48_setheight +.export _bitmap48_ptr_0, _bitmap48_ptr_1, _bitmap48_ptr_2, _bitmap48_ptr_3, _bitmap48_ptr_4, _bitmap48_ptr_5 + +LoopCount = tmp1 +Temp = tmp2 +FontBuf = $1000 ;unused + +; when the first STA GRP1 of the sequence happens +.define B48_CYCLE 42 + +; this will get loaded into RAM +; so we can change the offsets +.segment "XDATA" + +; Display the resulting 48x5 bitmap from FontBuf +_bitmap48_kernel: + sta WSYNC + sta LoopCount + dec LoopCount +b48loop: + ldy LoopCount ; counts backwards + sta WSYNC ; sync to next scanline +_bitmap48_ptr_0 = *+1 + lda FontBuf+0,y ; load B0 (1st sprite byte) + sta GRP0 ; B0 -> [GRP0] +_bitmap48_ptr_1 = *+1 + lda FontBuf+5,y ; load B1 -> A + sta GRP1 ; B1 -> [GRP1], B0 -> GRP0 +_bitmap48_ptr_2 = *+1 + lda FontBuf+10,y ; load B2 -> A + sta GRP0 ; B2 -> [GRP0], B1 -> GRP1 +_bitmap48_ptr_5 = *+1 + lda FontBuf+25,y ; load B5 -> A + sta Temp ; B5 -> temp +_bitmap48_ptr_4 = *+1 + ldx FontBuf+20,y ; load B4 -> X +_bitmap48_ptr_3 = *+1 + lda FontBuf+15,y ; load B3 -> A + ldy Temp ; load B5 -> Y + sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0 + stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1 + sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0 + sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1 +b48dec: + dec LoopCount ; go to next line + bpl b48loop ; repeat until < 0 + jmp _reset_sprites + +; only used by _bitmap48_setaddress +_bitmap48_height: .byte 8 + +; TODO: can we write even when RAM not selected? +.proc _bitmap48_setaddress + sta _bitmap48_ptr_0+$400+0 + stx _bitmap48_ptr_0+$400+1 + jsr add_height_ax + sta _bitmap48_ptr_1+$400+0 + stx _bitmap48_ptr_1+$400+1 + jsr add_height_ax + sta _bitmap48_ptr_2+$400+0 + stx _bitmap48_ptr_2+$400+1 + jsr add_height_ax + sta _bitmap48_ptr_3+$400+0 + stx _bitmap48_ptr_3+$400+1 + jsr add_height_ax + sta _bitmap48_ptr_4+$400+0 + stx _bitmap48_ptr_4+$400+1 + jsr add_height_ax + sta _bitmap48_ptr_5+$400+0 + stx _bitmap48_ptr_5+$400+1 + rts +add_height_ax: + clc + adc _bitmap48_height + bcc :+ + inx +: rts +.endproc + +.proc _bitmap48_setheight + sta _bitmap48_height+$400 + rts +.endproc + +.code +.proc _bitmap48_setup + lda #THREE_COPIES + sta NUSIZ0 + sta NUSIZ1 + sta WSYNC + SLEEPR B48_CYCLE-7 + sta RESP0 + sta RESP1 + sta HMCLR + lda #$10 + sta HMP1 + sta WSYNC + sta HMOVE + lda #1 + sta VDELP0 + sta VDELP1 + sta REFP0 + sta REFP1 + rts +.endproc + diff --git a/presets/vcs/vcslib/demo_kernels.ca65 b/presets/vcs/vcslib/demo_kernels.ca65 new file mode 100644 index 00000000..94ad8346 --- /dev/null +++ b/presets/vcs/vcslib/demo_kernels.ca65 @@ -0,0 +1,81 @@ + +.include "vcs-ca65.inc" + +.setcpu "6502x" +.macpack longbranch + +.global _kernel_2pp_4pfa +.global _kernel_2pfasync + +.importzp _k_height +.importzp _k_ypos +.importzp _k_bitmap +.importzp _k_colormap +.importzp _k_playfield +.importzp tmp1 +.import _k_asyncpf +.import _reset_gfx + +_k_pftmp = tmp1 ; no one's using this just now, right? + +.include "kernel.inc" + +.code + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Display Kernel +; - two double-line players w/ colormap +; - two missiles, variable height +; - versatile playfield, 4 lines per change (no cross page) +; Modifies: _k_ypos, _k_playfield +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +.proc _kernel_2pp_4pfa + tay + ldx #0 +@loop: +; first two lines, fetch PF0 and PF1 + DO_PCOLOR 0 + DO_PCOLOR 1 + DO_DRAW 0,1 + DO_DRAW 1,0 + DO_MISSILE 2 + DO_MISSILE_NOP 3 + DO_VERSATILE_PF_1 + dey +; second two lines, fetch PF2 and write PF registers + DO_PCOLOR 0 + DO_PCOLOR 1 + DO_DRAW 0,1 + DO_DRAW 1,0 + DO_MISSILE_NOP 2 + DO_MISSILE 3 + DO_VERSATILE_PF_2 + dey + jne @loop + jmp _reset_gfx +.endproc + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Display Kernel +; - async playfield, 6 lines per change +; - playfield data should be page-aligned +; Modifies: _k_playfield +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +.proc _kernel_2pfasync + tay +loop2: + dey + ldx #5 +loop: + DO_PFWRITE_2 + DO_WSYNC + lda _k_asyncpf,y + sta _k_pftmp,x + DO_PFWRITE + stx COLUPF ; fun vfx rainbow + dex + bmi loop2 + dey + jne loop + jmp _reset_gfx +.endproc diff --git a/presets/vcs/vcslib/demo_sounds.c b/presets/vcs/vcslib/demo_sounds.c new file mode 100644 index 00000000..d65b099f --- /dev/null +++ b/presets/vcs/vcslib/demo_sounds.c @@ -0,0 +1,115 @@ + +#include + +#define NSOUNDS 8 + +#pragma code-name (push, "ROM3") +#pragma rodata-name (push, "ROM3") + +#define AUDF(x) ((x)) +#define AUDV(x) ((x)*2+0x81) // 0..15 +#define AUDC(x) ((x)*2+0x80) // 0..15 + +// music note envelope +const byte sound_0[] = { + AUDV(1), AUDV(2), AUDV(3), AUDV(4), AUDV(6), // decay + AUDV(8), AUDV(9), AUDV(10), // sustain + AUDV(12), AUDV(6), AUDV(3), // attack +}; + +// bass drum +const byte sound_1[] = { + AUDV(2),AUDV(4),AUDV(6),0x2,AUDC(2),AUDV(8) +}; + +// snare +const byte sound_2[] = { + AUDV(3),AUDV(4),AUDV(5),AUDV(6),AUDV(7),0x7,AUDC(8),AUDV(8) +}; + +// tom +const byte sound_3[] = { + 0x1f,0x1e,0x1d,0x1c,0x1b,AUDC(12),AUDV(8),0x18 +}; + +// crash cymbal +const byte sound_4[] = { + AUDV(1),AUDV(2),AUDV(3),AUDV(4),AUDV(5),AUDV(6),AUDV(7),AUDV(8),0x1,AUDC(8),AUDV(9) +}; + +// high cowbell +const byte sound_5[] = { + AUDV(2),AUDV(4),AUDV(6),AUDC(7),AUDV(8),0x2 +}; + +// low cowbell +const byte sound_6[] = { + AUDV(2),AUDV(4),AUDV(6),AUDC(7),AUDV(8),0x3 +}; + +// sound effects +const byte sound_sfx_1[] = { + 0x02,0x03,0x04,0x08,0x10,0x20,0x10,0x20,0x10,AUDC(4),AUDV(8) +}; + +const byte sound_duration[NSOUNDS] = { + sizeof(sound_0), + sizeof(sound_1), + sizeof(sound_2), + sizeof(sound_3), + sizeof(sound_4), + sizeof(sound_5), + sizeof(sound_6), + sizeof(sound_sfx_1), +}; + +const byte* const sound_data[NSOUNDS] = { + sound_0, + sound_1, + sound_2, + sound_3, + sound_4, + sound_5, + sound_6, + sound_sfx_1, +}; + +const byte music_1[] = { +// MUSIC DATA - "The Easy Winners" by Scott Joplin +0x2A, 0x1E, 0x98, 0x33, 0x27, 0xA4, 0x31, 0x25, 0x8C, 0x2F, 0x23, +0x8C, 0x2E, 0x22, 0x8C, 0x2C, 0x20, 0x8C, 0x2A, 0x1E, 0x98, 0x28, 0x1C, 0x8C, 0x27, 0x1B, 0x98, +0x25, 0x19, 0x8C, 0x23, 0x17, 0x8C, 0x22, 0x12, 0x8C, 0x23, 0x8C, 0x25, 0x8C, 0x27, 0x8C, 0x28, +0x1E, 0x8C, 0x2A, 0x1C, 0x8C, 0x2C, 0x1B, 0x8C, 0x2E, 0x19, 0x8C, 0x2F, 0x17, 0x98, 0x1E, 0x98, +0x12, 0x98, 0x1E, 0x98, 0x2F, 0x17, 0x98, 0x33, 0x27, 0x98, 0x12, 0x98, 0x36, 0x1E, 0x98, 0x38, +0x17, 0x8C, 0x36, 0x8C, 0x1E, 0x8C, 0x38, 0x8C, 0x33, 0x12, 0x8C, 0x38, 0x8C, 0x36, 0x1E, 0x98, +0x3D, 0x10, 0x8C, 0x3B, 0x8C, 0x20, 0x8C, 0x37, 0x8C, 0x3B, 0x10, 0x8C, 0x3D, 0x8C, 0x3B, 0x28, +0x8C, 0x36, 0x8C, 0x17, 0x98, 0x2A, 0x1E, 0x8C, 0x2C, 0x8C, 0x2E, 0x12, 0x8C, 0x2F, 0x8C, 0x31, +0x1E, 0x8C, 0x32, 0x8C, 0x33, 0x17, 0x98, 0x33, 0x1E, 0x98, 0x12, 0x98, 0x33, 0x1E, 0x98, 0x38, +0x17, 0x8C, 0x36, 0x8C, 0x27, 0x8C, 0x38, 0x8C, 0x36, 0x18, 0x8C, 0x36, 0x8C, 0x33, 0x21, 0x98, +0x36, 0x19, 0x8C, 0x2E, 0x8C, 0x22, 0x8C, 0x36, 0x8C, 0x2F, 0x19, 0x8C, 0x36, 0x8C, 0x2F, 0x25, +0x98, 0x2E, 0x1E, 0x98, 0x1C, 0x98, 0x1B, 0x8C, 0x2A, 0x8C, 0x2E, 0x25, 0x8C, 0x34, 0x8C, 0x33, +0x17, 0x98, 0x33, 0x1E, 0x98, 0x12, 0x98, 0x33, 0x27, 0x98, 0x38, 0x17, 0x8C, 0x36, 0x8C, 0x1E, +0x8C, 0x38, 0x8C, 0x36, 0x12, 0x8C, 0x38, 0x8C, 0x33, 0x1E, 0x98, 0x3D, 0x10, 0x8C, 0x3B, 0x8C, +0x20, 0x8C, 0x3D, 0x8C, 0x3B, 0x1C, 0x8C, 0x3B, 0x8C, 0x38, 0x1C, 0x8C, 0x3F, 0x8C, 0x1B, 0x8C, +0x33, 0x8C, 0x37, 0x22, 0x8C, 0x3A, 0x8C, 0x3F, 0x0F, 0x98, 0x3A, 0x8C, 0x3B, 0x8C, 0x3D, 0x10, +0x8C, 0x3B, 0x8C, 0x20, 0x8C, 0x3D, 0x8C, 0x38, 0x10, 0x8C, 0x3D, 0x8C, 0x3B, 0x28, 0x8C, 0x36, +0x8C, 0x17, 0x8C, 0x34, 0x8C, 0x36, 0x1E, 0x8C, 0x34, 0x8C, 0x33, 0x17, 0x8C, 0x36, 0x8C, 0x27, +0x8C, 0x36, 0x8C, 0x30, 0x12, 0x8C, 0x34, 0x8C, 0x1E, 0x8C, 0x36, 0x8C, 0x34, 0x12, 0x8C, 0x33, +0x8C, 0x28, 0x1E, 0x98, 0x2F, 0x1E, 0x98, 0x12, 0x98, 0x17, +0xff, +}; + +//const byte music_2[] = { +// 0x38,0x8c,0x3a,0x88,0x20,0x81,0x23,0x82,0x28,0x81,0x3b,0x32,0x2c,0xa4,0x3a,0x8c,0x38,0x32,0x2c,0x91,0x1f,0x83,0x22,0x83,0x27,0x81,0x37,0x31,0x2e,0xa4,0x35,0x2c,0x8c,0x37,0x31,0x2e,0x90,0x20,0x83,0x23,0x83,0x27,0x82,0x38,0x2f,0x27,0xbf,0x85,0x20,0x81,0x23,0x82,0x27,0x81,0x38,0x2f,0x27,0xb0,0x2c,0x2c,0x20,0x98,0x2f,0x2c,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x8c,0x31,0x2e,0x27,0x98,0x33,0x2f,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x34,0x31,0x20,0x8c,0x33,0x2f,0x27,0x98,0x31,0x2e,0x2a,0x8c,0x1e,0x8c,0x22,0x8c,0x1e,0x8c,0x2e,0x2a,0x25,0x98,0x2a,0x2a,0x2a,0x8c,0x1e,0x8c,0x22,0x8c,0x2c,0x2c,0x29,0x8c,0x2e,0x2e,0x28,0x98,0x2f,0x2c,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x8c,0x2c,0x27,0x23,0x98,0x2c,0x26,0x23,0x8c,0x1c,0x8c,0x23,0x8c,0x2b,0x22,0x20,0x8c,0x2c,0x26,0x20,0x98,0x2e,0x27,0x1f,0x8c,0x1b,0x8c,0x1f,0x8c,0x1b,0x8c,0x22,0x8c,0x1f,0x8c,0x27,0x27,0x1f,0x8c,0x22,0x8c,0x2b,0x98,0x2c,0x2c,0x20,0x98,0x2f,0x2c,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x8c,0x31,0x2e,0x27,0x98,0x33,0x2f,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x34,0x31,0x20,0x8c,0x33,0x2f,0x27,0x98,0x31,0x2e,0x2a,0x8c,0x1e,0x8c,0x22,0x8c,0x1e,0x8c,0x2e,0x2a,0x25,0x98,0x2a,0x2a,0x2a,0x8c,0x1e,0x8c,0x22,0x8c,0x2c,0x2c,0x29,0x8c,0x2e,0x2e,0x28,0x98,0x2f,0x2c,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x2e,0x25,0x20,0x8c,0x2c,0x27,0x23,0x98,0x2b,0x27,0x22,0x8c,0x1b,0x8c,0x22,0x8c,0x29,0x20,0x1f,0x8c,0x2b,0x27,0x22,0x98,0x2c,0x27,0x23,0x8c,0x1b,0x8c,0x20,0x8c,0x1b,0x8c,0x27,0x8c,0x23,0x8c,0x2c,0x27,0x23,0x8c,0x1b,0x8c,0x20,0x8c,0x22,0x8c,0x23,0x8c,0x27,0x8c,0x36,0x33,0x2a,0x8c,0x23,0x8c,0x2a,0x8c,0x27,0x8c,0x1e,0x8c,0x23,0x8c,0x36,0x33,0x2a,0x8c,0x27,0x8c,0x2a,0x8c,0x35,0x31,0x27,0x8c,0x33,0x2f,0x2a,0x8c,0x23,0x8c,0x31,0x2e,0x2a,0x8c,0x22,0x8c,0x2a,0x8c,0x25,0x8c,0x2e,0x2a,0x25,0x8c,0x22,0x8c,0x2a,0x2a,0x2a,0x8c,0x25,0x8c,0x2a,0x8c,0x2c,0x2c,0x29,0x8c,0x2e,0x2e,0x28,0x8c,0x22,0x8c,0x2f,0x2c,0x27,0x8c,0x23,0x8c,0x27,0x8c,0x23,0x8c,0x2c,0x27,0x23,0x8c,0x23,0x8c,0x2c,0x26,0x23,0x8c,0x23,0x8c,0x28,0x8c,0x2b,0x22,0x23,0x8c,0x2c,0x26,0x20,0x8c,0x23,0x8c,0x2e,0x27,0x1f,0x8c,0x1f,0x8c,0x22,0x8c,0x27,0x8c,0x2b,0x27,0x22,0x8c,0x1f,0x8c,0x27,0x27,0x27,0x8c,0x22,0x8c,0x27,0x8c,0x2b,0x8c,0x27,0x8c,0x22,0x8c,0x36,0x33,0x2a,0x8c,0x23,0x8c,0x27,0x8c,0x2a,0x8c,0x23,0x8c,0x27,0x8c,0x36,0x33,0x2a,0x8c,0x23,0x8c,0x27,0x8c,0x35,0x31,0x2a,0x8c,0x33,0x2f,0x2a,0x8c,0x27,0x8c,0x31,0x2e,0x2a,0x8c,0x22,0x8c,0x25,0x8c,0x2a,0x8c,0x2e,0x2a,0x25,0x8c,0x25,0x8c,0x2a,0x2a,0x2a,0x8c,0x22,0x8c,0x25,0x8c,0x2c,0x2c,0x29,0x8c,0x2e,0x2e,0x28,0x8c,0x22,0x8c,0x2f,0x2c,0x27,0x8c,0x23,0x8c,0x27,0x8c,0x2e,0x25,0x20,0x8c,0x2c,0x27,0x23,0x8c,0x23,0x8c,0x2b,0x27,0x22,0x8c,0x22,0x8c,0x27,0x8c,0x29,0x20,0x2b,0x8c,0x2b,0x27,0x22,0x8c,0x22,0x8c,0x2c,0x27,0x23,0x8c,0x23,0x8c,0x28,0x25,0x25,0x8c,0x20,0x8c,0x25,0x22,0x28,0x8c,0x25,0x8c,0x2c,0x27,0x23,0xb0,0x38,0x8c,0x3a,0x88,0x20,0x81,0x23,0x82,0x28,0x81,0x3b,0x32,0x2c,0xa4,0x3a,0x8c,0x38,0x32,0x2c,0x91,0x1f,0x83,0x22,0x83,0x27,0x81,0x37,0x31,0x2e,0xa4,0x35,0x2c,0x8c,0x37,0x31,0x2e,0x90,0x20,0x83,0x23,0x83,0x27,0x82,0x38,0x2f,0x27,0xbf,0x85,0x20,0x81,0x23,0x82,0x27,0x81,0x38,0x2f,0x27,0xb0,0x20,0x98,0x23,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x8c,0x25,0x27,0x98,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x28,0x20,0x8c,0x27,0x27,0x98,0x25,0x8c,0x1e,0x8c,0x22,0x8c,0x1e,0x8c,0x22,0x25,0x98,0x1e,0x8c,0x1e,0x8c,0x22,0x8c,0x20,0x1e,0x8c,0x22,0x25,0x98,0x23,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x8c,0x20,0x27,0x98,0x20,0x8c,0x1c,0x8c,0x23,0x8c,0x1f,0x20,0x8c,0x20,0x28,0x98,0x22,0x8c,0x1b,0x8c,0x1f,0x8c,0x1b,0x8c,0x22,0x8c,0x1f,0x8c,0x1b,0x27,0x8c,0x22,0x8c,0x2b,0x98,0x20,0x98,0x23,0x20,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x8c,0x25,0x27,0x98,0x27,0x8c,0x1b,0x8c,0x23,0x8c,0x28,0x20,0x8c,0x27,0x27,0x98,0x25,0x8c,0x1e,0x8c,0x22,0x8c,0x1e,0x8c,0x22,0x25,0x98,0x1e,0x8c,0x1e,0x8c,0x22,0x8c,0x20,0x1e,0x8c,0x22,0x25,0x98,0x23,0x8c,0x1b,0x8c,0x23,0x8c,0x22,0x20,0x8c,0x20,0x27,0x98,0x1f,0x8c,0x1b,0x8c,0x22,0x8c,0x1d,0x1f,0x8c,0x1f,0x27,0x98,0x20,0x8c,0x1b,0x8c,0x20,0x8c,0x1b,0x8c,0x27,0x8c,0x23,0x8c,0x20,0x20,0x8c,0x1b,0x8c,0x20,0x8c,0x22,0x8c,0x23,0x8c,0x27,0x8c,0x27,0x2a,0x20,0x8c,0x23,0x8c,0x2a,0x8c,0x27,0x8c,0x1e,0x8c,0x23,0x8c,0x27,0x2a,0x1e,0x8c,0x27,0x8c,0x2a,0x8c,0x29,0x25,0x27,0x8c,0x23,0x27,0x1e,0x8c,0x23,0x8c,0x25,0x22,0x1e,0x8c,0x22,0x8c,0x2a,0x8c,0x25,0x8c,0x22,0x1e,0x1e,0x8c,0x22,0x8c,0x1e,0x1e,0x8c,0x25,0x8c,0x2a,0x8c,0x20,0x25,0x8c,0x22,0x1f,0x8c,0x22,0x8c,0x23,0x20,0x8c,0x23,0x8c,0x27,0x8c,0x23,0x8c,0x20,0x20,0x8c,0x23,0x8c,0x20,0x1c,0x8c,0x23,0x8c,0x28,0x8c,0x1f,0x23,0x8c,0x20,0x20,0x8c,0x23,0x8c,0x22,0x1b,0x8c,0x1f,0x8c,0x22,0x8c,0x27,0x8c,0x1f,0x22,0x8c,0x1f,0x8c,0x1b,0x1f,0x8c,0x22,0x8c,0x27,0x8c,0x2b,0x8c,0x27,0x8c,0x22,0x8c,0x2a,0x27,0x1e,0x8c,0x23,0x8c,0x27,0x8c,0x2a,0x8c,0x23,0x8c,0x27,0x8c,0x27,0x2a,0x1e,0x8c,0x23,0x8c,0x27,0x8c,0x29,0x25,0x2a,0x8c,0x27,0x23,0x23,0x8c,0x27,0x8c,0x25,0x22,0x1e,0x8c,0x22,0x8c,0x25,0x8c,0x2a,0x8c,0x22,0x1e,0x22,0x8c,0x25,0x8c,0x1e,0x1e,0x8c,0x22,0x8c,0x25,0x8c,0x20,0x2a,0x8c,0x22,0x1f,0x8c,0x22,0x8c,0x23,0x20,0x8c,0x23,0x8c,0x27,0x8c,0x22,0x20,0x8c,0x20,0x2c,0x8c,0x23,0x8c,0x1f,0x1b,0x8c,0x22,0x8c,0x27,0x8c,0x1d,0x2b,0x8c,0x1f,0x1f,0x8c,0x22,0x8c,0x20,0x1b,0x8c,0x23,0x8c,0x25,0x8c,0x20,0x8c,0x28,0x8c,0x25,0x8c,0x20,0x27,0xb0,0x38,0x8c,0x3a,0x88,0x20,0x81,0x23,0x82,0x28,0x81,0x3b,0x32,0x2c,0xa4,0x3a,0x8c,0x38,0x32,0x2c,0x91,0x1f,0x83,0x22,0x83,0x27,0x81,0x37,0x31,0x2e,0xa4,0x35,0x2c,0x8c,0x37,0x31,0x2e,0x90,0x20,0x83,0x23,0x83,0x27,0x82,0x38,0x2f,0x27,0xbf,0x85,0x20,0x81,0x23,0x82,0x27,0x81,0x38,0x27,0x2f,0x81,0x2f,0xaf,0x2c,0x82,0x2c,0x96,0x33,0x2c,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x87,0x2e,0x85,0x27,0x97,0x2f,0x8d,0x1b,0x8c,0x23,0x8a,0x31,0x82,0x20,0x8b,0x2f,0x33,0x81,0x27,0x97,0x2e,0x36,0x8d,0x1e,0x8c,0x22,0x8c,0x1e,0x8a,0x2a,0x81,0x31,0x81,0x25,0x97,0x25,0x83,0x36,0x8a,0x1e,0x8c,0x22,0x8a,0x2c,0x82,0x35,0x1e,0x8c,0x34,0x25,0x81,0x2e,0x97,0x33,0x82,0x2c,0x8a,0x1b,0x8c,0x23,0x8c,0x20,0x88,0x2f,0x27,0x84,0x27,0x95,0x26,0x81,0x2f,0x8e,0x1c,0x8c,0x23,0x89,0x2e,0x83,0x20,0x88,0x26,0x82,0x2c,0x82,0x28,0x97,0x27,0x81,0x2b,0x8c,0x1b,0x8c,0x1f,0x8c,0x1b,0x8c,0x22,0x8c,0x1f,0x8b,0x22,0x81,0x27,0x8c,0x22,0x8c,0x2b,0x97,0x2c,0x2c,0x99,0x2c,0x33,0x20,0x8c,0x1b,0x8c,0x23,0x8c,0x20,0x88,0x2e,0x84,0x27,0x94,0x2f,0x90,0x1b,0x8c,0x23,0x8b,0x31,0x81,0x20,0x8b,0x2f,0x33,0x81,0x27,0x95,0x2e,0x81,0x36,0x8e,0x1e,0x8c,0x22,0x8c,0x1e,0x88,0x31,0x82,0x2a,0x82,0x25,0x97,0x36,0x81,0x2a,0x8c,0x1e,0x8c,0x22,0x8b,0x2c,0x35,0x81,0x1e,0x8c,0x2e,0x25,0x81,0x34,0x97,0x2c,0x81,0x33,0x8b,0x1b,0x8c,0x23,0x8b,0x31,0x81,0x20,0x8a,0x27,0x82,0x2f,0x27,0x97,0x2e,0x81,0x27,0x8c,0x1b,0x8c,0x22,0x8b,0x2c,0x81,0x1f,0x8a,0x27,0x82,0x2e,0x27,0x97,0x27,0x82,0x2f,0x8b,0x1b,0x8c,0x20,0x8c,0x1b,0x8c,0x27,0x8c,0x23,0x8b,0x2f,0x81,0x20,0x81,0x27,0x8b,0x1b,0x8c,0x20,0x8c,0x22,0x8c,0x23,0x8c,0x27,0x8c,0x20,0x8c,0x27,0x23,0x8c,0x2a,0x2a,0x8c,0x2f,0x27,0x8c,0x33,0x1e,0x8c,0x23,0x8c,0x1e,0x8c,0x27,0x27,0x8c,0x2a,0x23,0x8c,0x2f,0x25,0x8c,0x33,0x27,0x8c,0x29,0x8c,0x1e,0x8c,0x25,0x22,0x8c,0x2a,0x2a,0x8c,0x2e,0x25,0x8c,0x31,0x1e,0x8c,0x22,0x8c,0x1e,0x8c,0x25,0x25,0x8c,0x2a,0x2a,0x8c,0x2e,0x25,0x8c,0x31,0x1f,0x8c,0x22,0x8c,0x20,0x8c,0x23,0x23,0x8c,0x27,0x27,0x8c,0x2c,0x23,0x8c,0x2f,0x20,0x8c,0x23,0x8c,0x1c,0x8c,0x23,0x23,0x8c,0x28,0x28,0x8c,0x2c,0x23,0x8c,0x2f,0x20,0x8c,0x23,0x8c,0x1b,0x8c,0x22,0x1f,0x8c,0x27,0x22,0x8c,0x2b,0x27,0x8c,0x2e,0x22,0x8c,0x1f,0x8c,0x1f,0x8c,0x27,0x22,0x8c,0x2b,0x27,0x8c,0x2e,0x2b,0x8c,0x33,0x27,0x8c,0x22,0x8c,0x1e,0x8c,0x27,0x23,0x8c,0x2a,0x27,0x8c,0x2f,0x2a,0x8c,0x33,0x23,0x8c,0x27,0x8c,0x1e,0x8c,0x27,0x27,0x8c,0x2a,0x23,0x8c,0x2f,0x25,0x8c,0x33,0x27,0x8c,0x29,0x8c,0x1e,0x8c,0x25,0x22,0x8c,0x2a,0x25,0x8c,0x2e,0x2a,0x8c,0x31,0x22,0x8c,0x25,0x8c,0x1e,0x8c,0x25,0x22,0x8c,0x2a,0x25,0x8c,0x2e,0x2a,0x8c,0x2e,0x1f,0x8c,0x22,0x8c,0x2f,0x20,0x8c,0x23,0x8c,0x27,0x8c,0x2e,0x20,0x8c,0x2c,0x2c,0x8c,0x23,0x8c,0x2b,0x1b,0x8c,0x22,0x8c,0x27,0x8c,0x29,0x2b,0x8c,0x2b,0x1f,0x8c,0x22,0x8c,0x2c,0x1b,0x8c,0x23,0x8c,0x25,0x8c,0x20,0x8c,0x28,0x8c,0x25,0x8c,0x2c,0x27,0xb0,0x38,0x2c,0x8c,0x3a,0x2e,0x88,0x20,0x81,0x23,0x82,0x28,0x81,0x3b,0x2f,0x2c,0xa4,0x3a,0x2e,0x8c,0x38,0x2c,0x91,0x1f,0x83,0x22,0x83,0x27,0x81,0x37,0x2b,0x2b,0xa4,0x35,0x29,0x8c,0x37,0x2b,0x90,0x20,0x83,0x23,0x83,0x27,0x82,0x38,0x2c,0x2c,0xbf,0x85,0x20,0x81,0x23,0x82,0x27,0x81,0x38,0x2c,0x2f,0xff +// 0x27,0x90,0x2c,0x8f,0x2f,0x8f,0x33,0x8f,0x38,0x8f,0x3b,0x8f,0x20,0x23,0x88,0x3a,0x83,0x38,0x82,0x37,0x83,0x38,0x20,0x8f,0x20,0x23,0x8f,0x2e,0x27,0x8f,0x33,0x8f,0x37,0x8f,0x3a,0x90,0x3d,0x8f,0x1f,0x22,0x87,0x3b,0x83,0x3a,0x82,0x38,0x83,0x3a,0x1f,0x8f,0x1f,0x22,0x8e,0x33,0x81,0x3b,0x8f,0x27,0x23,0x88,0x3a,0x82,0x38,0x83,0x37,0x82,0x38,0x20,0x90,0x20,0x23,0x8e,0x33,0x81,0x3d,0x8f,0x22,0x25,0x88,0x3b,0x82,0x3a,0x83,0x38,0x82,0x3a,0x22,0x8f,0x2b,0x25,0x8f,0x33,0x38,0x90,0x23,0x27,0x8f,0x3d,0x87,0x3b,0x88,0x3a,0x25,0x87,0x38,0x86,0x37,0x38,0x81,0x3a,0x81,0x38,0x8f,0x37,0x27,0x9f,0x16,0x8f,0x1b,0x8f,0x1e,0x8f,0x22,0x8f,0x27,0x8f,0x2a,0x97,0x29,0x83,0x27,0x82,0x26,0x83,0x27,0x8f,0x27,0x8f,0x2f,0x27,0x97,0x36,0x82,0x34,0x83,0x33,0x82,0x34,0x8f,0x34,0x90,0x34,0x25,0x96,0x31,0x83,0x2f,0x82,0x2e,0x83,0x2f,0x8f,0x2f,0x8f,0x2e,0x25,0x97,0x36,0x82,0x34,0x83,0x33,0x83,0x34,0x8f,0x34,0x8f,0x2f,0x2a,0x97,0x34,0x82,0x33,0x83,0x32,0x82,0x33,0x8f,0x33,0x8f,0x33,0x2c,0x90,0x31,0x8f,0x29,0x8f,0x2f,0x8f,0x2e,0x2a,0x8f,0x36,0x8f,0x34,0x90,0x33,0x2a,0x8f,0x2c,0x28,0x8f,0x31,0x8f,0x2c,0x29,0x8f,0x2f,0x8f,0x2e,0x2a,0x90,0x2a,0x36,0x8f,0x34,0x28,0x8f,0x27,0x33,0x8f,0x1c,0x20,0x8f,0x25,0x31,0x8f,0x20,0x1d,0x8f,0x23,0x2f,0x90,0x22,0x2e,0x87,0x2a,0x88,0x1e,0x87,0x2a,0x88,0x1e,0x88,0x2a,0x87,0x37,0x1e,0x88,0x2a,0x87,0x36,0x1e,0x88,0x2a,0x87,0x34,0x1e,0x88,0x2a,0x88,0x31,0x1e,0x87,0x2a,0x88,0x2e,0x1e,0x87,0x2a,0x88,0x2b,0x28,0x8f,0x1e,0x88,0x2a,0x87,0x2f,0x27,0x88,0x2a,0x87,0x37,0x1e,0x88,0x2a,0x88,0x36,0x1e,0x87,0x2a,0x88,0x34,0x1e,0x87,0x2a,0x88,0x31,0x1e,0x87,0x2a,0x88,0x2e,0x1e,0x88,0x2a,0x87,0x2b,0x28,0x8f,0x1e,0x88,0x2a,0x87,0x2f,0x27,0x88,0x2a,0x88,0x37,0x1e,0x87,0x2a,0x88,0x36,0x1e,0x87,0x2a,0x88,0x34,0x1e,0x88,0x2a,0x87,0x31,0x28,0x88,0x2a,0x87,0x2e,0x28,0x88,0x2a,0x87,0x27,0x88,0x2e,0x2a,0x88,0x31,0x27,0x87,0x2f,0x2a,0x88,0x22,0x87,0x30,0x2a,0x88,0x33,0x22,0x87,0x31,0x2a,0x88,0x23,0x88,0x32,0x2a,0x87,0x34,0x23,0x88,0x33,0x2a,0x87,0x20,0x88,0x35,0x29,0x88,0x3b,0x23,0x87,0x35,0x29,0x88,0x36,0x1e,0x87,0x2a,0x88,0x22,0x87,0x2a,0x88,0x20,0x88,0x35,0x29,0x87,0x3b,0x23,0x88,0x35,0x29,0x87,0x36,0x1e,0x88,0x2a,0x87,0x22,0x88,0x2a,0x88,0x1c,0x87,0x3a,0x25,0x88,0x43,0x1f,0x87,0x3a,0x25,0x88,0x3b,0x1b,0x88,0x23,0x87,0x1e,0x88,0x23,0x87,0x1c,0x88,0x3a,0x25,0x87,0x43,0x1f,0x88,0x3a,0x25,0x88,0x1b,0x87,0x3a,0x23,0x88,0x3d,0x1e,0x87,0x3b,0x23,0x88,0x16,0x87,0x3c,0x22,0x88,0x3f,0x1e,0x88,0x3d,0x22,0x87,0x17,0x88,0x3e,0x23,0x87,0x40,0x1e,0x88,0x3f,0x23,0x88,0x19,0x87,0x3f,0x25,0x88,0x42,0x1e,0x87,0x40,0x25,0x88,0x1b,0x87,0x41,0x88,0x44,0x1e,0x88,0x42,0x87,0x40,0x88,0x3f,0x87,0x3d,0x23,0x88,0x3b,0x87,0x3a,0x1c,0x88,0x38,0x88,0x36,0x20,0x87,0x34,0x88,0x33,0x87,0x31,0x88,0x2f,0x25,0x88,0x2e,0x87,0x2c,0x1e,0x88,0x2a,0x87,0x29,0x23,0x88,0x2a,0x87,0x29,0x88,0x2a,0x88,0x29,0x27,0x87,0x2a,0x88,0x29,0x28,0x87,0x2a,0x88,0x2c,0x25,0x87,0x2a,0x88,0x29,0x22,0x88,0x2a,0x87,0x2c,0x1c,0x88,0x2a,0x87,0x0f,0x88,0x3b,0x88,0x44,0x12,0x87,0x42,0x88,0x40,0x87,0x3f,0x88,0x3d,0x17,0x87,0x3b,0x88,0x3a,0x10,0x88,0x38,0x87,0x36,0x14,0x88,0x34,0x87,0x33,0x88,0x31,0x87,0x2f,0x19,0x88,0x2e,0x88,0x2c,0x12,0x87,0x2a,0x88,0x28,0x17,0x87,0x27,0x88,0x25,0x88,0x23,0x87,0x22,0x1b,0x88,0x20,0x87,0x1e,0x1c,0x88,0x20,0x87,0x22,0x19,0x88,0x23,0x88,0x25,0x16,0x87,0x27,0x88,0x28,0x12,0x87,0x25,0x88,0x23,0x17,0x8f,0x23,0x8e,0x29,0x81,0x32,0x8f,0x26,0x23,0x88,0x31,0x88,0x2f,0x8f,0x1e,0x23,0x8f,0x2e,0x8f,0x1e,0x25,0x88,0x36,0x87,0x36,0x8f,0x2f,0x23,0x8f,0x29,0x32,0x90,0x1d,0x20,0x87,0x31,0x88,0x2f,0x8f,0x27,0x23,0x8f,0x2e,0x8f,0x1e,0x25,0x88,0x36,0x87,0x36,0x90,0x2f,0x23,0x8e,0x35,0x81,0x3e,0x8f,0x29,0x2c,0x87,0x3d,0x88,0x3b,0x8f,0x2a,0x2f,0x8f,0x3a,0x90,0x34,0x31,0x87,0x42,0x88,0x34,0x3a,0xbc,0x33,0x36,0xae,0x2a,0x8f,0x2f,0x8f,0x33,0x8f,0x36,0x8f,0x3b,0x90,0x3f,0x8f,0x2a,0x27,0x87,0x3d,0x83,0x3b,0x82,0x3a,0x83,0x3b,0x23,0x8f,0x23,0x27,0x8e,0x34,0x81,0x40,0x8f,0x22,0x25,0x88,0x3f,0x82,0x3d,0x83,0x3c,0x83,0x3d,0x2a,0x8f,0x22,0x25,0x8f,0x31,0x8f,0x34,0x8f,0x3a,0x8f,0x3d,0x8f,0x34,0x40,0x90,0x22,0x25,0x87,0x3f,0x83,0x3d,0x82,0x3c,0x83,0x3d,0x22,0x8f,0x2b,0x28,0x8e,0x34,0x81,0x40,0x8f,0x21,0x25,0x88,0x3f,0x82,0x3d,0x83,0x3c,0x82,0x3d,0x21,0x90,0x2b,0x28,0x8f,0x3c,0x20,0x87,0x2c,0x88,0x20,0x87,0x2c,0x88,0x20,0x88,0x2c,0x87,0x39,0x20,0x88,0x2c,0x87,0x38,0x20,0x88,0x2c,0x88,0x36,0x20,0x87,0x2c,0x88,0x33,0x20,0x87,0x2c,0x88,0x30,0x20,0x87,0x2c,0x88,0x2d,0x2a,0x8f,0x20,0x88,0x2c,0x87,0x31,0x28,0x88,0x2c,0x87,0x39,0x20,0x88,0x2c,0x88,0x38,0x20,0x87,0x2c,0x88,0x36,0x20,0x87,0x2c,0x88,0x33,0x20,0x88,0x2c,0x87,0x30,0x20,0x88,0x2c,0x87,0x2d,0x2a,0x8f,0x20,0x88,0x2c,0x88,0x31,0x28,0x87,0x2c,0x88,0x39,0x20,0x87,0x2c,0x88,0x38,0x20,0x87,0x2c,0x88,0x36,0x20,0x88,0x2c,0x87,0x33,0x2a,0x88,0x2c,0x87,0x30,0x2a,0x88,0x2c,0x88,0x28,0x87,0x30,0x2c,0x88,0x33,0x28,0x87,0x31,0x2c,0x88,0x27,0x87,0x31,0x2c,0x88,0x34,0x27,0x88,0x33,0x2c,0x87,0x25,0x88,0x33,0x2c,0x87,0x36,0x25,0x88,0x34,0x2c,0x87,0x23,0x88,0x32,0x2d,0x88,0x35,0x23,0x87,0x33,0x2d,0x88,0x32,0x22,0x87,0x2e,0x88,0x22,0x88,0x2e,0x87,0x22,0x88,0x2e,0x87,0x3b,0x22,0x88,0x2e,0x87,0x3a,0x22,0x88,0x2e,0x88,0x38,0x22,0x87,0x2e,0x88,0x35,0x22,0x87,0x2e,0x88,0x32,0x22,0x87,0x2e,0x88,0x2f,0x2c,0x8f,0x22,0x88,0x2e,0x87,0x33,0x2a,0x88,0x2e,0x88,0x3b,0x22,0x87,0x2e,0x88,0x3a,0x22,0x87,0x2e,0x88,0x38,0x22,0x87,0x2e,0x88,0x35,0x22,0x88,0x2e,0x87,0x32,0x22,0x88,0x2e,0x87,0x2f,0x2c,0x8f,0x22,0x88,0x2e,0x88,0x33,0x2a,0x8f,0x2c,0x23,0x87,0x29,0x88,0x2c,0x22,0x88,0x29,0x87,0x2c,0x20,0x88,0x29,0x87,0x2c,0x1d,0x88,0x29,0x87,0x2c,0x1a,0x88,0x29,0x88,0x2c,0x17,0x87,0x29,0x88,0x32,0x2c,0x87,0x29,0x16,0x88,0x33,0x2a,0x87,0x27,0x88,0x2a,0x21,0x88,0x27,0x87,0x2a,0x20,0x88,0x27,0x87,0x2a,0x1e,0x88,0x27,0x88,0x2a,0x1b,0x87,0x27,0x88,0x2a,0x18,0x87,0x27,0x88,0x2a,0x15,0x87,0x27,0x88,0x30,0x2a,0x88,0x27,0x14,0x87,0x31,0x28,0x88,0x25,0x87,0x28,0x1f,0x88,0x25,0x87,0x28,0x1e,0x88,0x25,0x88,0x28,0x1c,0x87,0x25,0x88,0x28,0x19,0x87,0x25,0x88,0x28,0x16,0x88,0x25,0x87,0x28,0x13,0x88,0x25,0x87,0x28,0x12,0x88,0x25,0x87,0x2e,0x28,0x88,0x25,0x88,0x28,0x1e,0x87,0x25,0x88,0x27,0x87,0x23,0x88,0x2a,0x1b,0x87,0x23,0x88,0x2f,0x2a,0x88,0x23,0x87,0x2a,0x0f,0x88,0x23,0x87,0x28,0x88,0x23,0x88,0x28,0x10,0x87,0x23,0x88,0x2c,0x28,0x87,0x23,0x88,0x28,0x1c,0x87,0x23,0x88,0x28,0x88,0x22,0x87,0x28,0x19,0x88,0x22,0x87,0x28,0x2e,0x88,0x22,0x87,0x28,0x0d,0x88,0x22,0x88,0x27,0x87,0x22,0x88,0x27,0x0f,0x87,0x22,0x88,0x2b,0x27,0x88,0x22,0x87,0x27,0x1b,0x88,0x22,0x87,0x23,0x88,0x20,0x87,0x27,0x17,0x88,0x20,0x88,0x2c,0x27,0x87,0x20,0x88,0x27,0x0b,0x87,0x20,0x88,0x28,0x87,0x20,0x88,0x28,0x0d,0x88,0x20,0x87,0x28,0x2c,0x88,0x20,0x87,0x28,0x19,0x88,0x20,0x88,0x29,0x87,0x20,0x88,0x23,0x29,0x87,0x20,0x88,0x23,0x29,0x87,0x20,0x88,0x2c,0x29,0x88,0x20,0x87,0x22,0x27,0x88,0x1b,0x87,0x1f,0x88,0x1b,0x87,0x1f,0x88,0x1b,0x88,0x33,0x1f,0x87,0x1b,0x88,0x2f,0x20,0x87,0x1b,0x88,0x20,0x88,0x1b,0x87,0x20,0x88,0x1b,0x87,0x38,0x23,0x88,0x1b,0x87,0x37,0x22,0x88,0x1b,0x88,0x22,0x87,0x1b,0x88,0x22,0x87,0x1b,0x88,0x3f,0x25,0x87,0x1b,0x88,0x38,0x23,0x88,0x1b,0x87,0x27,0x88,0x1b,0x87,0x38,0x44,0x88,0x1b,0x88,0x29,0x87,0x1b,0x88,0x43,0x37,0x87,0x1b,0x88,0x1f,0x87,0x1b,0x88,0x1f,0x88,0x1b,0x87,0x33,0x22,0x88,0x1b,0x82,0x32,0x85,0x2f,0x20,0x88,0x1b,0x87,0x2f,0x20,0x88,0x1b,0x88,0x20,0x87,0x1b,0x88,0x38,0x23,0x87,0x1b,0x82,0x37,0x86,0x37,0x22,0x88,0x1b,0x87,0x37,0x22,0x88,0x1b,0x87,0x22,0x88,0x1b,0x87,0x3f,0x25,0x88,0x1b,0x82,0x3e,0x86,0x38,0x23,0x87,0x1b,0x88,0x38,0x27,0x87,0x1b,0x88,0x26,0x87,0x1b,0x88,0x38,0x44,0x88,0x1b,0x87,0x37,0x43,0x88,0x1b,0x87,0x37,0x43,0x88,0x1b,0x88,0x25,0x87,0x1b,0x88,0x34,0x40,0x87,0x1b,0x88,0x33,0x3f,0x87,0x1b,0x88,0x33,0x3f,0x88,0x1b,0x87,0x26,0x88,0x1b,0x87,0x38,0x44,0x88,0x1b,0x87,0x43,0x37,0x88,0x1b,0x88,0x37,0x43,0x87,0x1b,0x88,0x25,0x87,0x1b,0x88,0x34,0x40,0x88,0x1b,0x87,0x33,0x3f,0x88,0x1b,0x87,0x33,0x3f,0x88,0x1b,0x87,0x26,0x88,0x1b,0x88,0x38,0x44,0x87,0x1b,0x88,0x37,0x43,0x8f,0x27,0x8f,0x27,0x8f,0x27,0x8f,0x27,0x90,0x27,0x8f,0x27,0x8f,0x27,0x8f,0x27,0x28,0x8f,0x27,0x28,0x88,0x2f,0x82,0x2d,0x83,0x2c,0x82,0x2d,0x28,0x8f,0xff +// 0x35,0x41,0x8a,0x37,0x43,0x8a,0x33,0x3f,0x8a,0x30,0x3c,0x94,0x3e,0x32,0x8a,0x3a,0x2e,0x94,0x35,0x29,0x8a,0x37,0x2b,0x8a,0x33,0x27,0x8a,0x30,0x24,0x94,0x32,0x26,0x8a,0x2e,0x22,0x94,0x29,0x1d,0x8a,0x2b,0x1f,0x8a,0x27,0x1b,0x8a,0x24,0x18,0x94,0x1a,0x26,0x8a,0x18,0x24,0x8a,0x17,0x23,0x8a,0x16,0x22,0xa8,0x3a,0x35,0xff +//}; + +const byte music_2[] = { + 0x41,0x8b,0x8d,0x1d,0x42,0x8a,0x8d,0x11,0x41,0x8b,0x11,0x41,0x8b,0x1b,0x42,0x8b,0x1d,0x8c,0x11,0x41,0x8b,0x8c,0x1d,0x42,0x8b,0x8d,0x11,0x41,0x8b,0x11,0x41,0x8b,0x1b,0x42,0x8b,0x1d,0x8c,0x0f,0x41,0x8a,0x8d,0x1d,0x42,0x8b,0x8d,0x0f,0x41,0x8b,0x0f,0x41,0x8b,0x1b,0x42,0x8b,0x1d,0x8b,0x0f,0x41,0x8b,0x8d,0x1d,0x42,0x8b,0x8d,0x0f,0x41,0x8b,0x0f,0x41,0x8b,0x1b,0x42,0x8a,0x1d,0x8c,0x11,0x41,0x8b,0x8d,0x1d,0x42,0x8b,0x8d,0x11,0x41,0x8b,0x11,0x41,0x8a,0x1b,0x42,0x8b,0x1d,0x8c,0x11,0x41,0x8b,0x8d,0x1d,0x42,0x8b,0x8d,0x11,0x41,0x8a,0x11,0x41,0x8b,0x1b,0x42,0x8b,0x1d,0x8c,0x0f,0x41,0x8b,0x8d,0x1d,0x42,0x8b,0x8c,0x0f,0x41,0x8b,0x0f,0x41,0x8b,0x1b,0x42,0x8b,0x1d,0x8c,0x0f,0x41,0x8b,0x8d,0x1d,0x42,0x8a,0x8d,0x0f,0x41,0x8b,0x0f,0x41,0x8b,0x1b,0x42,0x8b,0x1d,0x8c,0x11,0x41,0x8b,0x8c,0x1d, + 0xff +}; + +#pragma code-name (pop) +#pragma rodata-name (pop) + diff --git a/presets/vcs/vcslib/demo_vcslib.c b/presets/vcs/vcslib/demo_vcslib.c new file mode 100644 index 00000000..1b90ea3d --- /dev/null +++ b/presets/vcs/vcslib/demo_vcslib.c @@ -0,0 +1,435 @@ + +//#resource "vcs-ca65.inc" +//#resource "kernel.inc" + +//#link "demo_kernels.ca65" + +//#link "libvcs.ca65" +//#link "mapper_3e.ca65" +//#link "xdata.ca65" +//#link "frameloop.c" +//#link "scorepf.ca65" +//#link "rand8.ca65" +//#link "bitmap48.ca65" +//#link "tinyfont48.c" +//#link "score6.ca65" + +//#link "sound.ca65" +//#link "music.ca65" +//#link "demo_sounds.c" + +#include +#include "bcd.h" +#include "vcslib.h" + +#define NSPRITES 2 +#define NOBJS 5 + +#pragma bss-name (push,"ZEROPAGE") + +/* +Attributes (position, etc) for all objects. +These map directly to player0/player1/missile0/missile1/ball. +(But they don't have to, if you write the code differently.) +*/ +byte xpos[NOBJS]; +byte ypos[NOBJS]; + +/* +These are variables used by the display kernels. +Some of them are modified by the kernels, like k_ypos, +so they must be initialized before the kernel starts. +*/ +byte k_height[NOBJS]; +byte k_ypos[NOBJS]; +byte* k_bitmap[NSPRITES]; +byte* k_colormap[NSPRITES]; +const byte* k_playfield; + +/* +BCD-encoded score, used by score display routines. +*/ +byte bcd_score[3]; // support 6-digit score (3 bytes) + +#pragma bss-name (pop) + +/* +We build a number of 30x5 bitmaps with tinyfont48 +*/ +#define NCAPTIONS 4 + +// the font doesn't map exactly to ASCII +#pragma charmap (0x20, 0x5b) +#pragma charmap (0x21, 0x29) +#pragma charmap (0x5f, 0x2d) + +// use the same ROM bank as tinyfont +#pragma bss-name(push, "XDATA") + +// these have to be either in PERM or in XDATA +const char* const CAPTIONS[NCAPTIONS] = { + "HELLO WORLD!", + " WELCOME TO ", + "**[VCSLIB[**", + "C FOR 2600!!", +}; + +// used by tinyfont48 routine +byte font_bitmap[NCAPTIONS][32]; // at least 30 bytes each + +#pragma bss-name(pop) + +// music data (demo_sounds.c) +extern const byte music_1[]; +extern const byte music_2[]; + +// kernel function for player sprites + background +extern void fastcall kernel_2pp_4pfa(byte nlines); + +#pragma code-name (push, "ROM2") +#pragma rodata-name (push, "ROM2") + +// kernel function for banner +extern void fastcall kernel_2pfasync(byte nlines); + +// asynchronous playfield bitmap +/*{w:48,h:8,flip:1}*/ +const byte k_asyncpf[6*8] = { + 0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x0C,0xCE,0x30,0xEE,0x10, + 0x40,0x92,0x50,0x00,0x49,0x28, + 0x20,0x50,0x50,0x00,0x49,0x50, + 0x20,0x50,0x4E,0x00,0x4E,0x28, + 0x20,0x52,0x41,0x00,0x49,0x50, + 0x20,0x4C,0x4E,0x00,0xEE,0x20, + 0x00,0x00,0x00,0x00,0x00,0x00, +}; + +// number of lines in the 2pp sprite kernel +#define NLINES (192-44-48) + +// Player sprite bitmap +/*{w:8,h:17,flip:1}*/ +const byte Frame0[17] = { + 0b1100001, + 0b100010, + 0b100100, + 0b101100, + 0b111000, + 0b10111001, + 0b10111010, + 0b1111100, + 0b11000, + 0b111100, + 0b1100110, + 0b1011010, + 0b1111110, + 0b1111110, + 0b1010110, + 0b1111110, + 0b10111101, +}; + +// Player sprite color map +const byte ColorFrame0[17+1] = { + 0xF4, // bottom + 0xF6, + 0x84, + 0x86, + 0x88, + 0xC2, + 0xC4, + 0xC6, + 0xC8, + 0x18, + 0x28, + 0x18, + 0x18, + 0x18, + 0x18, + 0x16, + 0x5c, // top + 0x5c, // (duplicated) +}; + +// move player with joystick +void move_joy(void) { + if (JOY_UP(0)) { + if (ypos[1] > 0x22) ypos[1]--; + } + if (JOY_DOWN(0)) { + if (ypos[1] < 0x22 + 16 + NLINES/2) ypos[1]++; + } + if (JOY_LEFT(0)) { + if (xpos[1] > 0x3) xpos[1]--; + TIA.refp1 = NO_REFLECT; + } + if (JOY_RIGHT(0)) { + if (xpos[1] < 0x9c) xpos[1]++; + TIA.refp1 = REFLECT; + } +} + +// Setup an object for the kernel routines. +void setup_object(byte index) { + k_ypos[index] = ypos[index] >> 1; + set_horiz_pos((index<<8) | xpos[index]); +} + +// Setup a player object for the kernel routines. +void setup_player(byte nlines, byte index) { + byte y = ypos[index] >> 1; + byte ofs = nlines - y + 1; + k_bitmap[index] = (char*) Frame0 - ofs; + ofs -= 1; + ofs -= ypos[index] & 1; + k_colormap[index] = (char*) ColorFrame0 - ofs; + k_ypos[index] = y; + set_horiz_pos((index<<8) | xpos[index]); +} + +/* +This function runs after VSYNC, and before the display kernel. +*/ +void my_preframe(void) { + TIA.vdelp0 = ypos[0]; + TIA.vdelp1 = ypos[1]; + TIA.nusiz0 = ONE_COPY | MSBL_SIZE4; + TIA.nusiz1 = DOUBLE_SIZE | MSBL_SIZE4; + setup_player(NLINES/2, P0); + setup_player(NLINES/2, P1); + setup_object(M0); + setup_object(M1); + apply_hmove(); +// k_playfield = (char*) 0xf000; +} + +/* +Versatile playfield data is pretty easy: +FIrst byte contains the register, second byte has the value. +It's in reverse order. +*/ +const byte VersatilePlayfield_data_e0_b0[] = { + 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x0E, 0xAA, 0x0E, + 0x18, 0x08, 0x02, 0x09, 0x00, 0x0F, 0x08, 0x0F, + 0x7F, 0x0F, 0x3E, 0x0F, 0x1C, 0x0F, 0x08, 0x0F, + 0xC2, 0x08, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, + 0x00, 0x0E, 0x1E, 0x0E, 0x08, 0x08, 0x7F, 0x0E, + 0xFE, 0x0E, 0x38, 0x0E, 0x06, 0x08, 0x01, 0x0A, + 0xa0, 0x09 +}; + +/* +This function is called to display the frame. +*/ +void my_doframe(void) { + byte caption_index; // which message to display? (0..NCAPTIONS-1) + + // draw the VCSLIB title using the async playfield kernel + TIA.ctrlpf = 0; + do_wsync(); + TIA.colubk = COLOR_CONV(0x68); + TIA.colupf = COLOR_CONV(0xa2); + kernel_2pfasync(42); + + // draw the sprites + playfield + TIA.colubk = 0x0; + TIA.ctrlpf = PF_REFLECT; + kernel_2pp_4pfa(NLINES/2); // each line is doubled + + // draw the playfield 2-digit score + TIA.ctrlpf = PF_SCORE; + do_wsync(); + TIA.colubk = COLOR_CONV(0xa2); + TIA.colup0 = COLOR_CONV(0x2e); + TIA.colup1 = COLOR_CONV(0x8e); + scorepf_kernel(); + TIA.wsync = 0; + TIA.colubk = 0; + TIA.ctrlpf = PF_REFLECT; + + // draw a 12-letter caption using bitmap48 + TIA.colubk = COLOR_CONV(0x82); + // cycle between the messages + // (we are low on memory, so use whatever counter is available :P) + caption_index = ((byte)music_ptr>>3) & (NCAPTIONS-1); + bitmap48_setheight(5); // must call before bitmap48_setaddress() + bitmap48_setaddress(font_bitmap[caption_index]); + bitmap48_setup(); + bitmap48_kernel(5); // 5 lines high + + // draw the 6-digit score (again using bitmap48) + score6_build(); + bitmap48_kernel(8); // 8 lines high +} + +/* +This function is called after the frame is displayed, +and before overscan. +*/ +void my_postframe(void) { + // move P1 + move_joy(); + // move P0 + if (++xpos[P0] > 150) { + xpos[P0] = 0; + } + if (++ypos[P0] > 100) { + ypos[P0] = 0; + } + // set missile positions + ypos[M0] = 80; + ypos[M1] = 82; + xpos[M0] = 10; + xpos[M1] = 155; + // fire buttons + if (JOY_FIRE(0)) { + sound_play(7); + score6_add(0x0199); + } + if (JOY_FIRE(1)) { + BCD_ADD(bcd_score[0], 1); + } + // update sound + sound_update(); + music_update(); + // update sound meter + k_height[M0] = sndchan_timer[0]*4; + k_height[M1] = sndchan_timer[1]*4; + // prepare score for next frame + scorepf_build(); + // play more music? + if (SW_SELECT()) { music_play(music_2); } +} + +/* +kernel_loop() is the main loop routine. +It's wrapped with wrapped-call so that it +switches to the appropriate bank (the one +that contains the function) before running. + +kernel_1() etc. do not have to be wrapped, +as long as they are called from a function +that is itself wrapped and in the same bank. +*/ + +#pragma wrapped-call (push, bankselect, bank) + +void kernel_loop() { + while (1) { + kernel_1(); + my_preframe(); + kernel_2(); + my_doframe(); + kernel_3(); + my_postframe(); + kernel_4(); + } +} + +#pragma wrapped-call (pop) + +#pragma rodata-name (pop) +#pragma code-name (pop) + + +/* +These are just test routines, they can be removed. +*/ +#pragma code-name(push, "XDATA"); +#pragma data-name(push, "XDATA"); +long int var = 0xdeadbeef; +int testfn() { + return 0x1234; +} +#pragma code-name(pop); +#pragma data-name(pop); + +#pragma wrapped-call (push, ramselect, 0) +void ramtest(void) { + char x; + POKE(0x17f0, 0xaa); + x = PEEK(0x17f0); + if (x != 0xaa) asm("brk"); + x = PEEK(&var); // 0xdeadbeef + if (x != 0xef) asm("brk"); + x = PEEK((char*)testfn+4); // rts from testfn() + if (x != 0x60) asm("brk"); + // TODO: doesn't work when ram selected + xramset((char*)0x13e0); + xramwrite(0x55); + x = xramread(); // TODO: selects ROM0 here + if (x != 0x55) asm("brk"); +} +#pragma wrapped-call (pop) +/* end of test routines */ + + +/* +init() runs first, and runs out of ROM0, which is +selected at power-up. +*/ + +#pragma wrapped-call (push, bankselect, bank) +#pragma code-name (push, "ROM0") + +void init(void) { + byte i; + + // set up initial object positions + xpos[P1] = 80; + ypos[P1] = 50; + ypos[M0] = 30; + ypos[M1] = 40; + ypos[BALL] = 60; + + // set up kernel variables + k_playfield = VersatilePlayfield_data_e0_b0-1; // kernel expects offset to be -1 + k_height[P0] = 16; + k_height[P1] = 16; + k_height[M0] = 0; // multiple of 4 + k_height[M1] = 4; // multiple of 4 + k_height[BALL] = 10; + + // initial BCD scores + bcd_score[0] = 0x12; + bcd_score[1] = 0x34; + + // build bitmap for caption messages + for (i=0; i= $40, play sound effect + cmp #$40 + bcs @PlaySound +; < $80, play next note +; but which channel to use? +; whichever has the lower timer counter + tay + ldx #0 + ldy _sndchan_timer+0 + cpy _sndchan_timer+1 + bcc @Chan0Free ; timer0 < timer 1? + inx +@Chan0Free: +; set the sound channels + tay + lda FREQZ,y + sta AUDF0,x + lda TONEZ,y + sta AUDC0,x +; set the sound channel + lda #0 + sta _sndchan_sfx,x ; sound 0 = envelope + lda _sound_duration+0 + sta _sndchan_timer,x ; set channel timer + jmp @IncMusic +@LoadDuration: + cmp #$ff + beq @Done ; end of sound + and #$7f + sta _music_timer ; set music timer +@IncMusic: + inc _music_ptr + bne @Done + inc _music_ptr+1 +@Done: + rts +@PlaySound: + sec + sbc #$40 + jsr _sound_play + jmp @IncMusic +.endproc + +; Table of AUDF base values for each note +FREQZ: + .byte 31, 31, 31, 31, 30, 28, 27, 25, 24, 22, 21, 20, 19, 17, 17, 15, 15, 14, 13, 12, 11, 11, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 31, 29, 27, 26, 24, 23, 22, 20, 19, 18, 17, 16, 15, 14, 13, 12, 12, 11, 10, 31, 29, 27, 26, 24, 23, 22, 20, 19, 18, 17, 16, 15 + +; Table of AUDC values for each note +TONEZ: + .byte 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 diff --git a/presets/vcs/vcslib/rand8.ca65 b/presets/vcs/vcslib/rand8.ca65 new file mode 100644 index 00000000..63d94f55 --- /dev/null +++ b/presets/vcs/vcslib/rand8.ca65 @@ -0,0 +1,36 @@ + +.include "vcs-ca65.inc" + +.global _randseed8 +.global _initrand8 +.global _nextrand8 +.global _prevrand8 + +_randseed8: .res 1 + +.proc _initrand8 + lda INTIM + ora #1 + sta _randseed8 + rts +.endproc + +.proc _nextrand8 + lda _randseed8 + lsr + bcc :+ + eor #$d4 +: + sta _randseed8 + rts +.endproc + +.proc _prevrand8 + lda _randseed8 + asl + bcc :+ + eor #$a9 +: + sta _randseed8 + rts +.endproc diff --git a/presets/vcs/vcslib/score6.ca65 b/presets/vcs/vcslib/score6.ca65 new file mode 100644 index 00000000..46215821 --- /dev/null +++ b/presets/vcs/vcslib/score6.ca65 @@ -0,0 +1,71 @@ + +.export _score6_build +.export _score6_add +.importzp _bcd_score +.import _bitmap48_ptr_0, _bitmap48_ptr_1, _bitmap48_ptr_2, _bitmap48_ptr_3, _bitmap48_ptr_4, _bitmap48_ptr_5 + +.proc _score6_add + sed + clc + adc _bcd_score+0 + sta _bcd_score+0 + txa + adc _bcd_score+1 + sta _bcd_score+1 + lda #0 + adc _bcd_score+2 + sta _bcd_score+2 + cld + rts +.endproc + +; needs to have XRAM active +.proc _score6_build + lda #>FontTable09 + sta _bitmap48_ptr_0+$400+1 + sta _bitmap48_ptr_1+$400+1 + sta _bitmap48_ptr_2+$400+1 + sta _bitmap48_ptr_3+$400+1 + sta _bitmap48_ptr_4+$400+1 + sta _bitmap48_ptr_5+$400+1 + ldy #2 ; start from most-sigificant BCD value + jsr score6_getbcd + stx _bitmap48_ptr_0+$400 + sta _bitmap48_ptr_1+$400 + dey + jsr score6_getbcd + stx _bitmap48_ptr_2+$400 + sta _bitmap48_ptr_3+$400 + dey + jsr score6_getbcd + stx _bitmap48_ptr_4+$400 + sta _bitmap48_ptr_5+$400 + rts +score6_getbcd: + lda _bcd_score,y ; get BCD value + and #$f0 ; isolate high nibble (* 16) + lsr ; shift right 1 bit (* 8) + ora # X + lda _bcd_score,y ; get BCD value (again) + and #$f ; isolate low nibble + asl + asl + asl ; * 8 + ora # A +.endproc + +; needs to be in PERM rom +.rodata +.align $80 +; Font table for digits 0-9 (8x8 pixels) +;;{w:8,h:8,count:12,brev:1,flip:1};; +FontTable09: + .byte $00,$3C,$66,$66,$76,$6E,$66,$3C,$00,$7E,$18,$18,$18,$38,$18,$18 + .byte $00,$7E,$60,$30,$0C,$06,$66,$3C,$00,$3C,$66,$06,$1C,$06,$66,$3C + .byte $00,$06,$06,$7F,$66,$1E,$0E,$06,$00,$3C,$66,$06,$06,$7C,$60,$7E + .byte $00,$3C,$66,$66,$7C,$60,$66,$3C,$00,$18,$18,$18,$18,$0C,$66,$7E + .byte $00,$3C,$66,$66,$3C,$66,$66,$3C,$00,$3C,$66,$06,$3E,$66,$66,$3C + .byte $00,$18,$00,$00,$00,$00,$00,$00,$00,$10,$7C,$12,$7C,$90,$7C,$10 +;; diff --git a/presets/vcs/vcslib/scorepf.ca65 b/presets/vcs/vcslib/scorepf.ca65 new file mode 100644 index 00000000..2385cb3f --- /dev/null +++ b/presets/vcs/vcslib/scorepf.ca65 @@ -0,0 +1,121 @@ + +.include "vcs-ca65.inc" + +.global _scorepf_build +.global _scorepf_kernel +.importzp _bcd_score +.importzp tmp1 +.import _reset_gfx +.import Return + +.zeropage +digit_ofs: .res 4 +;pftmp: .res 2 +; no one is using this, right?? +pftmp = tmp1 + +.segment "ROM1" +; calculate the byte offsets for each digit +; basically (digit * 5) +.proc _scorepf_build + ldx #0 + lda _bcd_score+0 + jsr calc_bcd_pair + lda _bcd_score+1 + jsr calc_bcd_pair + rts +.endproc + +.proc calc_bcd_pair + pha + and #$0f + sta pftmp + jsr mul5store ; (clever inlining) + pla + and #$f0 + lsr + lsr + lsr + lsr +mul5store: + sta pftmp + asl + asl + adc pftmp ; mul by 5 + sta digit_ofs,x + inx + rts +.endproc + +.proc _scorepf_kernel + jsr _reset_gfx ; returns A=0 + sta pftmp+0 + sta pftmp+1 + tax +; render the digits + ldx #0 +@loop: +; first digit pair + sta WSYNC + ldy digit_ofs+0 + inc digit_ofs+0 + lda DigitsBitmap,y + and #$0f + ldy pftmp+0 ; load old value digits 0/1 + sta pftmp+0 + sty PF1 ; store in PF1 + ldy digit_ofs+1 + inc digit_ofs+1 + lda DigitsBitmap,y + and #$f0 + ora pftmp+0 + sta pftmp+0 +; second digit pair + ldy pftmp+1 ; load old value digits 2/3 + sty PF1 ; store in PF1 + ldy digit_ofs+2 + inc digit_ofs+2 + lda DigitsBitmap,y + and #$0f + sta pftmp+1 + sta WSYNC + ldy digit_ofs+3 + inc digit_ofs+3 + lda DigitsBitmap,y + and #$f0 + ora pftmp+1 + sta pftmp+1 +; one more line + lda pftmp+0 + sta PF1 + SLEEPR 6 + lda pftmp+1 + sta PF1 +; loop over 5 lines + inx + cpx #5 + bne @loop +; one more line + sta WSYNC + lda pftmp+0 + sta PF1 + SLEEPR 24 + lda pftmp+1 + sta PF1 + sta WSYNC + jmp _reset_gfx +.endproc + +; Bitmap pattern for digits +DigitsBitmap: ;;{w:8,h:5,count:10,brev:1};; +.byte $EE,$AA,$AA,$AA,$EE +.byte $22,$22,$22,$22,$22 +.byte $EE,$22,$EE,$88,$EE +.byte $EE,$22,$66,$22,$EE +.byte $AA,$AA,$EE,$22,$22 +.byte $EE,$88,$EE,$22,$EE +.byte $EE,$88,$EE,$AA,$EE +.byte $EE,$22,$22,$22,$22 +.byte $EE,$AA,$EE,$AA,$EE +.byte $EE,$AA,$EE,$22,$EE +;;end diff --git a/presets/vcs/vcslib/sound.ca65 b/presets/vcs/vcslib/sound.ca65 new file mode 100644 index 00000000..c7c131ad --- /dev/null +++ b/presets/vcs/vcslib/sound.ca65 @@ -0,0 +1,79 @@ + +.include "vcs-ca65.inc" + +.export _sound_update +.export _sound_play + +.import _sound_duration +.import _sound_data + +.zeropage + +_sndchan_sfx: .res 2 +_sndchan_timer: .res 2 + +.exportzp _sndchan_sfx +.exportzp _sndchan_timer + +.importzp ptr3 +sounddata = ptr3 + +.segment "ROM3" + +; 00-1F: set frequency +; 81-9F odd: set volume +; 80-9E even: set control register + +.proc _sound_update + ldx #0 + jsr _sound_update_channel + ldx #1 +.endproc +.proc _sound_update_channel +; decrement timer + lda _sndchan_timer,x + beq @done + dec _sndchan_timer,x + beq @killsound +; get sound data address + lda _sndchan_sfx,x + asl + tay + lda _sound_data+0,y + sta sounddata+0 + lda _sound_data+1,y + sta sounddata+1 +; get next sound data byte + ldy _sndchan_timer,x + lda (sounddata),y ; get sound data + bpl @setfreq ; hi bit clear = just freq + lsr ; right shift (/ 2) + bcs @setvol ; lo bit set = volume + sta AUDC0,x ; lo bit clear = control + lsr ; also set freq (/ 2) +@setfreq: + sta AUDF0,x ; set frequency + rts +@killsound: + lda #0 +@setvol: + sta AUDV0,x ; set volume +@done: + rts +.endproc + +.proc _sound_play +; but which channel to use? +; whichever has the lower timer counter + ldx #0 + ldy _sndchan_timer+0 + cpy _sndchan_timer+1 + bcc @Chan0Free ; timer0 < timer 1? + inx +@Chan0Free: + sta _sndchan_sfx,x + tay + lda _sound_duration,y + sta _sndchan_timer,x + rts +.endproc diff --git a/presets/vcs/vcslib/tinyfont48.c b/presets/vcs/vcslib/tinyfont48.c new file mode 100644 index 00000000..11026f61 --- /dev/null +++ b/presets/vcs/vcslib/tinyfont48.c @@ -0,0 +1,53 @@ + +#include "vcslib.h" + +#pragma code-name (push, "ROM1") +#pragma rodata-name (push, "ROM1") + +#define LoChar 41 // lowest character value +#define HiChar 90 // highest character value + +/*{w:8,h:5,brev:1,flip:1,count:51}*/ +const unsigned char TINYFONT[51*5] = { +0x22, 0x00, 0x22, 0x22, 0x22, 0x55, 0x22, 0x55, 0x00, 0x00, 0x22, 0x77, 0x22, 0x00, 0x00, 0x44, +0x22, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, +0x22, 0x11, 0x11, 0x66, 0x55, 0x55, 0x55, 0x33, 0x22, 0x22, 0x22, 0x66, 0x22, 0x77, 0x44, 0x22, +0x11, 0x66, 0x66, 0x11, 0x22, 0x11, 0x66, 0x11, 0x11, 0x77, 0x55, 0x55, 0x66, 0x11, 0x66, 0x44, +0x77, 0x77, 0x55, 0x77, 0x44, 0x33, 0x44, 0x44, 0x22, 0x11, 0x77, 0x77, 0x55, 0x77, 0x55, 0x77, +0x66, 0x11, 0x77, 0x55, 0x77, 0x44, 0x00, 0x44, 0x00, 0x00, 0x44, 0x22, 0x00, 0x22, 0x00, 0x11, +0x22, 0x44, 0x22, 0x11, 0x77, 0x00, 0x77, 0x00, 0x00, 0x44, 0x22, 0x11, 0x22, 0x44, 0x22, 0x00, +0x22, 0x11, 0x77, 0x33, 0x44, 0x77, 0x55, 0x22, 0x55, 0x55, 0x77, 0x55, 0x22, 0x66, 0x55, 0x66, +0x55, 0x66, 0x33, 0x44, 0x44, 0x44, 0x33, 0x66, 0x55, 0x55, 0x55, 0x66, 0x77, 0x44, 0x77, 0x44, +0x77, 0x44, 0x44, 0x77, 0x44, 0x77, 0x33, 0x55, 0x77, 0x44, 0x33, 0x55, 0x55, 0x77, 0x55, 0x55, +0x77, 0x22, 0x22, 0x22, 0x77, 0x22, 0x55, 0x11, 0x11, 0x11, 0x55, 0x55, 0x66, 0x55, 0x55, 0x77, +0x44, 0x44, 0x44, 0x44, 0x55, 0x55, 0x77, 0x77, 0x55, 0x55, 0x77, 0x77, 0x77, 0x55, 0x22, 0x55, +0x55, 0x55, 0x22, 0x44, 0x44, 0x66, 0x55, 0x66, 0x33, 0x77, 0x55, 0x55, 0x22, 0x55, 0x66, 0x77, +0x55, 0x66, 0x66, 0x11, 0x22, 0x44, 0x33, 0x22, 0x22, 0x22, 0x22, 0x77, 0x33, 0x55, 0x55, 0x55, +0x55, 0x22, 0x22, 0x55, 0x55, 0x55, 0x55, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x22, 0x55, 0x55, +0x22, 0x22, 0x22, 0x55, 0x55, 0x77, 0x44, 0x22, 0x11, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void tinyfont48_build_char(byte* dest, char ch1, char ch2) { + byte y; + byte font1 = 5*(ch1-LoChar); + byte font2 = 5*(ch2-LoChar); + for (y=0; y<5; y++) { + byte b1 = TINYFONT[font1++] & 0xf0; + byte b2 = TINYFONT[font2++] & 0x0f; + xramset(dest); + xramwrite(b1 | b2); + dest++; + } +} + +// TODO: can we write when RAM is not selected? +void tinyfont48_build(byte* dest, const char str[12]) { + byte stri; + for (stri=0; stri<12; stri+=2) { + tinyfont48_build_char(dest, str[stri], str[stri+1]); + dest += 5; + } +} + +#pragma code-name (pop) +#pragma rodata-name (pop) diff --git a/presets/vcs/vcslib/vcs-ca65.inc b/presets/vcs/vcslib/vcs-ca65.inc new file mode 100644 index 00000000..54375a68 --- /dev/null +++ b/presets/vcs/vcslib/vcs-ca65.inc @@ -0,0 +1,375 @@ +.setcpu "6502X" + +; TIA write registers + +VSYNC := $00 ; ---- --1- This address controls vertical sync time by writing D1 into the VSYNC latch. +VBLANK := $01 ; 76-- --1- 1=Start VBLANK, 6=Enable INPT4, INPT5 latches, 7=Dump INPT1,2,3,6 to ground +WSYNC := $02 ; ---- ---- This address halts microprocessor by clearing RDY latch to zero. RDY is set true again by the leading edge of horizontal blank. +RSYNC := $03 ; ---- ---- This address resets the horizontal sync counter to define the beginning of horizontal blank time, and is used in chip testing. +NUSIZ0 := $04 ; --54 -210 \ 0,1,2: player copys'n'size, 4,5: missile size: 2^x pixels +NUSIZ1 := $05 ; --54 -210 / +COLUP0 := $06 ; 7654 321- color player 0 +COLUP1 := $07 ; 7654 321- color player 1 +COLUPF := $08 ; 7654 321- color playfield +COLUBK := $09 ; 7654 321- color background +CTRLPF := $0A ; --54 -210 0=reflect playfield, 1=pf uses player colors, 2=playfield over sprites 4,5=ballsize:2^x +REFP0 := $0B ; ---- 3--- reflect player 0 +REFP1 := $0C ; ---- 3--- reflect player 1 +PF0 := $0D ; DCBA ---- \ Playfield bits: ABCDEFGHIJKLMNOPQRST +PF1 := $0E ; EFGH IJKL > normal: ABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRST +PF2 := $0F ; TSRQ PONM / reflect: ABCDEFGHIJKLMNOPQRSTTSRQPONMLKJIHGFEDCBA +RESP0 := $10 ; ---- ---- \ +RESP1 := $11 ; ---- ---- \ +RESM0 := $12 ; ---- ---- > reset players, missiles and the ball. The object will begin its serial graphics at the time of a horizontal line at which the reset address occurs. +RESM1 := $13 ; ---- ---- / +RESBL := $14 ; ---- ---- / +AUDC0 := $15 ; ---- 3210 audio control voice 0 +AUDC1 := $16 ; ---- 3210 audio control voice 1 +AUDF0 := $17 ; ---4 3210 frequency divider voice 0 +AUDF1 := $18 ; ---4 3210 frequency divider voice 1 +AUDV0 := $19 ; ---- 3210 audio volume voice 0 +AUDV1 := $1A ; ---- 3210 audio volume voice 1 +GRP0 := $1B ; 7654 3210 graphics player 0 +GRP1 := $1C ; 7654 3210 graphics player 1 +ENAM0 := $1D ; ---- --1- enable missile 0 +ENAM1 := $1E ; ---- --1- enable missile 1 +ENABL := $1F ; ---- --1- enable ball +HMP0 := $20 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers +HMP1 := $21 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers +HMM0 := $22 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers +HMM1 := $23 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers +HMBL := $24 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers +VDELP0 := $25 ; ---- ---0 delay player 0 by one vertical line +VDELP1 := $26 ; ---- ---0 delay player 1 by one vertical line +VDELBL := $27 ; ---- ---0 delay ball by one vertical line +RESMP0 := $28 ; ---- --1- keep missile 0 aligned with player 0 +RESMP1 := $29 ; ---- --1- keep missile 1 aligned with player 1 +HMOVE := $2A ; ---- ---- This address causes the horizontal motion register values to be acted upon during the horizontal blank time in which it occurs. +HMCLR := $2B ; ---- ---- This address clears all horizontal motion registers to zero (no motion). +CXCLR := $2C ; ---- ---- clears all collision latches + +; TIA read registers + +CXM0P := $00 ; xx00 0000 Read Collision M0-P1 M0-P0 +CXM1P := $01 ; xx00 0000 M1-P0 M1-P1 +CXP0FB := $02 ; xx00 0000 P0-PF P0-BL +CXP1FB := $03 ; xx00 0000 P1-PF P1-BL +CXM0FB := $04 ; xx00 0000 M0-PF M0-BL +CXM1FB := $05 ; xx00 0000 M1-PF M1-BL +CXBLPF := $06 ; x000 0000 BL-PF ----- +CXPPMM := $07 ; xx00 0000 P0-P1 M0-M1 +INPT0 := $08 ; x000 0000 Read Pot Port 0 +INPT1 := $09 ; x000 0000 Read Pot Port 1 +INPT2 := $0A ; x000 0000 Read Pot Port 2 +INPT3 := $0B ; x000 0000 Read Pot Port 3 +INPT4 := $0C ; x000 0000 Read Input (Trigger) 0 +INPT5 := $0D ; x000 0000 Read Input (Trigger) 1 + +; RIOT + +SWCHA := $0280 +SWACNT := $0281 +SWCHB := $0282 +SWBCNT := $0283 +INTIM := $0284 ; Timer output +TIMINT := $0285 + +TIM1T := $0294 +TIM8T := $0295 +TIM64T := $0296 +TIM1024T := $0297 + +;------------------------------------------------------------------------------- +; SLEEP duration +; Original author: Thomas Jentzsch +; Inserts code which takes the specified number of cycles to execute. This is +; useful for code where precise timing is required. +; ILLEGAL-OPCODE VERSION DOES NOT AFFECT FLAGS OR REGISTERS. +; LEGAL OPCODE VERSION MAY AFFECT FLAGS +; Uses illegal opcode (DASM 2.20.01 onwards). + +.macro SLEEP cycles +.if cycles < 0 || cycles = 1 +.error "MACRO ERROR: 'SLEEP': Duration must be >= 2" +.endif +.if cycles & 1 +.ifndef NO_ILLEGAL_OPCODES + nop 0 +.else + bit VSYNC +.endif +.repeat (cycles-3)/2 + nop +.endrep +.else +.repeat cycles/2 + nop +.endrep +.endif +.endmacro + +;------------------------------------------------------------------------------- +; VERTICAL_SYNC +; revised version by Edwin Blink -- saves bytes! +; Inserts the code required for a proper 3 scanline vertical sync sequence +; Note: Alters the accumulator + +; OUT: A = 0 + +.macro VERTICAL_SYNC + lda #%1110 ; each '1' bits generate a VSYNC ON line (bits 1..3) +.local VSLP1 +VSLP1: sta WSYNC ; 1st '0' bit resets Vsync, 2nd '0' bit exit loop + sta VSYNC + lsr + bne VSLP1 ; branch until VYSNC has been reset +.endmacro + +;------------------------------------------------------- +; Usage: TIMER_SETUP lines +; where lines is the number of scanlines to skip (> 2). +; The timer will be set so that it expires before this number +; of scanlines. A WSYNC will be done first. + +.macro TIMER_SETUP lines +.local cycles +cycles = ((lines * 76) - 13) +; special case for when we have two timer events in a line +; and our 2nd event straddles the WSYNC boundary + .if (cycles .mod 64) < 12 + lda #(cycles / 64) - 1 + sta WSYNC + .else + lda #(cycles / 64) + sta WSYNC + .endif + sta TIM64T +.endmacro + +;------------------------------------------------------- +; Use with TIMER_SETUP to wait for timer to complete. +; Performs a WSYNC afterwards. + +.macro TIMER_WAIT +.local waittimer +waittimer: + lda INTIM + bne waittimer + sta WSYNC +.endmacro + +;------------------------------------------------------------------------------- +; CLEAN_START +; Original author: Andrew Davie +; Standardised start-up code, clears stack, all TIA registers and RAM to 0 +; Sets stack pointer to $FF, and all registers to 0 +; Sets decimal mode off, sets interrupt flag (kind of un-necessary) +; Use as very first section of code on boot (ie: at reset) +; Code written to minimise total ROM usage - uses weird 6502 knowledge :) + +.macro CLEAN_START +.local CLEAR_STACK + sei + cld + ldx #0 + txa + tay +CLEAR_STACK: dex + txs + pha + bne CLEAR_STACK ; SP=$FF, X = A = Y = 0 +.endmacro + +;------------------------------------------------------- +; SET_POINTER +; Original author: Manuel Rotschkar +; +; Sets a 2 byte RAM pointer to an absolute address. +; +; Usage: SET_POINTER pointer, address +; Example: SET_POINTER SpritePTR, SpriteData +; +; Note: Alters the accumulator, NZ flags +; IN 1: 2 byte RAM location reserved for pointer +; IN 2: absolute address +.macro SET_POINTER ptr, addr + lda #addr + sta ptr+1 +.endmacro + + +; assume NTSC unless PAL defined +.ifndef PAL +PAL = 0 +.endif + +; 192 visible scanlines for NTSC, 228 for PAL +.if PAL +SCANLINES = 228 +LINESD12 = 19 +.else +SCANLINES = 192 +LINESD12 = 16 +.endif + +; start of frame -- vsync and set back porch timer +.macro FRAME_START + VERTICAL_SYNC + .if PAL + TIMER_SETUP 44 + .else + TIMER_SETUP 36 + .endif +.endmacro + +; end of back porch -- start kernel +.macro KERNEL_START + TIMER_WAIT + lda #0 + sta VBLANK + .if !PAL + TIMER_SETUP 194 + .endif +.endmacro + +; end of kernel -- start front porch timer +.macro KERNEL_END + .if !PAL + TIMER_WAIT + .endif + lda #2 + sta VBLANK + .if PAL + TIMER_SETUP 36 + .else + TIMER_SETUP 28 + .endif +.endmacro + +; end of frame -- jump to frame start +.macro FRAME_END + TIMER_WAIT +.endmacro + +;----------------------------------------------------------- +; SLEEPR - sleep macro that uses JSR/RTS for 12 cycle delays +; Requires a lone RTS instruction with the label "Return" +; (note: may fool 8bitworkshop's Anaylze CPU Timing feature) + +.macro SLEEPR cycles +.if cycles >= 14 || cycles = 12 + jsr Return + SLEEPR (cycles-12) +.else + SLEEP cycles +.endif +.endmacro + +;----------------------------------------------------------- +; SLEEPH - sleep macro that uses PHA/PLA for 7 cycle delays +; (may affect flags) + +.macro SLEEPH cycles +.if cycles >= 9 || cycles = 7 + pha + pla + SLEEPH (cycles-7) +.else + SLEEP cycles +.endif +.endmacro + +;============================================================================== +; T I A - C O N S T A N T S +;============================================================================== + +HMOVE_L7 = $70 +HMOVE_L6 = $60 +HMOVE_L5 = $50 +HMOVE_L4 = $40 +HMOVE_L3 = $30 +HMOVE_L2 = $20 +HMOVE_L1 = $10 +HMOVE_0 = $00 +HMOVE_R1 = $F0 +HMOVE_R2 = $E0 +HMOVE_R3 = $D0 +HMOVE_R4 = $C0 +HMOVE_R5 = $B0 +HMOVE_R6 = $A0 +HMOVE_R7 = $90 +HMOVE_R8 = $80 + +; values for ENAMx and ENABL +DISABLE_BM = %00 +ENABLE_BM = %10 + +; values for RESMPx +LOCK_MISSILE = %10 +UNLOCK_MISSILE = %00 + +; values for REFPx: +NO_REFLECT = %0000 +REFLECT = %1000 + +; values for NUSIZx: +ONE_COPY = %000 +TWO_COPIES = %001 +TWO_MED_COPIES = %010 +THREE_COPIES = %011 +TWO_WIDE_COPIES = %100 +DOUBLE_SIZE = %101 +THREE_MED_COPIES = %110 +QUAD_SIZE = %111 +MSBL_SIZE1 = %000000 +MSBL_SIZE2 = %010000 +MSBL_SIZE4 = %100000 +MSBL_SIZE8 = %110000 + +; values for CTRLPF: +PF_PRIORITY = %100 +PF_SCORE = %10 +PF_REFLECT = %01 +PF_NO_REFLECT = %00 + +; values for SWCHB +P1_DIFF_MASK = %10000000 +P0_DIFF_MASK = %01000000 +BW_MASK = %00001000 +SELECT_MASK = %00000010 +RESET_MASK = %00000001 + +VERTICAL_DELAY = 1 + +; SWCHA joystick bits: +MOVE_RIGHT = %01111111 +MOVE_LEFT = %10111111 +MOVE_DOWN = %11011111 +MOVE_UP = %11101111 +P0_JOYSTICK_MASK = %11110000 +P1_JOYSTICK_MASK = %00001111 +P0_NO_MOVE = P0_JOYSTICK_MASK +P1_NO_MOVE = P1_JOYSTICK_MASK +NO_MOVE = P0_NO_MOVE | P1_NO_MOVE +P0_HORIZ_MOVE = MOVE_RIGHT & MOVE_LEFT & P0_NO_MOVE +P0_VERT_MOVE = MOVE_UP & MOVE_DOWN & P0_NO_MOVE +P1_HORIZ_MOVE = ((MOVE_RIGHT & MOVE_LEFT) >> 4) & P1_NO_MOVE +P1_VERT_MOVE = ((MOVE_UP & MOVE_DOWN) >> 4) & P1_NO_MOVE + +; SWCHA paddle bits: +P0_TRIGGER_PRESSED = %01111111 +P1_TRIGGER_PRESSED = %10111111 +P2_TRIGGER_PRESSED = %11110111 +P3_TRIGGER_PRESSED = %11111011 + +; values for VBLANK: +DUMP_PORTS = %10000000 +ENABLE_LATCHES = %01000000 +DISABLE_TIA = %00000010 +ENABLE_TIA = %00000000 + +;values for VSYNC: +START_VERT_SYNC = %10 +STOP_VERT_SYNC = %00 diff --git a/presets/vcs/vcslib/vcslib.h b/presets/vcs/vcslib/vcslib.h new file mode 100644 index 00000000..297f06fe --- /dev/null +++ b/presets/vcs/vcslib/vcslib.h @@ -0,0 +1,265 @@ + +#ifndef _VCSLIB_H +#define _VCSLIB_H + +#include +#include + +// Define data types for different data sizes and signedness + +typedef unsigned char byte; // 8-bit unsigned data type +typedef signed char sbyte; // 8-bit signed data type +typedef unsigned short word; // 16-bit unsigned data type +typedef signed short sword; // 16-bit signed data type + +// Bank switching functions that will be called directly when needed +// These are for changing which section of ROM or RAM the Atari 2600 accesses + +// Select a ROM bank by index +extern void fastcall bankselect(byte bankindex); + +// Select a RAM bank by index +extern void fastcall ramselect(byte ramindex); + +// Set address in extended RAM +extern void fastcall xramset(void* address); + +// Write a byte to extended RAM at set address +extern void fastcall xramwrite(byte value); + +// Read a byte from extended RAM at set address +extern byte fastcall xramread(void); + +// Copies initialized data from ROM to RAM at startup, if used +extern void copyxdata(void); + +// Atari 2600 kernel helpers, called in a sequence every frame + +extern void kernel_1(void); // before preframe +extern void kernel_2(void); // before kernel +extern void kernel_3(void); // after kernel +extern void kernel_4(void); // after postframe + +// Function to set horizontal position of a game object. +// The position and object index are packed into a single int. +// Hi byte = object index +// Lo byte = X coordinate + +extern void fastcall set_horiz_pos(int hi_obj__lo_xpos); + +// Waits for next scanline start +#define do_wsync() asm("sta $42 ; WSYNC"); + +// Applies horizontal motion to sprite(s) after set_horiz_pos() +#define apply_hmove() \ + asm("sta $42 ; WSYNC"); \ + asm("sta $6a ; HMOVE"); + + +/**** SCOREBOARD ROUTINES ****/ + +// Add 4-digit BCD to 6-digit BCD score +extern void fastcall score6_add(int delta_bcd); + +#pragma wrapped-call (push, bankselect, bank) + +// Setup TIA for Playfield score display +extern void scorepf_build(void); + +// Kernel for Playfield score display +extern void scorepf_kernel(void); + +#pragma wrapped-call (pop) + + +/**** SOUND AND MUSIC ROUTINES ****/ + +#pragma wrapped-call (push, bankselect, bank) + +// Update sound playback (once per frame) +extern void sound_update(); + +// Play a specific sound +extern void sound_play(byte sndindex); + +// Update music playback +extern void music_update(); + +#pragma wrapped-call (pop) + +extern const byte* music_ptr; // Pointer to current music data +#pragma zpsym("music_ptr"); + +// Macro to set music data pointer and begin playback +#define music_play(ptr) music_ptr = (ptr); + +extern byte sndchan_timer[2]; // sound channel timers, 0 = free channel +#pragma zpsym("sndchan_timer"); + +extern byte sndchan_sfx[2]; // sound channel sound index +#pragma zpsym("sndchan_sfx"); + + +/**** 48-PIXEL BITMAP ROUTINES ****/ + +// Setup TIA for 48-pixel wide bitmap mode +extern void fastcall bitmap48_setup(); + +#pragma wrapped-call (push, ramselect, 0) + +// Draws a 48-pixel wide bitmap +extern void fastcall bitmap48_kernel(unsigned char nlines); + +// Sets height for bitmap48_setaddress() function +extern void fastcall bitmap48_setheight(byte height); + +// Sets address of 48-pixel bitmap data +// Bitmap should be 6 bytes wide +extern void fastcall bitmap48_setaddress(byte* bitmap); + +// Builds a 6-digit score display in XRAM +extern void fastcall score6_build(); + +#pragma wrapped-call (pop) + +#pragma wrapped-call (push, bankselect, bank) + +// Create 48-pixel font from string (requires tinyfont48.c) +extern void tinyfont48_build(byte* dest, const char str[12]); + +#pragma wrapped-call (pop) + +///// + +#define P0 0 +#define P1 1 +#define M0 2 +#define M1 3 +#define BALL 4 + +#define OBJ_PLAYER_0 0x000 +#define OBJ_PLAYER_1 0x100 +#define OBJ_MISSILE_0 0x200 +#define OBJ_MISSILE_1 0x300 +#define OBJ_BALL 0x400 + +#define SW_RESET() ((RIOT.swchb & RESET_MASK) == 0) +#define SW_SELECT() ((RIOT.swchb & SELECT_MASK) == 0) +#define SW_COLOR() ((RIOT.swchb & BW_MASK) != 0) +#define SW_P0_PRO() ((RIOT.swchb & P0_DIFF_MASK) != 0) +#define SW_P1_PRO() ((RIOT.swchb & P1_DIFF_MASK) != 0) + +#define COLOR_CONV(color) (SW_COLOR() ? color : color & 0x0f) + +#define _CYCLES(lines) (((lines) * 76) - 13) +#define _TIM64(cycles) (((cycles) >> 6) - (((cycles) & 63) < 12)) +#define _T1024(cycles) ((cycles) >> 10) + +#ifdef PAL +#define VBLANK_TIM64 _TIM64(_CYCLES(45)) +#define KERNAL_T1024 _T1024(_CYCLES(250)) +#define OVERSCAN_TIM64 _TIM64(_CYCLES(36)) +#else +#define VBLANK_TIM64 _TIM64(_CYCLES(37)) +#define KERNAL_TIM64 _TIM64(_CYCLES(194)) +#define OVERSCAN_TIM64 _TIM64(_CYCLES(32)) +#endif + +#define JOY_UP(plyr) (!(RIOT.swcha & ((plyr) ? 0x1 : ~MOVE_UP))) +#define JOY_DOWN(plyr) (!(RIOT.swcha & ((plyr) ? 0x2 : ~MOVE_DOWN))) +#define JOY_LEFT(plyr) (!(RIOT.swcha & ((plyr) ? 0x4 : ~MOVE_LEFT))) +#define JOY_RIGHT(plyr) (!(RIOT.swcha & ((plyr) ? 0x8 : ~MOVE_RIGHT))) +#define JOY_FIRE(plyr) !(((plyr) ? TIA.inpt5 : TIA.inpt4) & 0x80) + +// TIA - CONSTANTS + +#define HMOVE_L7 (0x70) +#define HMOVE_L6 (0x60) +#define HMOVE_L5 (0x50) +#define HMOVE_L4 (0x40) +#define HMOVE_L3 (0x30) +#define HMOVE_L2 (0x20) +#define HMOVE_L1 (0x10) +#define HMOVE_0 (0x00) +#define HMOVE_R1 (0xF0) +#define HMOVE_R2 (0xE0) +#define HMOVE_R3 (0xD0) +#define HMOVE_R4 (0xC0) +#define HMOVE_R5 (0xB0) +#define HMOVE_R6 (0xA0) +#define HMOVE_R7 (0x90) +#define HMOVE_R8 (0x80) + +// Values for ENAMx and ENABL +#define DISABLE_BM (0b00) +#define ENABLE_BM (0b10) + +// Values for RESMPx +#define LOCK_MISSILE (0b10) +#define UNLOCK_MISSILE (0b00) + +// Values for REFPx +#define NO_REFLECT (0b0000) +#define REFLECT (0b1000) + +// Values for NUSIZx +#define ONE_COPY (0b000) +#define TWO_COPIES (0b001) +#define TWO_MED_COPIES (0b010) +#define THREE_COPIES (0b011) +#define TWO_WIDE_COPIES (0b100) +#define DOUBLE_SIZE (0b101) +#define THREE_MED_COPIES (0b110) +#define QUAD_SIZE (0b111) +#define MSBL_SIZE1 (0b000000) +#define MSBL_SIZE2 (0b010000) +#define MSBL_SIZE4 (0b100000) +#define MSBL_SIZE8 (0b110000) + +// Values for CTRLPF +#define PF_PRIORITY (0b100) +#define PF_SCORE (0b10) +#define PF_REFLECT (0b01) +#define PF_NO_REFLECT (0b00) + +// Values for SWCHB +#define P1_DIFF_MASK (0b10000000) +#define P0_DIFF_MASK (0b01000000) +#define BW_MASK (0b00001000) +#define SELECT_MASK (0b00000010) +#define RESET_MASK (0b00000001) + +#define VERTICAL_DELAY (1) + +// SWCHA joystick bits +#define MOVE_RIGHT (0b01111111) +#define MOVE_LEFT (0b10111111) +#define MOVE_DOWN (0b11011111) +#define MOVE_UP (0b11101111) +#define P0_JOYSTICK_MASK (0b11110000) +#define P1_JOYSTICK_MASK (0b00001111) +#define P0_NO_MOVE (P0_JOYSTICK_MASK) +#define P1_NO_MOVE (P1_JOYSTICK_MASK) +#define NO_MOVE (P0_NO_MOVE | P1_NO_MOVE) +#define P0_HORIZ_MOVE (MOVE_RIGHT & MOVE_LEFT & P0_NO_MOVE) +#define P0_VERT_MOVE (MOVE_UP & MOVE_DOWN & P0_NO_MOVE) +#define P1_HORIZ_MOVE (((MOVE_RIGHT & MOVE_LEFT) >> 4) & P1_NO_MOVE) +#define P1_VERT_MOVE (((MOVE_UP & MOVE_DOWN) >> 4) & P1_NO_MOVE) + +// SWCHA paddle bits +#define P0_TRIGGER_PRESSED (0b01111111) +#define P1_TRIGGER_PRESSED (0b10111111) +#define P2_TRIGGER_PRESSED (0b11110111) +#define P3_TRIGGER_PRESSED (0b11111011) + +// Values for VBLANK +#define DUMP_PORTS (0b10000000) +#define ENABLE_LATCHES (0b01000000) +#define DISABLE_TIA (0b00000010) +#define ENABLE_TIA (0b00000000) + +// Values for VSYNC +#define START_VERT_SYNC (0b10) +#define STOP_VERT_SYNC (0b00) + +#endif diff --git a/presets/vcs/vcslib/xdata.ca65 b/presets/vcs/vcslib/xdata.ca65 new file mode 100644 index 00000000..68ff60f9 --- /dev/null +++ b/presets/vcs/vcslib/xdata.ca65 @@ -0,0 +1,54 @@ + .export _copyxdata + .import __XDATA_LOAD__, __XDATA_RUN__, __XDATA_SIZE__ + .importzp ptr1, ptr2, tmp1 + +.code + +_copyxdata: + lda #<__XDATA_LOAD__ ; Source pointer + sta ptr1 + lda #>__XDATA_LOAD__ + sta ptr1+1 + + lda #<__XDATA_RUN__ ; Target pointer + sta ptr2 + lda #>__XDATA_RUN__ + ora #$04 ; write port + sta ptr2+1 + + ldx #<~__XDATA_SIZE__ + lda #>~__XDATA_SIZE__ ; Use -(__DATASIZE__+1) + sta tmp1 + ldy #$00 + +; Copy loop + +@L1: inx + beq @L3 + +@L2: + lda #0 + sta $3F ; select ROM0 + lda (ptr1),y + pha + lda #0 + sta $3E ; select RAM0 + pla + sta (ptr2),y + iny + bne @L1 + inc ptr1+1 + inc ptr2+1 ; Bump pointers + bne @L1 ; Branch always (hopefully) + +; Bump the high counter byte + +@L3: inc tmp1 + bne @L2 + +; Done + + lda #0 + sta $3F ; select ROM0 + rts + diff --git a/src/ide/project.ts b/src/ide/project.ts index 03414b2f..83b42ab0 100644 --- a/src/ide/project.ts +++ b/src/ide/project.ts @@ -441,7 +441,8 @@ export class CodeProject { stripLocalPath(path : string) : string { if (this.mainPath) { var folder = getFolderForPath(this.mainPath); - if (folder != '' && path.startsWith(folder)) { + // TODO: kinda weird if folder is same name as file prefix + if (folder != '' && path.startsWith(folder+'/')) { path = path.substring(folder.length+1); } } diff --git a/src/ide/ui.ts b/src/ide/ui.ts index cb821431..bc018b16 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -312,6 +312,10 @@ function refreshWindowList() { function loadEditor(path:string) { var tool = platform.getToolForFilename(path); + // hack because .h files can be DASM or CC65 + if (tool == 'dasm' && path.endsWith(".h") && getCurrentMainFilename().endsWith(".c")) { + tool = 'cc65'; + } var mode = tool && TOOL_TO_SOURCE_STYLE[tool]; return new SourceEditor(path, mode); } diff --git a/src/platform/vcs.ts b/src/platform/vcs.ts index d325f682..4a849680 100644 --- a/src/platform/vcs.ts +++ b/src/platform/vcs.ts @@ -54,6 +54,7 @@ const VCS_PRESETS = [ {id:'bb/duck_chase.bas', name:'Duck Chase (batariBASIC)'}, {id:'wiz/finalduck.wiz', name:'Final Duck (Wiz)'}, // {id:'bb/rblast106.bas', name:'Road Blasters (batariBASIC)'}, + {id:'vcslib/demo_vcslib.c', name:'VCSLib Demo (C)'}, ]; function getToolForFilename_vcs(fn: string) { @@ -226,8 +227,8 @@ class VCSPlatform extends BasePlatform { fixState(state) { // TODO: DASM listing prevents us from using RORG offset // TODO: how to handle 1000/3000/etc vs overlapping addresses? - if (state.ca.f != '3E' && state.ca.f != '3F') { - var ofs = (state.ca && state.ca.bo) || 0; + if (state.ca?.f != '3E' && state.ca?.f != '3F') { + var ofs = (state.ca?.bo) || 0; // TODO: for batari BASIC state.c.EPC = state.c.PC + ofs; // EPC = effective PC for ROM } diff --git a/src/worker/lib/vcs/crt0.o b/src/worker/lib/vcs/crt0.o new file mode 100644 index 00000000..8732c711 Binary files /dev/null and b/src/worker/lib/vcs/crt0.o differ diff --git a/src/worker/lib/vcs/crt0.s b/src/worker/lib/vcs/crt0.s new file mode 100644 index 00000000..83c5f480 --- /dev/null +++ b/src/worker/lib/vcs/crt0.s @@ -0,0 +1,51 @@ +; Atari VCS 2600 startup code for cc65 +; +; Florent Flament (contact@florentflament.com), 2017 + + .export _exit + .export __STARTUP__ : absolute = 1 + + .import __RAM_START__, __RAM_SIZE__ + .import copydata + .import _main + + .include "zeropage.inc" + + +.segment "STARTUP" +start: +; Clear decimal mode + cld + +; Initialization Loop: +; * Clears Atari 2600 whole memory (128 bytes) including BSS segment +; * Clears TIA registers +; * Sets system stack pointer to $ff (i.e top of zero-page) +; * Sets ROM bank 0 for mapper 3E/3F + ldx #0 + stx $3F + txa +clearLoop: + dex + txs + pha + bne clearLoop + +; Initialize data + jsr copydata + +; Initialize C stack pointer + lda #<(__RAM_START__ + __RAM_SIZE__) + ldx #>(__RAM_START__ + __RAM_SIZE__) + sta sp + stx sp+1 + +; Call main +_exit: + jmp _main + + +.segment "VECTORS" +.word start ; NMI +.word start ; Reset +.word start ; IRQ diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index 44b9e737..2ca136c5 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -85,9 +85,9 @@ var PLATFORM_PARAMS = { data_size: 0x80, wiz_rom_ext: '.a26', wiz_inc_dir: '2600', - extra_link_files: ['atari2600.cfg'], cfgfile: 'atari2600.cfg', - libargs: ['atari2600.lib'], + libargs: ['crt0.o', 'atari2600.lib'], + extra_link_files: ['crt0.o', 'atari2600.cfg'], define: ['__ATARI2600__'], }, 'mw8080bw': {