vcs: added vcslib demo

This commit is contained in:
Steven Hugg 2023-10-27 23:11:03 -05:00
parent d5460c991f
commit 92fde04422
26 changed files with 2529 additions and 134 deletions

389
package-lock.json generated
View File

@ -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": {

View File

@ -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",

19
presets/vcs/vcslib/bcd.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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 <peekpoke.h>
#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<NCAPTIONS; i++) {
tinyfont48_build(font_bitmap[i], CAPTIONS[i]);
}
// start playing music
music_play(music_1);
}
#pragma code-name (pop)
#pragma wrapped-call (pop)
/*
The main() function is called at startup.
It resides in the shared ROM area (PERM).
*/
void main(void) {
// call functions once for "Analyze CPU Timing" button
// (bank-switching does an indirect jump which isn't detected)
asm("lda #4");
asm("jsr _kernel_2pp_4pfa");
asm("lda #4");
asm("jsr _kernel_2pfasync");
// copy initialized data to XRAM
copyxdata();
// test XRAM (can be removed)
ramtest();
// initialization
init();
// main kernel loop
kernel_loop();
}

View File

@ -0,0 +1,51 @@
#include "vcslib.h"
#pragma warn (const-comparison, off)
void kernel_1(void) {
// Vertical Sync signal
TIA.vsync = START_VERT_SYNC;
TIA.wsync = 0x00;
// Test reset switch
if (SW_RESET()) {
asm("brk");
}
TIA.wsync = 0x00;
TIA.wsync = 0x00;
TIA.vsync = STOP_VERT_SYNC;
// Vertical Blank (preframe)
RIOT.tim64t = VBLANK_TIM64;
}
void kernel_2(void) {
while (RIOT.intim != 0) {}
// Turn on beam
TIA.wsync = 0x00;
TIA.vblank = ENABLE_TIA;
// Display frame (doframe)
#ifdef PAL
RIOT.t1024t = KERNAL_T1024;
#else
RIOT.tim64t = KERNAL_TIM64;
#endif
}
void kernel_3(void) {
while (RIOT.intim != 0) {}
// Turn off beam
TIA.wsync = 0x00;
TIA.vblank = DISABLE_TIA;
// Overscan (postframe)
RIOT.tim64t = OVERSCAN_TIM64;
}
void kernel_4(void) {
while (RIOT.intim != 0) {}
}

View File

@ -0,0 +1,104 @@
.macro DO_WSYNC
sta WSYNC
.endmacro
; 16-17 cycles
; modifies _k_ypos
.macro DO_DRAW_A index
lda _k_height+index
dcp _k_ypos+index
bcs :+
lda #0
.byte $2C
:
lda (_k_bitmap+index*2),y
.endmacro
; 19-20 cycles (unless WSYNC)
; modifies _k_ypos
.macro DO_DRAW index,wsync
DO_DRAW_A index
.if wsync
DO_WSYNC
.endif
sta GRP0+index
.endmacro
; 8 cycles
.macro DO_PCOLOR index
lda (_k_colormap+index*2),y
sta COLUP0+index
.endmacro
; 13-14 cycles
; modifies _k_playfield (can't cross page boundary)
.macro DO_PF index
lda (_k_playfield,x)
sta _k_pftmp + index
inc _k_playfield
.endmacro
; 18 cycles
.macro DO_PFWRITE
lda _k_pftmp+0
sta PF0
lda _k_pftmp+1
sta PF1
lda _k_pftmp+2
sta PF2
.endmacro
; 18 cycles
.macro DO_PFWRITE_2
lda _k_pftmp+3
sta PF0
lda _k_pftmp+4
sta PF1
lda _k_pftmp+5
sta PF2
.endmacro
; 7-8 cycles
.macro DO_VERSATILE_PF_1
lda (_k_playfield),y
tax
.endmacro
; 9-10 cycles
.macro DO_VERSATILE_PF_2
lda (_k_playfield),y
sta $40,x ; use TIA mirror
.endmacro
; 13 cycles
; modifies _k_ypos
.macro DO_MISSILE index
lda _k_height+index
dcp _k_ypos+index
sbc #$fe
sta ENAM0-2+index
.endmacro
; 5 cycles
; modifies _k_ypos
.macro DO_MISSILE_NOP index
dcp _k_ypos+index
.endmacro
; 13 cycles
.macro DO_MISSILE_PIXEL index
cpy _k_ypos+index
php
pla
sta ENAM0-2+index
.endmacro
.macro RESET_GFX
lda #0
sta GRP0
sta GRP1
sta PF0
sta PF1
sta PF2
.endmacro

View File

@ -0,0 +1,50 @@
.include "vcs-ca65.inc"
.global _set_horiz_pos
.export _reset_gfx
.export _reset_sprites
.export Return
;;;
; SetHorizPos routine
; A = X coordinate
; X = player number (0 or 1)
; must be in rodata segment because of alignment
.rodata
.align $10
.proc _set_horiz_pos
sec ; set carry flag
sta WSYNC ; start a new line
:
sbc #15 ; subtract 15
bcs :- ; branch until negative
eor #7 ; calculate fine offset
asl
asl
asl
asl
sta HMP0,x ; set fine offset
sta RESP0,x ; fix coarse position
sta WSYNC ; won't overrun if X < 150
rts
.endproc
.code
;;;
_reset_gfx:
lda #0
sta PF0
sta PF1
sta PF2
_reset_sprites:
lda #0
sta GRP0
sta GRP1
sta GRP0
sta GRP1
Return:
rts

View File

@ -0,0 +1,92 @@
.importzp tmp4, ptr3, ptr4
.import callax
.export _bankselect
.export _ramselect
.export _xramset
.export _xramwrite
.export _xramread
.zeropage
; current ROM bank index (not used for RAM)
_currbank: .res 1
; must be in shared ROM bank
.code
;extern void bankselect(char index);
;#pragma wrapped-call (push, bankselect, 0)
;#pragma code-name (push, "ROM0")
;
; Wrapper function for selecting a ROM bank
;NOTE: this does not preserve Y
_bankselect:
tay
; save the old bank index
lda _currbank
pha
; select the new bank
lda tmp4
sta _currbank
sta $3F
tya
; call the wrapped function
call_wrapped_and_exit:
jsr call_wrapped_func
; restore the previous bank
pla
sta _currbank
sta $3F
rts
; Wrapper function for selecting the RAM bank
; This must be called from a ROM bank, because it
; will always exit into the last selected ROM bank
;NOTE: this does not preserve Y
_ramselect:
tay
; save the old bank index
lda _currbank
pha
; select the RAM bank
lda tmp4
sta $3E
lda #0 ; needed for Stella signature?
tya
jmp call_wrapped_and_exit
; Used to do: jsr (ptr4)
call_wrapped_func:
jmp (ptr4)
; Write a byte to address (ptr3) in RAM bank 0
_xramwrite:
; select the RAM bank
ldx #0
stx $3E
sta (ptr3,x)
restore_bank:
ldx _currbank
stx $3F
rts
; Read a byte to address (ptr4) in RAM bank 0
_xramread:
; modify the ptr4
; select the RAM bank
ldx #0
stx $3E
lda (ptr4,x)
jmp restore_bank
; Set the xram read/write address (in ptr3/ptr4)
_xramset:
sta ptr4+0
sta ptr3+0
stx ptr4+1 ; read
txa
ora #%00000100
sta ptr3+1 ; write
rts

View File

@ -0,0 +1,89 @@
.include "vcs-ca65.inc"
.export _music_update
.exportzp _music_ptr
.import _sound_duration
.import _sound_play
.zeropage
_music_ptr: .res 2
_music_timer: .res 1
.importzp _sndchan_sfx
.importzp _sndchan_timer
.importzp ptr3
musicdata = ptr3
.segment "ROM3"
; 00-3f: play note
; 40-7f: play sound effect
; 80-fe: set duration until next note
; ff: stop music
.proc _music_update
; is music timer up?
lda _music_timer
bmi @Done
beq @NextData
dec _music_timer
jmp @Done
; Timer ran out, so fetch next note
@NextData:
ldx #0
lda (_music_ptr,x)
bmi @LoadDuration
; >= $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

View File

@ -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

View File

@ -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 #<FontTable09
tax ; lo ptr 0 -> X
lda _bcd_score,y ; get BCD value (again)
and #$f ; isolate low nibble
asl
asl
asl ; * 8
ora #<FontTable09
rts ; lo ptr 1 -> 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
;;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
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

265
presets/vcs/vcslib/vcslib.h Normal file
View File

@ -0,0 +1,265 @@
#ifndef _VCSLIB_H
#define _VCSLIB_H
#include <atari2600.h>
#include <stdint.h>
// 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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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
}

BIN
src/worker/lib/vcs/crt0.o Normal file

Binary file not shown.

51
src/worker/lib/vcs/crt0.s Normal file
View File

@ -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

View File

@ -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': {