Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma target(cx16)
- unsigned byte getMachineType;
- /**
- * C64 API intended for use with the SuperCPU
- * By Donkeysoft MMXXI
- * At the moment, KickC and Kick Assembler only
- * build 65c02 binaries; this may change in the
- * future.
- */
- void main() {
- setMachineType();
- disableBasicInterrupts();
- poke(0xd020, 0);
- poke(0xd021, 15);
- clearScreen();
- printAt(4, 12, "c64 rulez!");
- colourAt(4, 12, 1, 10);
- unsigned short xLocation = 64;
- unsigned char yLocation = 48;
- for(unsigned char index = 0; index < 8; index++) {
- setSpriteColour(index, index);
- switchOnSprites(index);
- spriteAt(xLocation, yLocation, index);
- xLocation += 24;
- yLocation += 24;
- }
- spriteExpandX(0);
- spriteExpandY(1);
- spriteUnexpandX(2);
- spriteUnexpandY(3);
- unsigned short waitState = 256;
- while(1) {
- if(checkForScanLine(44) == 1){
- poke(53280,1);
- wait(waitState);
- poke(53280,0);
- }
- if(checkForScanLine(88) == 1){
- poke(53280,3);
- wait(waitState);
- poke(53280,0);
- }
- if(checkForScanLine(244) == 1){
- poke(53280,5);
- wait(waitState);
- poke(53280,0);
- }
- if(checkForScanLine(272) == 1){
- poke(53280,7);
- wait(waitState);
- poke(53280,0);
- }
- }
- }
- /**
- * This is the initialisation will
- * determine the machine type
- * by setting the getMachineType global
- * as follows:
- * 37 is PAL
- * 5 is NTSC (old)
- * 6 is NTSC (new)
- * 0 (or any other value) is unknown
- *
- * For safety, the initial value of 0xc000
- * is stored into the accumulator and
- * pushed onto the stack; it is then
- * restored after the getMachineType
- * global is set
- *
- * @author Robin Harbron
- */
- void setMachineType() {
- asm {
- lda $c000
- pha
- sei
- __br1:
- lda $d011
- bmi __br1
- __br2:
- lda $d011
- bpl __br2
- __br3:
- lda $d012
- bit $d011
- bpl __ex1
- sta $c000
- bmi __br3
- __ex1:
- cli
- }
- getMachineType = peek(0xc000);
- asm {
- pla
- sta $c000
- }
- }
- /**
- * Takes in two 16-bit values, the first is
- * the memory location and the second will be
- * converted to an 8-bit value which is then
- * poked to memory
- */
- void poke(unsigned short location, unsigned short value) {
- char* loc = location;
- unsigned byte val = value & 255;
- *(loc) = val;
- }
- /**
- * Returns a single byte from a specific
- * memory location
- */
- unsigned char peek(unsigned short location) {
- unsigned char* memory = (char*)location;
- unsigned char returnByte = *memory;
- return returnByte;
- }
- /**
- * Disables BASIC interrupts
- */
- void disableBasicInterrupts() {
- unsigned byte basicInterruptStatus = peek(0xdc0e);
- poke(0xdc0e, basicInterruptStatus & 0xfe);
- }
- /**
- * Writes a string to the screen starting
- * from column x and row y (zero indexed)
- */
- void printAt(unsigned byte x, unsigned byte y, unsigned char* toPrint) {
- unsigned short screenAddress = 0x0400 + x + (y * 40);
- unsigned char index = 0;
- while(*(toPrint + index)) {
- poke(screenAddress++, *(toPrint + index));
- index++;
- }
- }
- /**
- * Changes the character colour of a
- * screen location starting from column
- * x and row y (zero indexed)
- */
- void colourAt(unsigned byte x, unsigned byte y, unsigned byte colour, unsigned byte numberOfCharacters) {
- unsigned short colourRamAddress = 0xd800 + x + (y * 40);
- for(unsigned char index = 0; index < numberOfCharacters; index++) {
- poke(colourRamAddress++, colour);
- }
- }
- /**
- * Will switch on a single sprite of the
- * eight available (zero indexed)
- */
- void switchOnSprites(unsigned char spriteNumber) {
- if(spriteNumber < 8) {
- unsigned byte toEnable = peek(0xd015) | getBitNumber(spriteNumber);
- poke(0xd015, toEnable);
- }
- }
- /**
- * Simple wait function - will count down
- * to zero; accepted parameters is 1 - 65535
- */
- void wait(unsigned short toWaitFor) {
- if(!toWaitFor){
- return;
- }
- for(; toWaitFor > 0; --toWaitFor) {
- ;;
- }
- }
- /**
- * Will switch off a single sprite of the
- * eight available (zero indexed)
- */
- void switchOffSprites(unsigned char spriteNumber) {
- if(spriteNumber < 8) {
- unsigned byte toDisable = peek(0xd015) ^ getBitNumber(spriteNumber);
- poke(0xd015, toDisable);
- }
- }
- /**
- * Set sprite to double width (zero indexed)
- */
- void spriteExpandX(unsigned byte spriteNumber) {
- if(spriteNumber < 8) {
- unsigned char toExpand = peek(0xd01d) | getBitNumber(spriteNumber);
- poke(0xd01d, toExpand);
- }
- }
- /**
- * Set sprite to double height (zero indexed)
- */
- void spriteExpandY(unsigned byte spriteNumber) {
- if(spriteNumber < 8) {
- unsigned char toExpand = peek(0xd017) | getBitNumber(spriteNumber);
- poke(0xd017, toExpand);
- }
- }
- /**
- * Unset sprite double width (zero indexed)
- */
- void spriteUnexpandX(unsigned byte spriteNumber) {
- if(spriteNumber < 8) {
- unsigned char toUnexpand = peek(0xd01d) ^ getBitNumber(spriteNumber);
- poke(0xd01d, toUnexpand);
- }
- }
- /**
- * Unset sprite double height (zero indexed)
- */
- void spriteUnexpandY(unsigned byte spriteNumber) {
- if(spriteNumber < 8) {
- unsigned char toUnexpand = peek(0xd017) ^ getBitNumber(spriteNumber);
- poke(0xd017, toUnexpand);
- }
- }
- /**
- * Returns the value of the joystick; zero
- * returns value of port 2, and 1 returns
- * value of port 1; any number above this
- * will return 0
- */
- unsigned byte readJoystickPort(unsigned char portNumber) {
- if(portNumber > 1) {
- return 0;
- }
- return peek(0xdc00 + portNumber);
- }
- /**
- * Positions a sprite at x pixels across
- * and y pixels down according to the
- * zero-indexed sprite number; note that
- * x can exceed 255
- */
- void spriteAt(unsigned short x, unsigned char y, unsigned byte spriteNumber) {
- unsigned byte spriteBit = getBitNumber(spriteNumber);
- unsigned byte sprite = 0;
- unsigned byte highBit = peek(0xd010);
- unsigned short spriteX = 0xd000;
- unsigned short spriteY = 0xd001;
- if(x > 255 && (highBit & spriteBit) == 0) {
- unsigned byte setBit = highBit | spriteBit;
- poke(0xd010, setBit);
- } else if(highBit > 0 && (highBit & spriteBit) == 1) {
- unsigned byte unsetBit = highBit - spriteBit;
- poke(0xd010, unsetBit);
- }
- if(spriteNumber > 0) {
- for(;sprite < spriteNumber; sprite++) {
- spriteX += 2;
- spriteY += 2;
- }
- }
- poke(spriteX, x);
- poke(spriteY, y);
- }
- /**
- * Sets the main sprite colour by
- * sprite numbe (zero indexed) and
- * colour (0 - 16) - will return
- * without altering if the spriteNumber
- * is 8 or over.
- */
- void setSpriteColour(unsigned char spriteNumber, unsigned char colour) {
- if(spriteNumber < 8) {
- poke(0xd027 + spriteNumber, colour);
- }
- }
- /**
- * Returns a value from 0 - 7 as its binary
- * equivalent, for instance, sending 3 to
- * this function will return 4; sending 7
- * will return 128
- */
- unsigned char getBitNumber(unsigned char bit) {
- unsigned char returnBit = 1;
- return returnBit << bit;
- }
- /**
- * From a 16-bit start position, it will store
- * the byte value in toFill by a set number
- * of bytes
- */
- void fillMemory(unsigned short startPosition, unsigned byte toFill, unsigned short numberOfBytes) {
- for(unsigned short index = 0; index < numberOfBytes; index++) {
- poke(startPosition + index, toFill);
- }
- }
- /**
- * Clears the screen according to
- * the current screen memory location
- * pointer at 0xd018
- */
- void clearScreen() {
- unsigned short screenLocation = getScreenMemoryLocation();
- fillMemory(screenLocation, 32, 1000);
- }
- /**
- * Will switch VIC II bank by setting
- * bit zero and one of 0xdd00. Any value
- * above three will default to bank zero
- */
- void switchVicBank(unsigned byte bank) {
- unsigned byte vicBank = peek(0xdd00);
- switch(bank) {
- case 0:
- poke(0xdd00, (vicBank & 0b11111100) | 0x03);
- break;
- case 1:
- poke(0xdd00, (vicBank & 0b11111100) | 0x02);
- break;
- case 2:
- poke(0xdd00, (vicBank & 0b11111100) | 0x01);
- break;
- case 3:
- poke(0xdd00, vicBank & 0b11111100);
- break;
- }
- }
- /**
- * The location 0xd018 controls the screen
- * and character memory as well as the
- * bitmap mode; this function points at the
- * character memory with a valid input of
- * zero to seven inclusive
- */
- void switchCharacterPointer(unsigned byte characterPointer) {
- if(characterPointer < 8) {
- characterPointer = characterPointer << 1;
- unsigned byte characterMemory = peek(0xd018);
- poke(0xd018, (characterMemory & 0b11110001) | characterPointer);
- }
- }
- /**
- * This will switch the default screen
- * memory; default is one, which points
- * to 0x0400. Values are zero through to
- * 16 inclusive
- */
- void switchScreenMemory(unsigned byte screenPointer) {
- if(screenPointer < 16) {
- screenPointer = screenPointer << 4;
- unsigned byte screenMemory = peek(0xd018);
- poke(0xd018, (screenMemory & 0b00001111) | screenPointer);
- }
- }
- /**
- * Returns the current screen location
- * based on the high bits of 0xd018
- */
- unsigned short getScreenMemoryLocation() {
- unsigned byte screenPointer = peek(0xd018) >> 4;
- unsigned short memoryLocation = 0;
- for(unsigned byte index = 0; index < screenPointer; index++) {
- memoryLocation += 0x0400;
- }
- return memoryLocation;
- }
- /**
- * Returns the keyboard stroke as a
- * byte
- *
- * @todo 2021-10-03
- */
- unsigned char getKeyboardInput() {
- return 0;
- }
- /**
- * Sets the C64's extended colour mode
- * accepting the four colours available
- * to set being between 0 - 15 inclusive;
- * any value above 15 means "no change"
- * This clears the bitmap and multi-colour
- * mode before implementing the extended
- * colour mode.
- */
- void setExtendedColourMode(unsigned byte colour1, unsigned byte colour2, unsigned byte colour3, unsigned byte colour4) {
- unsigned byte extendedColourMode = peek(0xd011);
- if((extendedColourMode & 0b01000000) == 0) {
- unsigned byte multiColourMode = peek(0xd016);
- poke(0xd016, (multiColourMode & 0b11101111));
- poke(0xd011, (extendedColourMode & 0b10011111) | 64);
- }
- if(colour1 > 15 && colour2 > 15 && colour3 > 15 && colour4 > 15) {
- return;
- }
- if(colour1 < 16){
- poke(0xd021, colour1);
- }
- if(colour2 < 16){
- poke(0xd022, colour2);
- }
- if(colour3 < 16){
- poke(0xd023, colour3);
- }
- if(colour4 < 16){
- poke(0xd024, colour4);
- }
- }
- /**
- * Switches off extended colour mode
- */
- void unsetExtendedColourMode() {
- unsigned byte extendedColourMode = peek(0xd011);
- poke(0xd011, extendedColourMode & 0b10111111);
- }
- /**
- * Switches on Multi Colour Mode
- * and ensures that the Extended Colour
- * Mode flag is unset; calling this
- * function with 1 or more will enable
- * bitmap mode as well
- */
- void setMultiColourMode(byte enableBitmap) {
- if(enableBitmap) {
- setBitmapMode();
- }
- unsigned byte controlRegister = peek(0xd016);
- poke(0xd016, (controlRegister & 0xff | 0b00010000));
- }
- /**
- * Sets bitmap mode on the 0xd011
- * control register (unsets extended
- * colour mode)
- */
- void setBitmapMode() {
- unsigned byte controlRegister = peek(0xd011);
- poke(0xd011, (controlRegister & 0b10111111) | 0b00100000);
- }
- /**
- * Will check for the current scan line
- * position; returns -1 if the parameter
- * sent is out of bounds (set to 312 assuming
- * PAL - valid range is therefore 0 - 311
- * assuming a zero index); 0 is returned if
- * not at that scan line, and 1 if the
- * parameter matches the current scan line
- *
- * @see setMachineType()
- */
- signed char checkForScanLine(unsigned int scanLine) {
- if(scanLine > 311 && getMachineType == 0x37) {
- return -1;
- }
- if(scanLine > 261 && getMachineType == 0x06) {
- return -1;
- }
- if(scanLine > 260 && getMachineType == 0x05) {
- return -1;
- }
- unsigned int currentScanLine = peek(0xd012);
- unsigned byte highBit = peek(0xd011);
- if(scanLine < 256) {
- if(scanLine == currentScanLine && highBit < 128) {
- return 1;
- }
- }
- if(highBit > 127 && scanLine > 255 ) {
- currentScanLine += 256;
- if(scanLine == currentScanLine) {
- return 1;
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement