├── .gitignore ├── README.md ├── assembler ├── apple.txt ├── assembly-to-hex.py ├── constants.py ├── fibonacci.txt ├── paintErase.txt ├── paintHeadAndTail.txt ├── references │ ├── addressing modes.txt │ ├── opcodes.txt │ └── parseOpcodes.py ├── snake.txt ├── temp1.txt └── update.txt ├── hexdump ├── apple ├── branching ├── checkCollision ├── colorTest ├── fibonacci ├── inc ├── indexedInd ├── indirect ├── indirectInd ├── indirectMode ├── initSnake ├── instructions ├── jsr ├── jump ├── paintErase ├── paintHeadAndTail ├── relative ├── snake ├── snakeFast ├── snakeUpdate ├── stack └── temp1 ├── runSnake.sh ├── snake └── runSnake.c ├── src ├── cpu.c ├── cpu.h ├── gfx.c ├── gfx.h ├── keyboard.c ├── keyboard.h ├── load_prog.c └── load_prog.h ├── tests ├── minunit.h └── testOPCODES.c └── tools ├── Makefile └── original-make /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | 34 | # Vim swap files 35 | *.sw* 36 | 37 | # Python files 38 | *.pyc 39 | 40 | # Binary and object files 41 | bin 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 6502-Emu 2 | A 6502 Emulator written in C! 3 | 4 | Made as a final project for Software Systems at Olin. Read the wiki for the full breakdown. 5 | 6 | To play Snake: run the shell script (runsnake.sh). Due to keyboard library limitations you need to click/focus back onto the original terminal when the game window opens. Control the snake with WASD (corresponding to up left down right) 7 | -------------------------------------------------------------------------------- /assembler/apple.txt: -------------------------------------------------------------------------------- 1 | ;initializes and draws apple 2 | define appleL $00 3 | define appleH $01 4 | 5 | jsr generateApplePosition 6 | jsr drawApple 7 | jsr end 8 | 9 | generateApplePosition: 10 | lda $fe 11 | sta appleL 12 | ;load a new random number from 2 to 5 into $01 13 | lda $fe 14 | and #$03 ;mask out lowest 2 bits 15 | clc 16 | adc #2 17 | sta appleH 18 | rts 19 | 20 | drawApple: 21 | ldy #0 22 | lda #$ff 23 | sta (appleL),y 24 | rts 25 | 26 | end: 27 | nop 28 | -------------------------------------------------------------------------------- /assembler/assembly-to-hex.py: -------------------------------------------------------------------------------- 1 | from constants import opcodes 2 | from constants import instructionLengths 3 | import argparse 4 | import re 5 | import os 6 | import sys 7 | 8 | # for negative hex values 9 | def toHex(val, nbits): 10 | return hex((val + (1 << nbits)) % (1 << nbits)) 11 | 12 | def stripCommentsAndWhitespace(line): 13 | # strip comments and whitespace 14 | commentStart = line.find(';') 15 | if (commentStart != -1): 16 | return line[0:commentStart].rstrip() 17 | else: 18 | return line.rstrip() 19 | 20 | def getLineDict(line): 21 | #returns dict of data and length for a line 22 | l = stripCommentsAndWhitespace(line) 23 | splitLine = filter(None, l.split(' ')) 24 | arguments = len(splitLine) 25 | return {'data':splitLine,'length':arguments} 26 | 27 | def findLabelsAndVariables(lineDict,labels,variables): 28 | #adds things to labels dictionary based on lineDict 29 | bytePosition = lineDict['bytePosition'] 30 | arguments = lineDict['length'] 31 | splitLine = lineDict['data'] 32 | twoByteAddress = re.compile('\$[0-9]{4}') 33 | if (arguments == 3): 34 | if (splitLine[0].endswith(':')): 35 | labels[splitLine[0][:-1]] = bytePosition 36 | elif (splitLine[0] == 'define'): 37 | variables[splitLine[1]] = splitLine[2]; 38 | elif (arguments == 2): 39 | # label and implicitly addressed opcode 40 | if (splitLine[0].endswith(':')): 41 | # remove colon before adding it to labels 42 | labels[splitLine[0][:-1]] = bytePosition 43 | elif (arguments == 1): 44 | # just a label 45 | if (splitLine[0].endswith(':')): 46 | # remove colon before adding it to labels 47 | labels[splitLine[0][:-1]] = bytePosition 48 | 49 | def getByteSize(lineDict,variables): 50 | #specifies size of line in terms of bytes once 51 | #compiled to hex 52 | bytePosition = lineDict['bytePosition'] 53 | arguments = lineDict['length'] 54 | splitLine = lineDict['data'] 55 | print(lineDict) 56 | twoByteAddress = re.compile('\$[a-fA-F0-9]{4}') 57 | if (arguments == 3): 58 | # label declaration. I think this is unused in snake 59 | # if (splitLine[0].endswith(':')): 60 | # if (twoByteAddress.search(splitLine[2])): 61 | # return 3 62 | # else: 63 | # return 2 64 | # else: 65 | # variable declaration 66 | return 0 67 | elif (arguments == 2): 68 | # label and implicitly addressed opcode 69 | if (splitLine[0].endswith(':')): 70 | return instructionLengths[splitLine[1].upper()][returnMode(lineDict,variables)] 71 | # opcode and address 72 | else: 73 | if (twoByteAddress.search(splitLine[1])): 74 | return instructionLengths[splitLine[0].upper()][returnMode(lineDict,variables)] 75 | else: 76 | return instructionLengths[splitLine[0].upper()][returnMode(lineDict,variables)] 77 | elif (arguments == 1): 78 | # just a label 79 | if (splitLine[0].endswith(':')): 80 | return 0 81 | # just an implicitly addressed opcode 82 | else: 83 | return instructionLengths[splitLine[0].upper()][returnMode(lineDict,variables)] 84 | elif (arguments == 0): 85 | return 0 86 | else: 87 | print("Number arguments: " + str(arguments)) 88 | raise ValueError("Number of arguments not between 0 and 3!") 89 | 90 | def parseLines(f): 91 | #returns parsedLines and labels, where parsedLines is a 92 | #list of dictionaries, each dictionary describing the contents 93 | #of the command on that line, and labels is the location 94 | #and names of jump labels 95 | bytePosition = 1536 96 | parsedLines = [] 97 | labels = {} 98 | variables = {} 99 | for line in f: 100 | stripped = line.strip() 101 | if stripped: #stripped line is not empty 102 | lineDict = getLineDict(stripped) 103 | lineDict['bytePosition'] = bytePosition 104 | findLabelsAndVariables(lineDict,labels,variables) 105 | parsedLines.append(lineDict) 106 | bytePosition += getByteSize(lineDict,variables) 107 | return parsedLines, labels, variables 108 | 109 | def padHex(s): 110 | # ensures that our hex output consists of single 111 | # bytes (00 to FF) with leading zeros 112 | if (len(s) == 1): 113 | return "0" + s + " " 114 | elif(len(s) == 3): 115 | return s[1:] + " 0" + s[0] + " " 116 | elif(len(s) == 4): 117 | return s[2:] + " " + s[0:2] + " " 118 | else: # len == 2 119 | return s + " " 120 | 121 | def getHexFromLines(parsedLines,labels,variables): 122 | print("Labels:", labels) 123 | print("Variables:", variables) 124 | hexOutput = "" 125 | for line in parsedLines: 126 | if(line['length'] > 0): 127 | # take the labels out of lines 128 | if (line['data'][0].endswith(':')): 129 | line['length'] -= 1 130 | line['data'] = line['data'][1:] 131 | # only process lines that aren't just labels or variables 132 | if(line['length'] > 0 and line['data'][0].lower() != 'define'): 133 | opcode = line['data'][0].upper() 134 | address = 'null' 135 | if (line['length']) == 2: 136 | address = line['data'][1] 137 | # replace variables with their values 138 | for variable in variables.keys(): 139 | if variable in address: 140 | address = address.replace(variable, variables[variable]) 141 | print("Opcode", opcode, "Address", address) 142 | if (opcode in opcodes.keys()): 143 | # implicit 144 | if (line['length'] == 1): 145 | print((opcodes[opcode]['SNGL']) + ' ') 146 | hexOutput += (opcodes[opcode]['SNGL']) + ' ' 147 | elif (line['length'] == 2): 148 | # immediate 149 | if(address.startswith('#')): 150 | if(address[1] == '$'): 151 | print(opcodes[opcode]['IMM'] + ' ' + padHex(address[2:])) 152 | hexOutput += opcodes[opcode]['IMM'] + ' ' + padHex(address[2:]) 153 | else: 154 | print(opcodes[opcode]['IMM'] + ' ' + padHex(address[1:])) 155 | hexOutput += opcodes[opcode]['IMM'] + ' ' + padHex(address[1:]) 156 | elif (address.startswith('(')): 157 | # indexed indirect 158 | if address[4] == ',': 159 | print(opcodes[opcode]['INDX'] + ' ' + address[2:4] + ' ') 160 | hexOutput += opcodes[opcode]['INDX'] + ' ' + address[2:4] + ' ' 161 | # indirect index 162 | elif address[5] == ',': 163 | print(opcodes[opcode]['INDY'] + ' ' + address[2:4] + ' ') 164 | hexOutput += opcodes[opcode]['INDY'] + ' ' + address[2:4] + ' ' 165 | # indirect 166 | else: 167 | print(opcodes[opcode]['IND'] + ' ' + address[4:6] + ' ' + address[2:4] + ' ') 168 | hexOutput += opcodes[opcode]['IND'] + ' ' + address[4:6] + ' ' + address[2:4] + ' ' 169 | elif (address.startswith('$')): 170 | operandLength = len(address) 171 | # absolute X and Y 172 | if (operandLength == 7): 173 | mode = 'ABS' + address[6].upper() 174 | print(opcodes[opcode][mode] + ' ' + address[3:5] + ' ' + address[1:3] + ' ') 175 | hexOutput += opcodes[opcode][mode] + ' ' + address[3:5] + ' ' + address[1:3] + ' ' 176 | # zero page 177 | elif (operandLength == 3): 178 | print(opcodes[opcode]['ZP'] + ' ' + padHex(address[1:])) 179 | hexOutput += opcodes[opcode]['ZP'] + ' ' + padHex(address[1:]) 180 | # zero page X and Y 181 | elif (address[3] == ','): 182 | mode = 'ZP' + address[4].upper() 183 | print(opcodes[opcode][mode] + ' ' + address[1:3] + ' ') 184 | hexOutput += opcodes[opcode][mode] + ' ' + address[1:3] + ' ' 185 | # absolute 186 | else: 187 | print(opcodes[opcode]['ABS'] + ' ' + padHex(address[3:]) + address[1:3] + ' ') 188 | hexOutput += opcodes[opcode]['ABS'] + ' ' + padHex(address[3:]) + address[1:3] + ' ' 189 | elif (address in labels.keys()): 190 | # print ("we\'ve got a label") 191 | if (opcode[0] == "J"): 192 | # Jump to an absolute point (this doesn't account for indirect jumps) 193 | byteDiff = labels[address] 194 | hexByteDiff = str(toHex(byteDiff, 16)[2:]) 195 | # take starting position 0x0600 into account 196 | if (len(hexByteDiff) < 3): 197 | print(opcodes[opcode]['ABS'] + ' ' + padHex(hexByteDiff) + '06 ') 198 | hexOutput += opcodes[opcode]['ABS'] + ' ' + padHex(hexByteDiff) + '06 ' 199 | else: 200 | print(opcodes[opcode]['ABS'] + ' ' + padHex(hexByteDiff)) 201 | hexOutput += opcodes[opcode]['ABS'] + ' ' + padHex(hexByteDiff) 202 | else: 203 | # relative addressing with label 204 | byteDiff = labels[address] - line['bytePosition'] - 2 205 | print(opcodes[opcode]['BRA'] + ' ' + padHex(str(toHex(byteDiff, 8)[2:]))) 206 | hexOutput += opcodes[opcode]['BRA'] + ' ' + padHex(str(toHex(byteDiff, 8)[2:])) 207 | else: 208 | raise ValueError('Problem with address in this line: ',line) 209 | else: 210 | raise ValueError('Invalid line length') 211 | else: 212 | raise ValueError('No opcode found') 213 | return (hexOutput.strip()) 214 | 215 | def returnMode(line,variables): 216 | if(line['length'] > 0): 217 | # take the labels out of lines 218 | if (line['data'][0].endswith(':')): 219 | line['length'] -= 1 220 | line['data'] = line['data'][1:] 221 | # only process lines that aren't just labels or variables 222 | if(line['length'] > 0 and line['data'][0].lower() != 'define'): 223 | opcode = line['data'][0].upper() 224 | address = 'null' 225 | if (line['length']) == 2: 226 | address = line['data'][1] 227 | # replace variables with their values 228 | for variable in variables.keys(): 229 | if variable in address: 230 | address = address.replace(variable, variables[variable]) 231 | if (opcode in opcodes.keys()): 232 | if (line['length'] == 1): 233 | return 'SNGL' 234 | elif (line['length'] == 2): 235 | # immediate 236 | if(address.startswith('#')): 237 | return 'IMM' 238 | elif (address.startswith('(')): 239 | # indexed indirect 240 | if address[4] == ',': 241 | return 'INDX' 242 | # indirect index 243 | elif address[5] == ',': 244 | return 'INDY' 245 | # indirect 246 | else: 247 | return 'IND' 248 | elif (address.startswith('$')): 249 | operandLength = len(address) 250 | # absolute X and Y 251 | if (operandLength == 7): 252 | mode = 'ABS' + address[6].upper() 253 | return mode 254 | # zero page 255 | elif (operandLength == 3): 256 | return 'ZP' 257 | # zero page X and Y 258 | elif (address[3] == ','): 259 | mode = 'ZP' + address[4].upper() 260 | return mode 261 | # absolute 262 | else: 263 | return 'ABS' 264 | elif (opcode[0] == "J"): 265 | return 'ABS' 266 | elif (opcode in ['BCC','BCS','BEQ','BMI','BNE','BPL','BVC','BVS']): 267 | return 'BRA' 268 | else: 269 | raise ValueError('Problem with address in this line: ',line) 270 | else: 271 | raise ValueError('Invalid line length') 272 | else: 273 | raise ValueError('No opcode found') 274 | 275 | def assemblyToHex(f): 276 | #takes file handler for text file with assembly and returns string of hex vals 277 | parsedLines,labels,variables = parseLines(f) 278 | hexString = getHexFromLines(parsedLines,labels,variables) 279 | return hexString 280 | 281 | if __name__ == "__main__": 282 | parser = argparse.ArgumentParser() 283 | parser.add_argument("-i","--input",type=argparse.FileType('r')) 284 | parser.add_argument("-o", "--output", help="Directs the output to a name of your choice") 285 | args = parser.parse_args() 286 | hexStr = assemblyToHex(args.input) 287 | with open(args.output, 'w') as output_file: 288 | output_file.write(hexStr) 289 | -------------------------------------------------------------------------------- /assembler/constants.py: -------------------------------------------------------------------------------- 1 | opcodes = { 2 | '---': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 3 | 'ADC': {'SNGL': 'null', 'INDY': '71', 'IMM': '69', 'INDX': '61', 'ZPX': '75', 'ABS': '6d', 'ABSY': '79', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '65', 'ABSX': '7d'}, 4 | 'AND': {'SNGL': 'null', 'INDY': '31', 'IMM': '29', 'INDX': '21', 'ZPX': '35', 'ABS': '2d', 'ABSY': '39', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '25', 'ABSX': '3d'}, 5 | 'ASL': {'SNGL': '0a', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': '16', 'ABS': '0e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '06', 'ABSX': '1e'}, 6 | 'BCC': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '90', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 7 | 'BCS': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'b0', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 8 | 'BEQ': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'f0', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 9 | 'BIT': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '2c', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '24', 'ABSX': 'null'}, 10 | 'BMI': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '30', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 11 | 'BNE': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'd0', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 12 | 'BPL': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '10', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 13 | 'BRK': {'SNGL': '00', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 14 | 'BVC': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '50', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 15 | 'BVS': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '70', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 16 | 'CLC': {'SNGL': '18', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 17 | 'CLD': {'SNGL': 'd8', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 18 | 'CLI': {'SNGL': '58', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 19 | 'CLV': {'SNGL': 'b8', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 20 | 'CMP': {'SNGL': 'null', 'INDY': 'd1', 'IMM': 'c9', 'INDX': 'c1', 'ZPX': 'd5', 'ABS': 'cd', 'ABSY': 'd9', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'c5', 'ABSX': 'dd'}, 21 | 'CPX': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'e0', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'ec', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'e4', 'ABSX': 'null'}, 22 | 'CPY': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'c0', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'cc', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'c4', 'ABSX': 'null'}, 23 | 'DEC': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'd6', 'ABS': 'ce', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'c6', 'ABSX': 'de'}, 24 | 'DEX': {'SNGL': 'ca', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 25 | 'DEY': {'SNGL': '88', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 26 | 'EOR': {'SNGL': 'null', 'INDY': '51', 'IMM': '49', 'INDX': '41', 'ZPX': '55', 'ABS': '4d', 'ABSY': '59', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '45', 'ABSX': '5d'}, 27 | 'INC': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'f6', 'ABS': 'ee', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'e6', 'ABSX': 'fe'}, 28 | 'INX': {'SNGL': 'e8', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 29 | 'INY': {'SNGL': 'c8', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 30 | 'JMP': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '4c', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': '6c', 'ZP': 'null', 'ABSX': 'null'}, 31 | 'JSR': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '20', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 32 | 'LDA': {'SNGL': 'null', 'INDY': 'b1', 'IMM': 'a9', 'INDX': 'a1', 'ZPX': 'b5', 'ABS': 'ad', 'ABSY': 'b9', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'a5', 'ABSX': 'bd'}, 33 | 'LDX': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'a2', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'ae', 'ABSY': 'be', 'BRA': 'null', 'ZPY': 'b6', 'IND': 'null', 'ZP': 'a6', 'ABSX': 'null'}, 34 | 'LDY': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'a0', 'INDX': 'null', 'ZPX': 'b4', 'ABS': 'ac', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'a4', 'ABSX': 'bc'}, 35 | 'LSR': {'SNGL': '4a', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': '56', 'ABS': '4e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '46', 'ABSX': '5e'}, 36 | 'NOP': {'SNGL': 'ea', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 37 | 'ORA': {'SNGL': 'null', 'INDY': '11', 'IMM': '09', 'INDX': '01', 'ZPX': '15', 'ABS': '0d', 'ABSY': '19', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '05', 'ABSX': '1d'}, 38 | 'PHA': {'SNGL': '48', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 39 | 'PHP': {'SNGL': '08', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 40 | 'PLA': {'SNGL': '68', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 41 | 'PLP': {'SNGL': '28', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 42 | 'ROL': {'SNGL': '2a', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': '36', 'ABS': '2e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '26', 'ABSX': '3e'}, 43 | 'ROR': {'SNGL': '6a', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': '76', 'ABS': '6e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '66', 'ABSX': '7e'}, 44 | 'RTI': {'SNGL': '40', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 45 | 'RTS': {'SNGL': '60', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 46 | 'SBC': {'SNGL': 'null', 'INDY': 'f1', 'IMM': 'e9', 'INDX': 'e1', 'ZPX': 'f5', 'ABS': 'ed', 'ABSY': 'f9', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'e5', 'ABSX': 'fd'}, 47 | 'SEC': {'SNGL': '38', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 48 | 'SED': {'SNGL': 'f8', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 49 | 'SEI': {'SNGL': '78', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 50 | 'STA': {'SNGL': 'null', 'INDY': '91', 'IMM': 'null', 'INDX': '81', 'ZPX': '95', 'ABS': '8d', 'ABSY': '99', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '85', 'ABSX': '9d'}, 51 | 'STX': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '8e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': '96', 'IND': 'null', 'ZP': '86', 'ABSX': 'null'}, 52 | 'STY': {'SNGL': 'null', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': '94', 'ABS': '8c', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '84', 'ABSX': 'null'}, 53 | 'TAX': {'SNGL': 'aa', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 54 | 'TAY': {'SNGL': 'a8', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 55 | 'TSX': {'SNGL': 'ba', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 56 | 'TXA': {'SNGL': '8a', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 57 | 'TXS': {'SNGL': '9a', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 58 | 'TYA': {'SNGL': '98', 'INDY': 'null', 'IMM': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'}, 59 | 'WDM': {'SNGL': 'null', 'INDY': 'null', 'IMM': '42', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '42', 'ABSX': 'null'}, 60 | } 61 | 62 | instructionLengths = { 63 | 'ADC': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 64 | 'AND': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 65 | 'ASL': {'SNGL': 1, 'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 66 | 'BCC': {'BRA': 2}, 67 | 'BCS': {'BRA': 2}, 68 | 'BEQ': {'BRA': 2}, 69 | 'BIT': {'ABS': 3, 'ZP': 2}, 70 | 'BMI': {'BRA': 2}, 71 | 'BNE': {'BRA': 2}, 72 | 'BPL': {'BRA': 2}, 73 | 'BRK': {'SNGL': 1}, 74 | 'BVC': {'BRA': 2}, 75 | 'BVS': {'BRA': 2}, 76 | 'CLC': {'SNGL': 1}, 77 | 'CLD': {'SNGL': 1}, 78 | 'CLI': {'SNGL': 1}, 79 | 'CLV': {'SNGL': 1}, 80 | 'CMP': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 81 | 'CPX': {'IMM': 2, 'ABS': 3, 'ZP': 2}, 82 | 'CPY': {'IMM': 2, 'ABS': 3, 'ZP': 2}, 83 | 'DEC': {'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 84 | 'DEX': {'SNGL': 1}, 85 | 'DEY': {'SNGL': 1}, 86 | 'EOR': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 87 | 'INC': {'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 88 | 'INX': {'SNGL': 1}, 89 | 'INY': {'SNGL': 1}, 90 | 'JMP': {'ABS': 3, 'IND': 3}, 91 | 'JSR': {'ABS': 3}, 92 | 'LDA': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 93 | 'LDX': {'IMM': 2, 'ABS': 3, 'ABSY': 3, 'ZPY': 2, 'ZP': 2}, 94 | 'LDY': {'IMM': 2, 'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 95 | 'LSR': {'SNGL': 1, 'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 96 | 'NOP': {'SNGL': 1}, 97 | 'ORA': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 98 | 'PHA': {'SNGL': 1}, 99 | 'PHP': {'SNGL': 1}, 100 | 'PLA': {'SNGL': 1}, 101 | 'PLP': {'SNGL': 1}, 102 | 'ROL': {'SNGL': 1, 'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 103 | 'ROR': {'SNGL': 1, 'ZPX': 2, 'ABS': 3, 'ZP': 2, 'ABSX': 3}, 104 | 'RTI': {'SNGL': 1}, 105 | 'RTS': {'SNGL': 1}, 106 | 'SBC': {'INDY': 2, 'IMM': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 107 | 'SEC': {'SNGL': 1}, 108 | 'SED': {'SNGL': 1}, 109 | 'SEI': {'SNGL': 1}, 110 | 'STA': {'INDY': 2, 'INDX': 2, 'ZPX': 2, 'ABS': 3, 'ABSY': 3, 'ZP': 2, 'ABSX': 3}, 111 | 'STX': {'ABS': 3, 'ZPY': 2, 'ZP': 2}, 112 | 'STY': {'ZPX': 2, 'ABS': 3, 'ZP': 2}, 113 | 'TAX': {'SNGL': 1}, 114 | 'TAY': {'SNGL': 1}, 115 | 'TSX': {'SNGL': 1}, 116 | 'TXA': {'SNGL': 1}, 117 | 'TXS': {'SNGL': 1}, 118 | 'TYA': {'SNGL': 1}, 119 | 'WDM': {'IMM': 1, 'ZP': 2}, 120 | } 121 | -------------------------------------------------------------------------------- /assembler/fibonacci.txt: -------------------------------------------------------------------------------- 1 | LDX #$01; 2 | STX $00; 3 | SEC; 4 | LDY #$07; 5 | TYA; 6 | SBC #$03; 7 | TAY; 8 | CLC; 9 | LDA #$02; 10 | STA $01; 11 | loop: 12 | LDX $01; 13 | ADC $00; 14 | STA $01; 15 | STX $00; 16 | DEY; 17 | BNE loop; 18 | -------------------------------------------------------------------------------- /assembler/paintErase.txt: -------------------------------------------------------------------------------- 1 | define appleL $00 ; screen location of apple, low byte 2 | define appleH $01 ; screen location of apple, high byte 3 | define snakeHeadH $11 ; screen location of snake head, high byte 4 | define snakeBodyStart $12 ; start of snake body byte pairs 5 | define snakeDirection $02 ; direction (possible values are below) 6 | 7 | ; Directions (each using a separate bit) 8 | define movingUp 1 9 | define movingRight 2 10 | define movingDown 4 11 | define movingLeft 8 12 | 13 | 14 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 15 | 16 | define snakeLength $03 ; snake length, in bytes 17 | define snakeHeadL $10 ; screen location of snake head, low byte 18 | 19 | jsr initSnake 20 | jsr drawSnake 21 | jsr eraseSnake 22 | jmp end 23 | 24 | 25 | initSnake: 26 | lda #movingRight ;start direction 27 | sta snakeDirection 28 | 29 | lda #4 ;start length (2 segments) 30 | sta snakeLength 31 | 32 | lda #$11 33 | sta snakeHeadL 34 | 35 | lda #$10 36 | sta snakeBodyStart 37 | 38 | lda #$0f 39 | sta $14 ; body segment 1 40 | 41 | lda #$04 42 | sta snakeHeadH 43 | sta $13 ; body segment 1 44 | sta $15 ; body segment 2 45 | rts 46 | 47 | drawSnake: 48 | ldx snakeLength 49 | lda #$ff 50 | sta (snakeHeadL,x) ; paint end of tail 51 | 52 | ldx #0 53 | lda #1 54 | sta (snakeHeadL,x) ; paint head 55 | rts 56 | 57 | eraseSnake: 58 | ldx snakeLength 59 | lda #0 60 | sta (snakeHeadL,x) ; erase end of tail 61 | 62 | ldx #0 63 | lda #0 64 | sta (snakeHeadL,x) ; erase head 65 | rts 66 | 67 | end: 68 | nop 69 | -------------------------------------------------------------------------------- /assembler/paintHeadAndTail.txt: -------------------------------------------------------------------------------- 1 | ;initializes snake and then paints head with 1 and tail with ff in memory 2 | ;look at memory addresses 0x400 to 0x410 for the head and tail pixels 3 | 4 | define appleL $00 ; screen location of apple, low byte 5 | define appleH $01 ; screen location of apple, high byte 6 | define snakeHeadH $11 ; screen location of snake head, high byte 7 | define snakeBodyStart $12 ; start of snake body byte pairs 8 | define snakeDirection $02 ; direction (possible values are below) 9 | 10 | ; Directions (each using a separate bit) 11 | define movingUp 1 12 | define movingRight 2 13 | define movingDown 4 14 | define movingLeft 8 15 | 16 | 17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | 19 | define snakeLength $03 ; snake length, in bytes 20 | define snakeHeadL $10 ; screen location of snake head, low byte 21 | 22 | jsr initSnake 23 | jsr drawSnake 24 | jmp end 25 | 26 | 27 | initSnake: 28 | lda #movingRight ;start direction 29 | sta snakeDirection 30 | 31 | lda #4 ;start length (2 segments) 32 | sta snakeLength 33 | 34 | lda #$11 35 | sta snakeHeadL 36 | 37 | lda #$10 38 | sta snakeBodyStart 39 | 40 | lda #$0f 41 | sta $14 ; body segment 1 42 | 43 | lda #$04 44 | sta snakeHeadH 45 | sta $13 ; body segment 1 46 | sta $15 ; body segment 2 47 | rts 48 | 49 | drawSnake: 50 | ldx snakeLength 51 | lda #$ff 52 | sta (snakeHeadL,x) ; erase end of tail 53 | 54 | ldx #0 55 | lda #1 56 | sta (snakeHeadL,x) ; paint head 57 | rts 58 | 59 | end: 60 | nop 61 | -------------------------------------------------------------------------------- /assembler/references/addressing modes.txt: -------------------------------------------------------------------------------- 1 | absolute (DONE) 2 | zp (DONE) 3 | zpx (DONE) 4 | zpy (DONE) 5 | absx (DONE) 6 | absy (DONE) 7 | imm (DONE) 8 | implicit (DONE) 9 | indirect (DONE except for strings) 10 | indexed indirect (x) (add register to address, get value from new address) (DONE) 11 | indirect indexed (y) (get value from address, add register to value) (DONE) 12 | relative (DONE?) -------------------------------------------------------------------------------- /assembler/references/opcodes.txt: -------------------------------------------------------------------------------- 1 | opcodes = { 2 | '---': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 3 | 'ADC': {'SNGL': 'null', 'INDY': '0x71', 'Imm': '0x69', 'INDX': '0x61', 'ZPX': '0x75', 'ABS': '0x6d', 'ABSY': '0x79', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x65', 'ABSX': '0x7d'} 4 | 'AND': {'SNGL': 'null', 'INDY': '0x31', 'Imm': '0x29', 'INDX': '0x21', 'ZPX': '0x35', 'ABS': '0x2d', 'ABSY': '0x39', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x25', 'ABSX': '0x3d'} 5 | 'ASL': {'SNGL': '0x0a', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0x16', 'ABS': '0x0e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x06', 'ABSX': '0x1e'} 6 | 'BCC': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0x90', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 7 | 'BCS': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0xb0', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 8 | 'BEQ': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0xf0', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 9 | 'BIT': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0x2c', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x24', 'ABSX': 'null'} 10 | 'BMI': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0x30', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 11 | 'BNE': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0xd0', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 12 | 'BPL': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0x10', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 13 | 'BRK': {'SNGL': '0x00', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 14 | 'BVC': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0x50', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 15 | 'BVS': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': '0x70', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 16 | 'CLC': {'SNGL': '0x18', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 17 | 'CLD': {'SNGL': '0xd8', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 18 | 'CLI': {'SNGL': '0x58', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 19 | 'CLV': {'SNGL': '0xb8', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 20 | 'CMP': {'SNGL': 'null', 'INDY': '0xd1', 'Imm': '0xc9', 'INDX': '0xc1', 'ZPX': '0xd5', 'ABS': '0xcd', 'ABSY': '0xd9', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xc5', 'ABSX': '0xdd'} 21 | 'CPX': {'SNGL': 'null', 'INDY': 'null', 'Imm': '0xe0', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0xec', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xe4', 'ABSX': 'null'} 22 | 'CPY': {'SNGL': 'null', 'INDY': 'null', 'Imm': '0xc0', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0xcc', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xc4', 'ABSX': 'null'} 23 | 'DEC': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0xd6', 'ABS': '0xce', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xc6', 'ABSX': '0xde'} 24 | 'DEX': {'SNGL': '0xca', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 25 | 'DEY': {'SNGL': '0x88', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 26 | 'EOR': {'SNGL': 'null', 'INDY': '0x51', 'Imm': '0x49', 'INDX': '0x41', 'ZPX': '0x55', 'ABS': '0x4d', 'ABSY': '0x59', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x45', 'ABSX': '0x5d'} 27 | 'INC': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0xf6', 'ABS': '0xee', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xe6', 'ABSX': '0xfe'} 28 | 'INX': {'SNGL': '0xe8', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 29 | 'INY': {'SNGL': '0xc8', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 30 | 'JMP': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0x4c', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': '0x6c', 'ZP': 'null', 'ABSX': 'null'} 31 | 'JSR': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0x20', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 32 | 'LDA': {'SNGL': 'null', 'INDY': '0xb1', 'Imm': '0xa9', 'INDX': '0xa1', 'ZPX': '0xb5', 'ABS': '0xad', 'ABSY': '0xb9', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xa5', 'ABSX': '0xbd'} 33 | 'LDX': {'SNGL': 'null', 'INDY': 'null', 'Imm': '0xa2', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0xae', 'ABSY': '0xbe', 'BRA': 'null', 'ZPY': '0xb6', 'IND': 'null', 'ZP': '0xa6', 'ABSX': 'null'} 34 | 'LDY': {'SNGL': 'null', 'INDY': 'null', 'Imm': '0xa0', 'INDX': 'null', 'ZPX': '0xb4', 'ABS': '0xac', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xa4', 'ABSX': '0xbc'} 35 | 'LSR': {'SNGL': '0x4a', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0x56', 'ABS': '0x4e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x46', 'ABSX': '0x5e'} 36 | 'NOP': {'SNGL': '0xea', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 37 | 'ORA': {'SNGL': 'null', 'INDY': '0x11', 'Imm': '0x09', 'INDX': '0x01', 'ZPX': '0x15', 'ABS': '0x0d', 'ABSY': '0x19', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x05', 'ABSX': '0x1d'} 38 | 'PHA': {'SNGL': '0x48', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 39 | 'PHP': {'SNGL': '0x08', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 40 | 'PLA': {'SNGL': '0x68', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 41 | 'PLP': {'SNGL': '0x28', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 42 | 'ROL': {'SNGL': '0x2a', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0x36', 'ABS': '0x2e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x26', 'ABSX': '0x3e'} 43 | 'ROR': {'SNGL': '0x6a', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0x76', 'ABS': '0x6e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x66', 'ABSX': '0x7e'} 44 | 'RTI': {'SNGL': '0x40', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 45 | 'RTS': {'SNGL': '0x60', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 46 | 'SBC': {'SNGL': 'null', 'INDY': '0xf1', 'Imm': '0xe9', 'INDX': '0xe1', 'ZPX': '0xf5', 'ABS': '0xed', 'ABSY': '0xf9', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0xe5', 'ABSX': '0xfd'} 47 | 'SEC': {'SNGL': '0x38', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 48 | 'SED': {'SNGL': '0xf8', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 49 | 'SEI': {'SNGL': '0x78', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 50 | 'STA': {'SNGL': 'null', 'INDY': '0x91', 'Imm': 'null', 'INDX': '0x81', 'ZPX': '0x95', 'ABS': '0x8d', 'ABSY': '0x99', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x85', 'ABSX': '0x9d'} 51 | 'STX': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': '0x8e', 'ABSY': 'null', 'BRA': 'null', 'ZPY': '0x96', 'IND': 'null', 'ZP': '0x86', 'ABSX': 'null'} 52 | 'STY': {'SNGL': 'null', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': '0x94', 'ABS': '0x8c', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x84', 'ABSX': 'null'} 53 | 'TAX': {'SNGL': '0xaa', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 54 | 'TAY': {'SNGL': '0xa8', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 55 | 'TSX': {'SNGL': '0xba', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 56 | 'TXA': {'SNGL': '0x8a', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 57 | 'TXS': {'SNGL': '0x9a', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 58 | 'TYA': {'SNGL': '0x98', 'INDY': 'null', 'Imm': 'null', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': 'null', 'ABSX': 'null'} 59 | 'WDM': {'SNGL': 'null', 'INDY': 'null', 'Imm': '0x42', 'INDX': 'null', 'ZPX': 'null', 'ABS': 'null', 'ABSY': 'null', 'BRA': 'null', 'ZPY': 'null', 'IND': 'null', 'ZP': '0x42', 'ABSX': 'null'} 60 | } -------------------------------------------------------------------------------- /assembler/references/parseOpcodes.py: -------------------------------------------------------------------------------- 1 | keys = ['Imm', 'ZP', 'ZPX', 'ZPY', 'ABS', 'ABSX', 'ABSY', 'IND', 'INDX', 'INDY', 'SNGL', 'BRA'] 2 | null = 'null' 3 | opcodes = { 4 | "ADC": [ 0x69, 0x65, 0x75, null, 0x6d, 0x7d, 0x79, null, 0x61, 0x71, null, null], 5 | "AND": [ 0x29, 0x25, 0x35, null, 0x2d, 0x3d, 0x39, null, 0x21, 0x31, null, null], 6 | "ASL": [ null, 0x06, 0x16, null, 0x0e, 0x1e, null, null, null, null, 0x0a, null], 7 | "BIT": [ null, 0x24, null, null, 0x2c, null, null, null, null, null, null, null], 8 | "BPL": [ null, null, null, null, null, null, null, null, null, null, null, 0x10], 9 | "BMI": [ null, null, null, null, null, null, null, null, null, null, null, 0x30], 10 | "BVC": [ null, null, null, null, null, null, null, null, null, null, null, 0x50], 11 | "BVS": [ null, null, null, null, null, null, null, null, null, null, null, 0x70], 12 | "BCC": [ null, null, null, null, null, null, null, null, null, null, null, 0x90], 13 | "BCS": [ null, null, null, null, null, null, null, null, null, null, null, 0xb0], 14 | "BNE": [ null, null, null, null, null, null, null, null, null, null, null, 0xd0], 15 | "BEQ": [ null, null, null, null, null, null, null, null, null, null, null, 0xf0], 16 | "BRK": [ null, null, null, null, null, null, null, null, null, null, 0x00, null], 17 | "CMP": [ 0xc9, 0xc5, 0xd5, null, 0xcd, 0xdd, 0xd9, null, 0xc1, 0xd1, null, null], 18 | "CPX": [ 0xe0, 0xe4, null, null, 0xec, null, null, null, null, null, null, null], 19 | "CPY": [ 0xc0, 0xc4, null, null, 0xcc, null, null, null, null, null, null, null], 20 | "DEC": [ null, 0xc6, 0xd6, null, 0xce, 0xde, null, null, null, null, null, null], 21 | "EOR": [ 0x49, 0x45, 0x55, null, 0x4d, 0x5d, 0x59, null, 0x41, 0x51, null, null], 22 | "CLC": [ null, null, null, null, null, null, null, null, null, null, 0x18, null], 23 | "SEC": [ null, null, null, null, null, null, null, null, null, null, 0x38, null], 24 | "CLI": [ null, null, null, null, null, null, null, null, null, null, 0x58, null], 25 | "SEI": [ null, null, null, null, null, null, null, null, null, null, 0x78, null], 26 | "CLV": [ null, null, null, null, null, null, null, null, null, null, 0xb8, null], 27 | "CLD": [ null, null, null, null, null, null, null, null, null, null, 0xd8, null], 28 | "SED": [ null, null, null, null, null, null, null, null, null, null, 0xf8, null], 29 | "INC": [ null, 0xe6, 0xf6, null, 0xee, 0xfe, null, null, null, null, null, null], 30 | "JMP": [ null, null, null, null, 0x4c, null, null, 0x6c, null, null, null, null], 31 | "JSR": [ null, null, null, null, 0x20, null, null, null, null, null, null, null], 32 | "LDA": [ 0xa9, 0xa5, 0xb5, null, 0xad, 0xbd, 0xb9, null, 0xa1, 0xb1, null, null], 33 | "LDX": [ 0xa2, 0xa6, null, 0xb6, 0xae, null, 0xbe, null, null, null, null, null], 34 | "LDY": [ 0xa0, 0xa4, 0xb4, null, 0xac, 0xbc, null, null, null, null, null, null], 35 | "LSR": [ null, 0x46, 0x56, null, 0x4e, 0x5e, null, null, null, null, 0x4a, null], 36 | "NOP": [ null, null, null, null, null, null, null, null, null, null, 0xea, null], 37 | "ORA": [ 0x09, 0x05, 0x15, null, 0x0d, 0x1d, 0x19, null, 0x01, 0x11, null, null], 38 | "TAX": [ null, null, null, null, null, null, null, null, null, null, 0xaa, null], 39 | "TXA": [ null, null, null, null, null, null, null, null, null, null, 0x8a, null], 40 | "DEX": [ null, null, null, null, null, null, null, null, null, null, 0xca, null], 41 | "INX": [ null, null, null, null, null, null, null, null, null, null, 0xe8, null], 42 | "TAY": [ null, null, null, null, null, null, null, null, null, null, 0xa8, null], 43 | "TYA": [ null, null, null, null, null, null, null, null, null, null, 0x98, null], 44 | "DEY": [ null, null, null, null, null, null, null, null, null, null, 0x88, null], 45 | "INY": [ null, null, null, null, null, null, null, null, null, null, 0xc8, null], 46 | "ROR": [ null, 0x66, 0x76, null, 0x6e, 0x7e, null, null, null, null, 0x6a, null], 47 | "ROL": [ null, 0x26, 0x36, null, 0x2e, 0x3e, null, null, null, null, 0x2a, null], 48 | "RTI": [ null, null, null, null, null, null, null, null, null, null, 0x40, null], 49 | "RTS": [ null, null, null, null, null, null, null, null, null, null, 0x60, null], 50 | "SBC": [ 0xe9, 0xe5, 0xf5, null, 0xed, 0xfd, 0xf9, null, 0xe1, 0xf1, null, null], 51 | "STA": [ null, 0x85, 0x95, null, 0x8d, 0x9d, 0x99, null, 0x81, 0x91, null, null], 52 | "TXS": [ null, null, null, null, null, null, null, null, null, null, 0x9a, null], 53 | "TSX": [ null, null, null, null, null, null, null, null, null, null, 0xba, null], 54 | "PHA": [ null, null, null, null, null, null, null, null, null, null, 0x48, null], 55 | "PLA": [ null, null, null, null, null, null, null, null, null, null, 0x68, null], 56 | "PHP": [ null, null, null, null, null, null, null, null, null, null, 0x08, null], 57 | "PLP": [ null, null, null, null, null, null, null, null, null, null, 0x28, null], 58 | "STX": [ null, 0x86, null, 0x96, 0x8e, null, null, null, null, null, null, null], 59 | "STY": [ null, 0x84, 0x94, null, 0x8c, null, null, null, null, null, null, null], 60 | "WDM": [ 0x42, 0x42, null, null, null, null, null, null, null, null, null, null], 61 | "---": [ null, null, null, null, null, null, null, null, null, null, null, null] 62 | } 63 | 64 | f = open("opcodes.txt", "w") 65 | for opcode in sorted(opcodes): 66 | newDict = {} 67 | for i in range(12): 68 | if opcodes[opcode][i] is not 'null': 69 | code = hex(int(opcodes[opcode][i]))[2:] 70 | if int(code,16) < 16: 71 | code = "0" + str(code) 72 | newDict[keys[i]] = "0x" + code 73 | else: 74 | newDict[keys[i]] = opcodes[opcode][i] 75 | opcodes[opcode] = newDict 76 | f.write("\'" + str(opcode) + "\': " + str(opcodes[opcode]) + "\n") 77 | f.close() -------------------------------------------------------------------------------- /assembler/snake.txt: -------------------------------------------------------------------------------- 1 | JSR $0606 2 | JSR $0638 3 | JSR $060d 4 | JSR $062a 5 | RTS 6 | LDA #$02 7 | STA $02 8 | LDA #$04 9 | STA $03 10 | LDA #$11 11 | STA $10 12 | LDA #$10 13 | STA $12 14 | LDA #$0f 15 | STA $14 16 | LDA #$04 17 | STA $11 18 | STA $13 19 | STA $15 20 | RTS 21 | LDA $fe 22 | STA $00 23 | LDA $fe 24 | AND #$03 25 | CLC 26 | ADC #$02 27 | STA $01 28 | RTS 29 | JSR $064d 30 | JSR $068d 31 | JSR $06c3 32 | JSR $0719 33 | JSR $0720 34 | JSR $072d 35 | JMP $0638 36 | LDA $ff 37 | CMP #$77 38 | BEQ $0660 39 | CMP #$64 40 | BEQ $066b 41 | CMP #$73 42 | BEQ $0676 43 | CMP #$61 44 | BEQ $0681 45 | RTS 46 | LDA #$04 47 | BIT $02 48 | BNE $068c 49 | LDA #$01 50 | STA $02 51 | RTS 52 | LDA #$08 53 | BIT $02 54 | BNE $068c 55 | LDA #$02 56 | STA $02 57 | RTS 58 | LDA #$01 59 | BIT $02 60 | BNE $068c 61 | LDA #$04 62 | STA $02 63 | RTS 64 | LDA #$02 65 | BIT $02 66 | BNE $068c 67 | LDA #$08 68 | STA $02 69 | RTS 70 | RTS 71 | JSR $0694 72 | JSR $06a8 73 | RTS 74 | LDA $00 75 | CMP $10 76 | BNE $06a7 77 | LDA $01 78 | CMP $11 79 | BNE $06a7 80 | INC $03 81 | INC $03 82 | JSR $062a 83 | RTS 84 | LDX #$02 85 | LDA $10,X 86 | CMP $10 87 | BNE $06b6 88 | LDA $11,X 89 | CMP $11 90 | BEQ $06bf 91 | INX 92 | INX 93 | CPX $03 94 | BEQ $06c2 95 | JMP $06aa 96 | JMP $0735 97 | RTS 98 | LDX $03 99 | DEX 100 | TXA 101 | LDA $10,X 102 | STA $12,X 103 | DEX 104 | BPL $06c7 105 | LDA $02 106 | LSR A 107 | BCS $06dc 108 | LSR A 109 | BCS $06ef 110 | LSR A 111 | BCS $06f8 112 | LSR A 113 | BCS $070b 114 | LDA $10 115 | SEC 116 | SBC #$20 117 | STA $10 118 | BCC $06e6 119 | RTS 120 | DEC $11 121 | LDA #$01 122 | CMP $11 123 | BEQ $0716 124 | RTS 125 | INC $10 126 | LDA #$1f 127 | BIT $10 128 | BEQ $0716 129 | RTS 130 | LDA $10 131 | CLC 132 | ADC #$20 133 | STA $10 134 | BCS $0702 135 | RTS 136 | INC $11 137 | LDA #$06 138 | CMP $11 139 | BEQ $0716 140 | RTS 141 | DEC $10 142 | LDA $10 143 | AND #$1f 144 | CMP #$1f 145 | BEQ $0716 146 | RTS 147 | JMP $0735 148 | LDY #$00 149 | LDA $fe 150 | STA ($00),Y 151 | RTS 152 | LDX $03 153 | LDA #$00 154 | STA ($10,X) 155 | LDX #$00 156 | LDA #$01 157 | STA ($10,X) 158 | RTS 159 | LDX #$00 160 | NOP 161 | NOP 162 | DEX 163 | BNE $072f 164 | RTS 165 | -------------------------------------------------------------------------------- /assembler/temp1.txt: -------------------------------------------------------------------------------- 1 | LDA #$02 2 | STA $02 3 | LDA #$04 4 | STA $03 5 | LDA #$11 6 | STA $10 7 | LDA #$10 8 | STA $12 9 | LDA #$0f 10 | STA $14 11 | LDA #$04 12 | STA $11 13 | STA $13 14 | STA $15 15 | -------------------------------------------------------------------------------- /assembler/update.txt: -------------------------------------------------------------------------------- 1 | define appleL $00 ; screen location of apple, low byte 2 | define appleH $01 ; screen location of apple, high byte 3 | define snakeHeadL $10 ; screen location of snake head, low byte 4 | define snakeHeadH $11 ; screen location of snake head, high byte 5 | define snakeBodyStart $12 ; start of snake body byte pairs 6 | define snakeDirection $02 ; direction (possible values are below) 7 | define snakeLength $03 ; snake length, in bytes 8 | 9 | ; Directions (each using a separate bit) 10 | define movingUp 1 11 | define movingRight 2 12 | define movingDown 4 13 | define movingLeft 8 14 | 15 | ; ASCII values of keys controlling the snake 16 | define ASCII_w $77 17 | define ASCII_a $61 18 | define ASCII_s $73 19 | define ASCII_d $64 20 | 21 | ; System variables 22 | define sysRandom $fe 23 | define sysLastKey $ff 24 | 25 | jsr initSnake 26 | jsr updateSnake 27 | jmp notGameOver 28 | 29 | initSnake: 30 | lda #movingRight ;start direction 31 | sta snakeDirection 32 | 33 | lda #4 ;start length (2 segments) 34 | sta snakeLength 35 | 36 | lda #$11 37 | sta snakeHeadL 38 | 39 | lda #$10 40 | sta snakeBodyStart 41 | 42 | lda #$0f 43 | sta $14 ; body segment 1 44 | 45 | lda #$04 46 | sta snakeHeadH 47 | sta $13 ; body segment 1 48 | sta $15 ; body segment 2 49 | rts 50 | 51 | updateSnake: 52 | ldx snakeLength 53 | dex 54 | txa 55 | updateloop: 56 | lda snakeHeadL,x 57 | sta snakeBodyStart,x 58 | dex 59 | bpl updateloop 60 | 61 | lda snakeDirection 62 | lsr 63 | bcs up 64 | lsr 65 | bcs right 66 | lsr 67 | bcs down 68 | lsr 69 | bcs left 70 | up: 71 | lda snakeHeadL 72 | sec 73 | sbc #$20 74 | sta snakeHeadL 75 | bcc upup 76 | rts 77 | upup: 78 | dec snakeHeadH 79 | lda #$1 80 | cmp snakeHeadH 81 | beq collision 82 | rts 83 | right: 84 | inc snakeHeadL 85 | lda #$1f 86 | bit snakeHeadL 87 | beq collision 88 | rts 89 | down: 90 | lda snakeHeadL 91 | clc 92 | adc #$20 93 | sta snakeHeadL 94 | bcs downdown 95 | rts 96 | downdown: 97 | inc snakeHeadH 98 | lda #$6 99 | cmp snakeHeadH 100 | beq collision 101 | rts 102 | left: 103 | dec snakeHeadL 104 | lda snakeHeadL 105 | and #$1f 106 | cmp #$1f 107 | beq collision 108 | rts 109 | collision: 110 | jmp gameOver 111 | 112 | gameOver: 113 | ldy #$bb 114 | jmp end 115 | 116 | notGameOver: 117 | ldy #$aa 118 | jmp end 119 | 120 | end: 121 | nop 122 | -------------------------------------------------------------------------------- /hexdump/apple: -------------------------------------------------------------------------------- 1 | 20 09 06 20 17 06 20 1e 06 a5 fe 85 00 a5 fe 29 03 18 69 02 85 01 60 a0 00 a9 ff 91 00 60 ea 2 | -------------------------------------------------------------------------------- /hexdump/branching: -------------------------------------------------------------------------------- 1 | a2 08 ca 8e 00 02 e0 03 d0 f8 8e 01 02 00 2 | -------------------------------------------------------------------------------- /hexdump/checkCollision: -------------------------------------------------------------------------------- 1 | 20 06 06 20 23 06 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a2 02 b5 10 c5 10 d0 06 b5 11 c5 11 f0 09 e8 e8 e4 03 f0 08 4c 25 06 a0 aa 4c 44 06 a0 bb 4c 44 06 ea 2 | -------------------------------------------------------------------------------- /hexdump/colorTest: -------------------------------------------------------------------------------- 1 | a9 01 8d 00 02 a9 05 8d 01 02 a9 08 8d 02 02 2 | -------------------------------------------------------------------------------- /hexdump/fibonacci: -------------------------------------------------------------------------------- 1 | a2 01 86 00 38 a0 07 98 e9 03 a8 18 a9 02 85 01 a6 01 65 00 85 01 86 00 88 d0 f5 2 | -------------------------------------------------------------------------------- /hexdump/inc: -------------------------------------------------------------------------------- 1 | e6 10 2 | -------------------------------------------------------------------------------- /hexdump/indexedInd: -------------------------------------------------------------------------------- 1 | a2 01 a9 05 85 01 a9 06 85 02 a0 0a 8c 05 06 a1 00 2 | -------------------------------------------------------------------------------- /hexdump/indirect: -------------------------------------------------------------------------------- 1 | a9 01 85 f0 a9 cc 85 f1 6c f0 00 2 | -------------------------------------------------------------------------------- /hexdump/indirectInd: -------------------------------------------------------------------------------- 1 | a0 01 a9 03 85 01 a9 07 85 02 a2 0a 8e 04 07 b1 01 2 | -------------------------------------------------------------------------------- /hexdump/indirectMode: -------------------------------------------------------------------------------- 1 | a9 01 85 f0 a9 cc 85 f1 6c f0 00 2 | -------------------------------------------------------------------------------- /hexdump/initSnake: -------------------------------------------------------------------------------- 1 | 20 09 06 20 26 06 4c 33 06 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a2 00 a9 01 81 10 a6 03 a9 00 81 10 60 ea ea 2 | -------------------------------------------------------------------------------- /hexdump/instructions: -------------------------------------------------------------------------------- 1 | a9 c0 aa e8 69 c4 00 2 | -------------------------------------------------------------------------------- /hexdump/jsr: -------------------------------------------------------------------------------- 1 | 20 09 06 20 0c 06 20 12 06 a2 00 60 e8 e0 05 d0 fb 60 2 | -------------------------------------------------------------------------------- /hexdump/jump: -------------------------------------------------------------------------------- 1 | a9 03 4c 08 06 00 00 00 8d 00 02 2 | -------------------------------------------------------------------------------- /hexdump/paintErase: -------------------------------------------------------------------------------- 1 | 20 0c 06 20 29 06 20 36 06 4c 43 06 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a6 03 a9 ff 81 10 a2 00 a9 01 81 10 60 a6 03 a9 00 81 10 a2 00 a9 00 81 10 60 ea 2 | -------------------------------------------------------------------------------- /hexdump/paintHeadAndTail: -------------------------------------------------------------------------------- 1 | 20 09 06 20 26 06 4c 33 06 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a6 03 a9 ff 81 10 a2 00 a9 01 81 10 60 ea 2 | -------------------------------------------------------------------------------- /hexdump/relative: -------------------------------------------------------------------------------- 1 | a9 01 c9 02 d0 02 85 22 00 2 | -------------------------------------------------------------------------------- /hexdump/snake: -------------------------------------------------------------------------------- 1 | 20 06 06 20 38 06 20 0d 06 20 2a 06 60 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a5 fe 85 00 a5 fe 29 03 18 69 02 85 01 60 20 4d 06 20 8d 06 20 c3 06 20 19 07 20 20 07 20 2d 07 4c 38 06 a5 ff c9 77 f0 0d c9 64 f0 14 c9 73 f0 1b c9 61 f0 22 60 a9 04 24 02 d0 26 a9 01 85 02 60 a9 08 24 02 d0 1b a9 02 85 02 60 a9 01 24 02 d0 10 a9 04 85 02 60 a9 02 24 02 d0 05 a9 08 85 02 60 60 20 94 06 20 a8 06 60 a5 00 c5 10 d0 0d a5 01 c5 11 d0 07 e6 03 e6 03 20 2a 06 60 a2 02 b5 10 c5 10 d0 06 b5 11 c5 11 f0 09 e8 e8 e4 03 f0 06 4c aa 06 4c 35 07 60 a6 03 ca 8a b5 10 95 12 ca 10 f9 a5 02 4a b0 09 4a b0 19 4a b0 1f 4a b0 2f a5 10 38 e9 20 85 10 90 01 60 c6 11 a9 01 c5 11 f0 28 60 e6 10 a9 1f 24 10 f0 1f 60 a5 10 18 69 20 85 10 b0 01 60 e6 11 a9 06 c5 11 f0 0c 60 c6 10 a5 10 29 1f c9 1f f0 01 60 4c 35 07 a0 00 a5 fe 91 00 60 a6 03 a9 00 81 10 a2 00 a9 01 81 10 60 a2 ff ea ea ca d0 fb 60 2 | -------------------------------------------------------------------------------- /hexdump/snakeFast: -------------------------------------------------------------------------------- 1 | 20 06 06 20 38 06 20 0d 06 20 2a 06 60 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a5 fe 85 00 a5 fe 29 03 18 69 02 85 01 60 20 4d 06 20 8d 06 20 c3 06 20 19 07 20 20 07 20 2d 07 4c 38 06 a5 ff c9 77 f0 0d c9 64 f0 14 c9 73 f0 1b c9 61 f0 22 60 a9 04 24 02 d0 26 a9 01 85 02 60 a9 08 24 02 d0 1b a9 02 85 02 60 a9 01 24 02 d0 10 a9 04 85 02 60 a9 02 24 02 d0 05 a9 08 85 02 60 60 20 94 06 20 a8 06 60 a5 00 c5 10 d0 0d a5 01 c5 11 d0 07 e6 03 e6 03 20 2a 06 60 a2 02 b5 10 c5 10 d0 06 b5 11 c5 11 f0 09 e8 e8 e4 03 f0 06 4c aa 06 4c 30 07 60 a6 03 ca 8a b5 10 95 12 ca 10 f9 a5 02 4a b0 09 4a b0 19 4a b0 1f 4a b0 2f a5 10 38 e9 20 85 10 90 01 60 c6 11 a9 01 c5 11 f0 28 60 e6 10 a9 1f 24 10 f0 1f 60 a5 10 18 69 20 85 10 b0 01 60 e6 11 a9 06 c5 11 f0 0c 60 c6 10 a5 10 29 1f c9 1f f0 01 60 4c 30 07 a0 00 a5 fe 91 00 60 a6 03 a9 00 81 10 a2 00 a9 01 81 10 60 a2 00 60 2 | -------------------------------------------------------------------------------- /hexdump/snakeUpdate: -------------------------------------------------------------------------------- 1 | 20 09 06 20 26 06 4c 81 06 a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 60 a6 03 ca 8a b5 10 95 12 ca 10 f9 a5 02 4a b0 09 4a b0 19 4a b0 1f 4a b0 2f a5 10 38 e9 20 85 10 90 01 60 c6 11 a9 01 c5 11 f0 28 60 e6 10 a9 1f 24 10 f0 1f 60 a5 10 18 69 20 85 10 b0 01 60 e6 11 a9 06 c5 11 f0 0c 60 c6 10 a5 10 29 1f c9 1f f0 01 60 4c 7c 06 a0 bb 4c 86 06 a0 aa 4c 86 06 ea 2 | -------------------------------------------------------------------------------- /hexdump/stack: -------------------------------------------------------------------------------- 1 | a2 00 a0 00 8a 99 00 02 48 e8 c8 c0 10 d0 f5 68 99 00 02 c8 c0 20 d0 f7 2 | -------------------------------------------------------------------------------- /hexdump/temp1: -------------------------------------------------------------------------------- 1 | a9 02 85 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 14 a9 04 85 11 85 13 85 15 2 | -------------------------------------------------------------------------------- /runSnake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ./tools 4 | make all 5 | cd ../bin 6 | clear 7 | ./runSnake 8 | -------------------------------------------------------------------------------- /snake/runSnake.c: -------------------------------------------------------------------------------- 1 | #include //to seed RNG and for sleeping in game loop 2 | #include "../src/load_prog.h" 3 | #include "../src/gfx.h" 4 | #include "../src/keyboard.h" 5 | #include "../src/cpu.h" 6 | #include "../src/load_prog.h" 7 | 8 | int PIXEL_SIZE = 20; 9 | int SCREEN_SIZE = 32; 10 | 11 | void drawPoint(int x, int y){ 12 | //draws point onto 'pixel' (actually a 8 by 8 square) 13 | int cornerX = x * PIXEL_SIZE; 14 | int cornerY = y * PIXEL_SIZE; 15 | gfx_rectangle(cornerX,cornerY,PIXEL_SIZE,PIXEL_SIZE); 16 | } 17 | 18 | void initializegfx(){ 19 | int ysize = SCREEN_SIZE*PIXEL_SIZE; 20 | int xsize = SCREEN_SIZE*PIXEL_SIZE; 21 | gfx_open(xsize,ysize,"Snake"); 22 | gfx_color(255,255,255); 23 | return; 24 | } 25 | 26 | void visualizeMemory(CPU *c){ 27 | //visualizes memory addresses $0200 to $05ff 28 | //(32 by 32 bytes) 29 | //as a SCREEN_SIZE*PIXEL_SIZE by SCREEN_SIZE*PIXEL_SIZE pixel square 30 | gfx_clear(); 31 | int x = 0; 32 | int y = 0; 33 | int i; 34 | for(i = 0x0200; i < 0x0600; i++){ 35 | uint8_t memVal = c->addressSpace[i]; 36 | if(memVal == 1){ 37 | //in the snake game a memory val 38 | //of 1 represents a white color. 39 | //this special if statement is 40 | //because 1 needs to be mapped 41 | //to (255,255,255) in RGB 42 | gfx_color(255,255,255); 43 | drawPoint(x,y); 44 | } else if (memVal > 0){ 45 | //this is to convert between 46 | //a memVal between 0-255 and 47 | //three 0-255 vals representing R,G,B 48 | //red is the first 3 bits 49 | uint8_t red = memVal & 0xE0; 50 | //blue is the next 3 bits 51 | uint8_t blue = (memVal << 3) & 0xE0; 52 | //green is the last 2 53 | uint8_t green = (memVal << 6) & 0xE0; 54 | gfx_color(red,blue,green); 55 | drawPoint(x,y); 56 | } else {} 57 | x++; 58 | if(x == 32){ 59 | x = 0; 60 | y++; 61 | } 62 | } 63 | gfx_flush(); 64 | } 65 | 66 | void getKeyboardInput(CPU *c){ 67 | //reads keyboard input and 68 | //sets memory location $ff 69 | //to match keyboard input 70 | int dir = getDirection(); 71 | switch(dir){ 72 | case 0: 73 | //printf("left"); 74 | c->addressSpace[0xff] = 0x61; 75 | break; 76 | case 1: 77 | //printf("right"); 78 | c->addressSpace[0xff] = 0x64; 79 | break; 80 | case 2: 81 | //printf("up"); 82 | c->addressSpace[0xff] = 0x77; 83 | break; 84 | case 3: 85 | //printf("down"); 86 | c->addressSpace[0xff] = 0x73; 87 | break; 88 | } 89 | } 90 | 91 | void getRandomVal(CPU *c){ 92 | //loads a random byte into $FE of 93 | //the cpu's memory (this is specifically 94 | //to get the snake game implementation 95 | //working and is NOT something the 6502 96 | //actually ever does 97 | uint8_t randNum = rand(); 98 | c->addressSpace[0xfe] = randNum; 99 | } 100 | 101 | void initializerng(){ 102 | //initialize random number generator 103 | srand(time(NULL)); 104 | } 105 | 106 | void runSnake(CPU *c, int16_t end) { 107 | initializerng(); 108 | int counter = 0; 109 | while (c->PC < end){ 110 | getKeyboardInput(c); 111 | getRandomVal(c); 112 | run_op(c); 113 | visualizeMemory(c); 114 | nanosleep((const struct timespec[]){{0, 50000L}}, NULL); 115 | } 116 | } 117 | 118 | void countdown(){ 119 | int counter = 3; 120 | int sleepTime = 1; 121 | printf("Game starting in 3 seconds!\n"); 122 | sleep(sleepTime); 123 | while(counter > 0){ 124 | printf("%d\n",counter); 125 | sleep(sleepTime); 126 | counter--; 127 | } 128 | printf("GO!\n"); 129 | } 130 | 131 | int main() { 132 | uint16_t programStart = 0x0600; 133 | CPU *c = getCPU(); 134 | c->PC = programStart; 135 | int argc = 2; 136 | char *argv[2] = {"./runSnake", "../hexdump/snake"}; 137 | int16_t end = load_program(argc, argv, c->addressSpace, programStart); 138 | printf("Focus in this terminal and press W,A,S,D to move the snake. Collect the apples and avoid colliding with the wall or yourself. Good luck!\n"); 139 | initializegfx(); 140 | countdown(); 141 | runSnake(c, end); 142 | int finalScore = read(c,0x0003)/2-2; 143 | printf("\nSorry, you lose! Your final score was %d\n!",finalScore); 144 | freeCPU(c); 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /src/cpu.c: -------------------------------------------------------------------------------- 1 | #include "cpu.h" 2 | 3 | /* sets a single bit of one of the eight bit 4 | * registers on CPU to val */ 5 | void setRegBit(CPU *c, REG name, int8_t bit, int8_t val){ 6 | //bit must be between 0 and 7 since registers 7 | //are 8 bits 8 | assert(bit > -1 && bit < 8); 9 | //only setting one bit so val must be 0 or 1 10 | assert (val == 0 || val == 1); 11 | c->regs[name] = (c->regs[name] & ~(1 << bit)) | 12 | (val << bit); 13 | } 14 | 15 | int8_t getRegBit(CPU *c, REG name, int8_t bit){ 16 | //bit must be between 0 and 7 since registers 17 | //are 8 bits 18 | assert(bit > -1 && bit < 8); 19 | return (c->regs[name] & (1 << bit)) > 0 ? 1 : 0; 20 | } 21 | 22 | /* CPU initializer */ 23 | CPU * getCPU(){ 24 | CPU *c = malloc(sizeof(CPU)); 25 | //programs start at 0x600 in memory 26 | c->PC = 0; 27 | //initialize 8 bit registers 28 | int NUM_REG = 5; 29 | int8_t *r = calloc(NUM_REG,sizeof(int8_t)); 30 | c-> regs = r; 31 | //initialize address space 32 | int ADDR_SPACE_SIZE = 65536; 33 | int8_t *a= calloc(ADDR_SPACE_SIZE,sizeof(int8_t)); 34 | c-> addressSpace = a; 35 | //set bit 5 of status register to 1 36 | //to match specifications 37 | setRegBit(c, STATUS, 5, 1); 38 | //initialize stack pointer to 256 (it grows downwards 39 | //towards zero) 40 | setRegByte(c, STACK, 0xFF); 41 | return c; 42 | } 43 | 44 | void resetCPU(CPU *c){ 45 | //resets CPU to initial state as if it has just been initialized 46 | int NUM_REG = 5; 47 | memset(c->regs, 0, NUM_REG*sizeof(int8_t)); 48 | int ADDR_SPACE_SIZE = 65536; 49 | memset(c->addressSpace, 0, ADDR_SPACE_SIZE*sizeof(int8_t)); 50 | c->PC = 0; 51 | setRegBit(c, STATUS, 5, 1); 52 | } 53 | 54 | void freeCPU(CPU *c){ 55 | free(c->regs); 56 | free(c->addressSpace); 57 | free(c); 58 | } 59 | 60 | /* prints state of CPU registers */ 61 | void print(CPU *c){ 62 | printf("PC: "); 63 | printf("%x\n", c->PC); 64 | printf("SVUBDIZC\n"); 65 | printf("%s\n",getStatus(c)); 66 | printf("STACK REG: "); 67 | uint8_t stackVal = 0xFF & c->regs[STACK]; 68 | printf("%x\n", stackVal); 69 | printf("ACCUM REG: "); 70 | uint8_t accumVal = 0xFF & c->regs[ACCUM]; 71 | printf("%x\n", accumVal); 72 | printf("IND_X REG: "); 73 | uint8_t xVal = 0xFF & c->regs[IND_X]; 74 | printf("%x\n", xVal); 75 | printf("IND_Y REG: "); 76 | uint8_t yVal = 0xFF & c->regs[IND_Y]; 77 | printf("%x\n", yVal); 78 | } 79 | 80 | void printAddressLine(CPU *c, uint16_t beg){ 81 | //prints 16 hex vals starting from beg 82 | uint16_t counter = beg; 83 | while(counter < (beg + 16) && counter < 65536){ 84 | printf(" %02x", c->addressSpace[counter]&0xFF); 85 | counter++; 86 | } 87 | printf("\n"); 88 | } 89 | 90 | void printAddressSpace(CPU *c, uint16_t beg, uint16_t end){ 91 | //prints address space from beg to end 92 | //prints 16 8-bit vals at a time as hex 93 | uint16_t counter = beg; 94 | while(counter < end){ 95 | printf("%03x: ",counter); 96 | printAddressLine(c, counter); 97 | counter += 16; 98 | } 99 | } 100 | 101 | char *getStatus(CPU *c){ 102 | return byte_to_binary(c->regs[STATUS]); 103 | } 104 | 105 | char *byte_to_binary(int x){ 106 | char *b = malloc(sizeof(char)*9); 107 | b[0] = '\0'; 108 | int z; 109 | for (z = 128; z > 0; z >>= 1) 110 | { 111 | strcat(b, ((x & z) == z) ? "1" : "0"); 112 | } 113 | return b; 114 | } 115 | 116 | /* set byte value in one of the eight bit 117 | * registers to val */ 118 | void setRegByte(CPU *c, REG name, int8_t val){ 119 | c->regs[name] = val; 120 | } 121 | 122 | int8_t getRegByte(CPU *c, REG name){ 123 | return c->regs[name]; 124 | } 125 | 126 | void setFlag(CPU *c, FLAG name, int8_t val){ 127 | //bit 5 of the status register is not to be set 128 | //and should always be 1 129 | assert(name != NOT_USED_FLAG); 130 | setRegBit(c, STATUS, name, val); 131 | } 132 | 133 | int8_t getFlag(CPU *c, FLAG name){ 134 | //bit 5 of the status register is not to be set 135 | //and should always be 1 136 | assert(name != NOT_USED_FLAG); 137 | return getRegBit(c, STATUS, name); 138 | } 139 | 140 | int8_t read(CPU *c, uint16_t addr){ 141 | return c->addressSpace[addr]; 142 | } 143 | 144 | void write(CPU *c, uint16_t addr, int8_t val){ 145 | c->addressSpace[addr] = val; 146 | } 147 | 148 | /* FLAG REG OPERATIONS */ 149 | 150 | void setCarry(CPU *c, int16_t val){ 151 | //sets carry flag if 152 | //val > 0b11111111, largest 153 | //eight bit val 154 | int8_t carry = val > 0xFF ? 1 : 0; 155 | setFlag(c,C,carry); 156 | } 157 | 158 | void setCarryBCD(CPU *c, int16_t val){ 159 | //sets carry flag if 160 | //val > 0x99, for addition in BCD mode 161 | int8_t carry = val > 0x99 ? 1 : 0; 162 | setFlag(c,C,carry); 163 | } 164 | 165 | void setOverflow(CPU *c, int8_t a, int8_t b, int8_t val){ 166 | //sets overflow if overflow in twos complement 167 | //occurred when adding a and b to get val 168 | //this bit twiddling from: 169 | //http://nesdev.com/6502.txt 170 | int8_t overflow = !((a ^ b) & 0x80) && ((a ^ val) & 0x80); 171 | //overflow = signs of operands are the same AND 172 | // sign of result not equal to sign of operands 173 | setFlag(c,V,overflow); 174 | } 175 | 176 | void setOverflowSubtract(CPU *c, int8_t a, int8_t b, int8_t val){ 177 | //sets overflow if overflow in twos complement 178 | //occurred when subtracting b from a to get val 179 | //this bit twiddling from: 180 | //http://nesdev.com/6502.txt 181 | int8_t overflow = ((a ^ b) & 0x80) && ((a ^ val) & 0x80); 182 | //overflow = signs of operands are the same AND 183 | // sign of result not equal to sign of operands 184 | setFlag(c,V,overflow); 185 | } 186 | 187 | void setSign(CPU *c, int8_t val){ 188 | //sets sign flag equal to sign 189 | //of bit 7 of val 190 | int8_t sign = val & 0x80? 1 : 0; 191 | setFlag(c,S,sign); 192 | } 193 | 194 | void setZero(CPU *c, int8_t val){ 195 | //sets zero flag to 0 if val == 0 196 | //and zero flag to 1 otherwise 197 | int8_t isZero = val? 0 : 1 ; 198 | setFlag(c,Z,isZero); 199 | } 200 | 201 | OP_CODE_INFO * getOP_CODE_INFO(int8_t operand, uint16_t address, MODE mode){ 202 | OP_CODE_INFO *o = malloc(sizeof(OP_CODE_INFO)); 203 | o->operand = operand; 204 | o->address = address; 205 | o->mode = mode; 206 | return o; 207 | } 208 | 209 | void freeOP_CODE_INFO(OP_CODE_INFO *o){ 210 | free(o); 211 | } 212 | 213 | void run_op(CPU *c){ 214 | //runs a single operation based on whatever 215 | //is loaded into CPU memory, changing 216 | //hardware state appropriately. 217 | uint8_t opCode = c->addressSpace[c->PC]; 218 | if(strcmp(instructionNames[opCode],"FUT") == 0){ 219 | printf("Future opcode not implemented yet!"); 220 | assert(0); 221 | } 222 | OP_CODE_INFO *o; 223 | //printf("%s\n",instructionNames[opCode]); 224 | uint8_t mode = instructionModes[opCode]; 225 | uint16_t address; 226 | int8_t operand; 227 | switch(mode){ 228 | case UNUSED: 229 | printf("Error! unused instruction mode!"); 230 | assert(0); 231 | break; 232 | case modeAbsolute: 233 | //piece together 16 bit address from 2 bytes 234 | //following op code 235 | { 236 | //curly braces to allow for variable declaration 237 | //inside of case statement 238 | uint8_t lowerByte = c->addressSpace[c->PC+1]; 239 | uint8_t upperByte = c->addressSpace[c->PC+2]; 240 | uint16_t address = (upperByte << 8) | lowerByte; 241 | o = getOP_CODE_INFO(0, address, mode); 242 | } 243 | break; 244 | case modeAbsoluteX: 245 | { 246 | uint8_t lowerByte = c->addressSpace[c->PC+1]; 247 | uint8_t upperByte = c->addressSpace[c->PC+2]; 248 | uint16_t address = (upperByte << 8) | lowerByte; 249 | uint16_t xVal = getRegByte(c,IND_X); 250 | o = getOP_CODE_INFO(0, address+xVal, mode); 251 | } 252 | break; 253 | case modeAbsoluteY: 254 | { 255 | uint8_t lowerByte = c->addressSpace[c->PC+1]; 256 | uint8_t upperByte = c->addressSpace[c->PC+2]; 257 | uint16_t address = (upperByte << 8) | lowerByte; 258 | uint16_t yVal = getRegByte(c,IND_Y); 259 | o = getOP_CODE_INFO(0, address+yVal, mode); 260 | } 261 | break; 262 | case modeAccumulator: 263 | address = 0; //ADDRESS IS NOT APPLICABLE IN THIS MODE 264 | operand = getRegByte(c,ACCUM); 265 | o = getOP_CODE_INFO(operand, address, mode); 266 | break; 267 | case modeImmediate: 268 | address = c->PC + 1; 269 | operand = c->addressSpace[address]; 270 | o = getOP_CODE_INFO(operand, address, mode); 271 | break; 272 | case modeImplied: 273 | address = c->PC; 274 | o = getOP_CODE_INFO(0, address, mode); 275 | break; 276 | case modeIndexedIndirect: 277 | { 278 | uint16_t immediateVal = c->addressSpace[c->PC + 1]; 279 | uint16_t xVal = getRegByte(c,IND_X); 280 | uint8_t lowerByte = c->addressSpace[immediateVal+xVal]; 281 | uint8_t upperByte = c->addressSpace[immediateVal+xVal+1]; 282 | address = (upperByte << 8) | lowerByte; 283 | operand = c->addressSpace[address]; 284 | o = getOP_CODE_INFO(operand, address, mode); 285 | } 286 | break; 287 | case modeIndirect: 288 | { 289 | uint8_t lowerByte = c->addressSpace[c->PC+1]; 290 | uint8_t upperByte = c->addressSpace[c->PC+2]; 291 | uint16_t address = (upperByte << 8) | lowerByte; 292 | uint8_t l = c->addressSpace[address]; 293 | uint8_t u = c->addressSpace[address+1]; 294 | uint16_t finalAddress = (u << 8) | l; 295 | o = getOP_CODE_INFO(0, finalAddress, mode); 296 | } 297 | break; 298 | case modeIndirectIndexed: 299 | { 300 | uint16_t immediateVal = c->addressSpace[c->PC + 1]; 301 | uint8_t lowerByte = c->addressSpace[immediateVal]; 302 | uint8_t upperByte = c->addressSpace[immediateVal+1]; 303 | uint16_t yVal = getRegByte(c,IND_Y); 304 | address = ((upperByte << 8) | lowerByte) + yVal; 305 | operand = c->addressSpace[address]; 306 | o = getOP_CODE_INFO(operand, address, mode); 307 | } 308 | break; 309 | case modeRelative: 310 | //for branching within +-128 311 | { 312 | int16_t offset = c->addressSpace[c->PC + 1]; 313 | address = c->PC + 2 + offset; 314 | o = getOP_CODE_INFO(0, address, mode); 315 | } 316 | break; 317 | case modeZeroPage: 318 | address = 0x00FF & c->addressSpace[c->PC + 1]; 319 | operand = c->addressSpace[address]; 320 | o = getOP_CODE_INFO(operand, address, mode); 321 | break; 322 | case modeZeroPageX: 323 | { 324 | address = 0x00FF & c->addressSpace[c->PC + 1]; 325 | int8_t xVal = getRegByte(c,IND_X); 326 | address += xVal; 327 | operand = c->addressSpace[address]; 328 | o = getOP_CODE_INFO(operand, address, mode); 329 | } 330 | break; 331 | case modeZeroPageY: 332 | { 333 | address = 0x00FF & c->addressSpace[c->PC + 1]; 334 | int8_t yVal = getRegByte(c,IND_Y); 335 | address += yVal; 336 | operand = c->addressSpace[address]; 337 | o = getOP_CODE_INFO(operand, address, mode); 338 | } 339 | break; 340 | } 341 | c->PC += instructionSizes[opCode]; 342 | opcodeToFunction[opCode](c,o); 343 | freeOP_CODE_INFO(o); 344 | } 345 | 346 | /* STACK OPERATIONS HERE */ 347 | void PUSH(CPU *c, int8_t operand){ 348 | uint8_t stackVal = getRegByte(c, STACK); 349 | //0x0100 hardcoded in because stack 350 | //lives in 0x0100 to 0x01FF area of 351 | //memory 352 | uint16_t address = 0x0100 | stackVal; 353 | write(c, address, operand); 354 | uint8_t newStackVal = stackVal - 1; 355 | setRegByte(c, STACK, newStackVal); 356 | } 357 | 358 | int8_t PULL(CPU *c){ 359 | uint8_t stackVal = getRegByte(c, STACK); 360 | uint8_t newStackVal = stackVal + 1; 361 | setRegByte(c, STACK, newStackVal); 362 | //0x0100 hardcoded in because stack 363 | //lives in 0x0100 to 0x01FF area of 364 | //memory 365 | uint16_t address = 0x0100 | newStackVal; 366 | return read(c, address); 367 | } 368 | 369 | /* OP CODE IMPLEMENTATIONS HERE */ 370 | 371 | //Add with carry 372 | void adc(CPU *c, OP_CODE_INFO *o){ 373 | int8_t carry = getFlag(c,C); 374 | int8_t accum = getRegByte(c,ACCUM); 375 | int8_t operand = o->operand; 376 | int16_t sum = (0x00FF&carry) + (0x00FF&accum) + (0x00FF&operand); 377 | int8_t sumByte = sum & 0x00FF; 378 | setZero(c,sumByte); 379 | if(getFlag(c,D)){ //in decimal mode 380 | //if lower 4 bits of operands plus 381 | //the carry in are larger than 9, 382 | //then we need to apply conversions 383 | //to remain in binary coded decimal format. 384 | if((accum & 0xF) + (operand & 0xF) 385 | + carry > 9){ 386 | sum += 6; 387 | } 388 | setSign(c,sum&0xFF); 389 | setOverflow(c,accum,operand,sum&0xFF); 390 | //if the higher bits aren't in 391 | //BCD format we need to add 96 to convert. 392 | //Black magic from http://nesdev.com/6502.txt 393 | sum += sum > 0x99 ? 96 : 0; 394 | setCarryBCD(c, sum); 395 | } else { 396 | setSign(c,sumByte); 397 | setOverflow(c,accum,operand,sumByte); 398 | setCarry(c,sum); 399 | } 400 | setRegByte(c,ACCUM,sum&0xFF); 401 | } 402 | 403 | void and(CPU *c, OP_CODE_INFO *o){ 404 | int8_t accum = getRegByte(c,ACCUM); 405 | int8_t operand = o->operand; 406 | int8_t res = accum & operand; 407 | setSign(c,res); 408 | setZero(c,res); 409 | setRegByte(c,ACCUM,res); 410 | } 411 | 412 | //Arithmetic shift left 413 | void asl(CPU *c, OP_CODE_INFO *o){ 414 | int8_t operand = o->operand; 415 | int16_t res = (0x00FF&operand) << 1; 416 | int8_t resByte = res & 0x00FF; 417 | setCarry(c,res); 418 | setSign(c,resByte); 419 | setZero(c,resByte); 420 | if(o->mode == modeAccumulator){ 421 | setRegByte(c,ACCUM,res); 422 | } else { 423 | write(c,o->address,res); 424 | } 425 | } 426 | 427 | //Branch if carry clear 428 | void bcc(CPU *c, OP_CODE_INFO *o){ 429 | if(!getFlag(c,C)){ 430 | c->PC = o->address; 431 | //TODO: cpu add branch cycles here 432 | } 433 | } 434 | 435 | //Branch if carry set 436 | void bcs(CPU *c, OP_CODE_INFO *o){ 437 | if(getFlag(c,C)){ 438 | c->PC = o->address; 439 | //TODO: cpu add branch cycles here 440 | } 441 | } 442 | 443 | //Branch if equals 444 | void beq(CPU *c, OP_CODE_INFO *o){ 445 | if(getFlag(c,Z)){ 446 | c->PC = o->address; 447 | //TODO: cpu add branch cycles here 448 | } 449 | } 450 | 451 | // Test bits in memory with accumulator 452 | void bit(CPU *c, OP_CODE_INFO *o){ 453 | int8_t src = o->operand; 454 | int8_t accum = getRegByte(c, ACCUM); 455 | setFlag(c, V, (src & 0x40) ? 1 : 0); // get 6th bit of src 456 | setFlag(c, S, (src & 0x80) ? 1 : 0); // get 7th bit of src 457 | setFlag(c, Z, (src & accum) ? 0 : 1); 458 | } 459 | 460 | // Branch if result minus 461 | void bmi(CPU *c, OP_CODE_INFO *o){ 462 | if (getFlag(c, S)) { 463 | c->PC = o->address; 464 | //TODO: cpu add branch cycles here 465 | } 466 | } 467 | 468 | // Branch if not equals 469 | void bne(CPU *c, OP_CODE_INFO *o){ 470 | if(!(getFlag(c,Z))){ 471 | c->PC = o->address; 472 | //TODO: cpu add branch cycles here 473 | } 474 | } 475 | 476 | // Branch if result plus 477 | void bpl(CPU *c, OP_CODE_INFO *o){ 478 | if(!(getFlag(c,S))){ 479 | c->PC = o->address; 480 | //TODO: cpu add branch cycles here 481 | } 482 | } 483 | 484 | // TODO BRK 485 | // Force Break 486 | void brk(CPU *c, OP_CODE_INFO *o){ 487 | (c->PC)++; // this could be between 0 and 3. 488 | PUSH(c, (c->PC >> 8) & 0xff); // Push return address onto the stack. 489 | PUSH(c, c->PC & 0xff); // (push Program Counter AND 0xFF) 490 | setFlag(c, B, 1); 491 | PUSH(c, getRegByte(c, STATUS)); // (push status register onto top of stack) 492 | setFlag(c, I, 1); 493 | uint8_t lowerByte = c->addressSpace[0xFFFE]; 494 | uint8_t upperByte = c->addressSpace[0xFFFF]; 495 | uint16_t returnAddress = (upperByte << 8) | lowerByte; 496 | //c->PC = returnAddress; 497 | } 498 | 499 | // Branch if overflow clear 500 | void bvc(CPU *c, OP_CODE_INFO *o){ 501 | if (!(getFlag(c, V))){ 502 | c->PC = o->address; 503 | //TODO: add clk cycles here 504 | } 505 | } 506 | 507 | //Branch on overflow set 508 | void bvs(CPU *c, OP_CODE_INFO *o){ 509 | if (getFlag(c, V)){ 510 | c->PC = o->address; 511 | //TODO: add clk cycles here 512 | } 513 | } 514 | 515 | //Clear carry flag 516 | void clc(CPU *c, __attribute__ ((unused)) OP_CODE_INFO *o){ 517 | setFlag(c, C, 0); 518 | } 519 | 520 | //Clear decimal mode 521 | void cld(CPU *c, __attribute__ ((unused)) OP_CODE_INFO *o){ 522 | setFlag(c, D, 0); 523 | } 524 | 525 | //Clear interrupt disable bit 526 | void cli(CPU *c, __attribute__ ((unused)) OP_CODE_INFO *o){ 527 | setFlag(c, I, 0); 528 | } 529 | 530 | //Clear overflow flag 531 | void clv(CPU *c, __attribute__ ((unused)) OP_CODE_INFO *o){ 532 | setFlag(c, V, 0); 533 | } 534 | 535 | //Compare memory and accumulator 536 | void cmp(CPU *c, OP_CODE_INFO *o){ 537 | int8_t accum = getRegByte(c,ACCUM); 538 | int8_t operand = o->operand; 539 | int8_t diff = accum-operand; 540 | //longdiff is used to calculate whether a carry occurred 541 | uint16_t longDiff = (0x00FF&accum) - (0x00FF&operand); 542 | setFlag(c, C, longDiff < 0x100); 543 | setFlag(c, S, (diff & 0x80) ? 1 : 0); // get 7th bit of src 544 | setFlag(c, Z, diff ? 0 : 1); 545 | } 546 | 547 | //Compare memory and index x 548 | void cpx(CPU *c, OP_CODE_INFO *o){ 549 | int8_t xVal = getRegByte(c,IND_X); 550 | int8_t operand = o->operand; 551 | int8_t diff = xVal-operand; 552 | //longdiff is used to calculate whether a carry occurred 553 | uint16_t longDiff = (0x00FF&xVal) - (0x00FF&operand); 554 | setFlag(c, C, longDiff < 0x100); 555 | setFlag(c, S, (diff & 0x80) ? 1 : 0); // get 7th bit of src 556 | setFlag(c, Z, diff ? 0 : 1); 557 | } 558 | 559 | //Compare memory and index y 560 | void cpy(CPU *c, OP_CODE_INFO *o){ 561 | int8_t yVal = getRegByte(c,IND_Y); 562 | int8_t operand = o->operand; 563 | int8_t diff = yVal-operand; 564 | //longdiff is used to calculate whether a carry occurred 565 | uint16_t longDiff = (0x00FF&yVal) - (0x0FF&operand); 566 | setFlag(c, C, longDiff < 0x100); 567 | setFlag(c, S, (diff & 0x80) ? 1 : 0); // get 7th bit of src 568 | setFlag(c, Z, diff ? 0 : 1); 569 | } 570 | 571 | //Decrement byte at specified address by 1 572 | void dec(CPU *c, OP_CODE_INFO *o){ 573 | uint8_t operand = o->operand; 574 | uint8_t res = operand - 1; 575 | setSign(c,res); 576 | setZero(c,res); 577 | c->addressSpace[o->address] = res; 578 | } 579 | 580 | //Decrement X index by 1 581 | void dex(CPU *c, OP_CODE_INFO *o){ 582 | uint8_t xVal = getRegByte(c, IND_X); 583 | uint8_t res = xVal - 1; 584 | setSign(c,res); 585 | setZero(c,res); 586 | setRegByte(c, IND_X, res); 587 | } 588 | 589 | //Decrement Y index by 1 590 | void dey(CPU *c, OP_CODE_INFO *o){ 591 | uint8_t yVal = getRegByte(c, IND_Y); 592 | uint8_t res = yVal - 1; 593 | setSign(c,res); 594 | setZero(c,res); 595 | setRegByte(c, IND_Y, res); 596 | } 597 | 598 | //Unimplemented future function that will error 599 | //when called 600 | void fut(CPU *c, OP_CODE_INFO *o){ 601 | printf("Error! Called unimplemented future function!"); 602 | assert(0); 603 | } 604 | 605 | //Increments specified address by 1 606 | void inc(CPU *c, OP_CODE_INFO *o){ 607 | uint8_t operand = o->operand; 608 | uint8_t res = operand + 1; 609 | setSign(c,res); 610 | setZero(c,res); 611 | c->addressSpace[o->address] = res; 612 | } 613 | 614 | //Increment X index by 1 615 | void inx(CPU *c, OP_CODE_INFO *o){ 616 | uint8_t xVal = getRegByte(c, IND_X); 617 | uint8_t res = xVal + 1; 618 | setSign(c,res); 619 | setZero(c,res); 620 | setRegByte(c, IND_X, res); 621 | } 622 | 623 | //Increment Y index by 1 624 | void iny(CPU *c, OP_CODE_INFO *o){ 625 | uint8_t yVal = getRegByte(c, IND_Y); 626 | uint8_t res = yVal + 1; 627 | setSign(c,res); 628 | setZero(c,res); 629 | setRegByte(c, IND_Y, res); 630 | } 631 | 632 | //Jump PC to 16 bit operand 633 | void jmp(CPU *c, OP_CODE_INFO *o){ 634 | c->PC = 0xFFFF&(o->address); 635 | } 636 | 637 | //Jump to subroutine 638 | void jsr(CPU *c, OP_CODE_INFO *o){ 639 | //decrement PC because PC will be 640 | //incremented by one when it jumps back 641 | c->PC--; 642 | //STACK holds eight bit values 643 | //so we push the 16 bit address 644 | //onto the stack in two parts 645 | uint8_t upperByte = ((c->PC)>>8) & 0xFF; 646 | uint8_t lowerByte = c->PC; 647 | PUSH(c, upperByte); 648 | PUSH(c, lowerByte); 649 | c->PC = o->address; 650 | } 651 | 652 | //Load value into accumulator 653 | void lda(CPU *c, OP_CODE_INFO *o){ 654 | setSign(c, o->operand); 655 | setZero(c, o->operand); 656 | setRegByte(c, ACCUM, o->operand); 657 | } 658 | 659 | //Load value into x reg 660 | void ldx(CPU *c, OP_CODE_INFO *o){ 661 | setSign(c, o->operand); 662 | setZero(c, o->operand); 663 | setRegByte(c, IND_X, o->operand); 664 | } 665 | 666 | //Load value into y reg 667 | void ldy(CPU *c, OP_CODE_INFO *o){ 668 | setSign(c, o->operand); 669 | setZero(c, o->operand); 670 | setRegByte(c, IND_Y, o->operand); 671 | } 672 | 673 | //Logical shift right with zero fill 674 | void lsr(CPU *c, OP_CODE_INFO *o){ 675 | //shift rightmost bit into carry 676 | setFlag(c, C, o->operand & 0x01); 677 | //cast to uint8_t to force zero fill 678 | int8_t shifted = ((uint8_t)o->operand) >> 1; 679 | setSign(c, shifted); 680 | setZero(c, shifted); 681 | if(o->mode == modeAccumulator){ 682 | setRegByte(c, ACCUM, shifted); 683 | } else { 684 | write(c, o->address, shifted); 685 | } 686 | } 687 | 688 | // No operation 689 | void nop(CPU *c, OP_CODE_INFO *o){} 690 | 691 | // OR memory with accumulator 692 | void ora(CPU *c, OP_CODE_INFO *o){ 693 | int8_t src = o->operand | getRegByte(c, ACCUM); 694 | printf("FUNCTION NOT IMPLEMENTED CORRECTLY!"); 695 | assert(0); 696 | //setFlag(c, Z, src); 697 | //setFlag(c, S, src); 698 | setRegByte(c, ACCUM, src); 699 | } 700 | 701 | // Push accumulator onto stack 702 | void pha(CPU *c, OP_CODE_INFO *o){ 703 | PUSH(c, getRegByte(c, ACCUM)); 704 | } 705 | 706 | // Push status register onto stack 707 | void php(CPU *c, OP_CODE_INFO *o){ 708 | PUSH(c, getRegByte(c, STATUS)); 709 | } 710 | 711 | // Pull accumulator from stack 712 | void pla(CPU *c, OP_CODE_INFO *o){ 713 | int8_t accumVal = PULL(c); 714 | setRegByte(c, ACCUM, accumVal); 715 | setSign(c,accumVal); 716 | setZero(c,accumVal); 717 | } 718 | 719 | // Pull status register from stack 720 | void plp(CPU *c, OP_CODE_INFO *o){ 721 | assert(0); 722 | // setRegByte(c, STATUS, PULL(c)); 723 | } 724 | 725 | void rts(CPU *c, OP_CODE_INFO *o){ 726 | uint8_t lowerByte = PULL(c); 727 | uint8_t upperByte = PULL(c); 728 | //add 1 to address before we jump PC to it 729 | //in order to resume program at correct place 730 | uint16_t address = ((upperByte << 8) | lowerByte) + 1; 731 | c->PC = address; 732 | } 733 | 734 | // Subtract operand from accumulator with borrow 735 | void sbc(CPU *c, OP_CODE_INFO *o){ 736 | //we want to subtract the opposite of the carry bit 737 | int8_t carry = getFlag(c,C) ? 0 : 1; 738 | int8_t accum = getRegByte(c,ACCUM); 739 | int8_t operand = o->operand; 740 | uint16_t diff = (0x00FF&accum) - (0x00FF&operand) - (0x00FF&carry); 741 | setSign(c,diff&0xFF); 742 | setZero(c,diff&0xFF); 743 | setOverflowSubtract(c,accum,operand,diff&0xFF); 744 | if(getFlag(c,D)){ //in decimal mode 745 | if(((accum & 0xF) - carry) < (operand & 0xF)){ 746 | diff -= 6; 747 | } 748 | if(diff > 0x99){ 749 | diff -= 0x60; 750 | } 751 | } 752 | setFlag(c,C, diff < 0x100); 753 | setRegByte(c,ACCUM,diff&0xFF); 754 | } 755 | 756 | // Set carry flag to 1 757 | void sec(CPU *c, OP_CODE_INFO *o){ 758 | setFlag(c, C, 1); 759 | } 760 | 761 | // Store accumulator reg into memory 762 | void sta(CPU *c, OP_CODE_INFO *o){ 763 | write(c, o->address, getRegByte(c,ACCUM)); 764 | } 765 | 766 | // Store X reg into memory 767 | void stx(CPU *c, OP_CODE_INFO *o){ 768 | write(c, o->address, getRegByte(c,IND_X)); 769 | } 770 | 771 | // Store Y reg into memory 772 | void sty(CPU *c, OP_CODE_INFO *o){ 773 | write(c, o->address, getRegByte(c,IND_Y)); 774 | } 775 | 776 | // Transfer accumulator to Y reg 777 | void tay(CPU *c, OP_CODE_INFO *o){ 778 | int8_t accumVal = getRegByte(c,ACCUM); 779 | setSign(c,accumVal); 780 | setZero(c,accumVal); 781 | setRegByte(c,IND_Y,accumVal); 782 | } 783 | 784 | // Transfer Y to accumulator 785 | void tya(CPU *c, OP_CODE_INFO *o){ 786 | int8_t yVal = getRegByte(c,IND_Y); 787 | setSign(c,yVal); 788 | setZero(c,yVal); 789 | setRegByte(c,ACCUM,yVal); 790 | } 791 | 792 | // Transfer x to accumulator 793 | void txa(CPU *c, OP_CODE_INFO *o){ 794 | int8_t xVal = getRegByte(c,IND_X); 795 | setSign(c,xVal); 796 | setZero(c,xVal); 797 | setRegByte(c,ACCUM,xVal); 798 | } 799 | 800 | // Transfer accumulator to x 801 | void tax(CPU *c, OP_CODE_INFO *o){ 802 | int8_t accumVal = getRegByte(c,ACCUM); 803 | setSign(c,accumVal); 804 | setZero(c,accumVal); 805 | setRegByte(c,IND_X,accumVal); 806 | } 807 | 808 | // Exclusive OR memory with accumulator 809 | void eor(CPU *c, OP_CODE_INFO *o){ 810 | int8_t accumVal = getRegByte(c,ACCUM); 811 | int8_t newVal = accumVal ^ o->operand; 812 | setRegByte(c,ACCUM,newVal); 813 | setSign(c,newVal); 814 | setZero(c,newVal); 815 | } 816 | 817 | // Return from interrupt 818 | void rti(CPU *c, OP_CODE_INFO *o){ 819 | uint8_t status = PULL(c); 820 | setRegByte(c,STATUS,status); 821 | uint8_t lowerByte = PULL(c); 822 | uint8_t upperByte = PULL(c); 823 | uint16_t address = ((upperByte << 8) | lowerByte); 824 | c->PC = address; 825 | } 826 | 827 | // Rotate one bit left 828 | void rol(CPU *c, OP_CODE_INFO *o){ 829 | uint16_t src = (o->operand) << 1; 830 | if (getFlag(c,C)) { 831 | src |= 0x1; 832 | } 833 | setFlag(c,C,src > 0xFF); 834 | src &= 0xFF; 835 | setSign(c,src); 836 | setZero(c,src); 837 | if(o->mode == modeAccumulator){ 838 | setRegByte(c,ACCUM,src); 839 | } else { 840 | write(c,o->address,src); 841 | } 842 | } 843 | 844 | // Rotate one bit right 845 | void ror(CPU *c, OP_CODE_INFO *o){ 846 | uint16_t src = 0xFF & o->operand; 847 | if (getFlag(c,C)) { 848 | src |= 0x100; 849 | } 850 | setFlag(c,C,src & 0x01); 851 | src >>= 1; 852 | setSign(c,src); 853 | setZero(c,src); 854 | if(o->mode == modeAccumulator){ 855 | setRegByte(c,ACCUM,src); 856 | } else { 857 | write(c,o->address,src); 858 | } 859 | } 860 | 861 | // Set interrupt disable status 862 | void sei(CPU *c, OP_CODE_INFO *o){ 863 | setFlag(c,I,1); 864 | } 865 | 866 | // Transfer index X to stack pointer 867 | void txs(CPU *c, OP_CODE_INFO *o){ 868 | int8_t src = getRegByte(c,IND_X); 869 | setRegByte(c,STACK,src); 870 | } 871 | 872 | // Transfer stack pointer to index X 873 | void tsx(CPU *c, OP_CODE_INFO *o){ 874 | int8_t src = getRegByte(c,STACK); 875 | setRegByte(c,IND_X,src); 876 | } 877 | 878 | // Set decimal mode 879 | void sed(CPU *c, OP_CODE_INFO *o){ 880 | setFlag(c,D,1); 881 | } 882 | 883 | //from https://github.com/fogleman/nes/blob/master/nes/cpu.go 884 | uint8_t instructionSizes[256] = { 885 | 1, 2, 0, 0, 2, 2, 2, 0, 886 | 1, 2, 1, 0, 3, 3, 3, 0, 887 | 2, 2, 0, 0, 2, 2, 2, 0, 888 | 1, 3, 1, 0, 3, 3, 3, 0, 889 | 3, 2, 0, 0, 2, 2, 2, 0, 890 | 1, 2, 1, 0, 3, 3, 3, 0, 891 | 2, 2, 0, 0, 2, 2, 2, 0, 892 | 1, 3, 1, 0, 3, 3, 3, 0, 893 | 1, 2, 0, 0, 2, 2, 2, 0, 894 | 1, 2, 1, 0, 3, 3, 3, 0, 895 | 2, 2, 0, 0, 2, 2, 2, 0, 896 | 1, 3, 1, 0, 3, 3, 3, 0, 897 | 1, 2, 0, 0, 2, 2, 2, 0, 898 | 1, 2, 1, 0, 3, 3, 3, 0, 899 | 2, 2, 0, 0, 2, 2, 2, 0, 900 | 1, 3, 1, 0, 3, 3, 3, 0, 901 | 2, 2, 0, 0, 2, 2, 2, 0, 902 | 1, 0, 1, 0, 3, 3, 3, 0, 903 | 2, 2, 0, 0, 2, 2, 2, 0, 904 | 1, 3, 1, 0, 0, 3, 0, 0, 905 | 2, 2, 2, 0, 2, 2, 2, 0, 906 | 1, 2, 1, 0, 3, 3, 3, 0, 907 | 2, 2, 0, 0, 2, 2, 2, 0, 908 | 1, 3, 1, 0, 3, 3, 3, 0, 909 | 2, 2, 0, 0, 2, 2, 2, 0, 910 | 1, 2, 1, 0, 3, 3, 3, 0, 911 | 2, 2, 0, 0, 2, 2, 2, 0, 912 | 1, 3, 1, 0, 3, 3, 3, 0, 913 | 2, 2, 0, 0, 2, 2, 2, 0, 914 | 1, 2, 1, 0, 3, 3, 3, 0, 915 | 2, 2, 0, 0, 2, 2, 2, 0, 916 | 1, 3, 1, 0, 3, 3, 3, 0 917 | }; 918 | 919 | //from https://github.com/fogleman/nes/blob/master/nes/cpu.go 920 | uint8_t instructionModes[256] = { 921 | 6, 7, 6, 7, 11, 11, 11, 11, 6, 5, 4, 5, 1, 1, 1, 1, 922 | 10, 9, 6, 9, 12, 12, 12, 12, 6, 3, 6, 3, 2, 2, 2, 2, 923 | 1, 7, 6, 7, 11, 11, 11, 11, 6, 5, 4, 5, 1, 1, 1, 1, 924 | 10, 9, 6, 9, 12, 12, 12, 12, 6, 3, 6, 3, 2, 2, 2, 2, 925 | 6, 7, 6, 7, 11, 11, 11, 11, 6, 5, 4, 5, 1, 1, 1, 1, 926 | 10, 9, 6, 9, 12, 12, 12, 12, 6, 3, 6, 3, 2, 2, 2, 2, 927 | 6, 7, 6, 7, 11, 11, 11, 11, 6, 5, 4, 5, 8, 1, 1, 1, 928 | 10, 9, 6, 9, 12, 12, 12, 12, 6, 3, 6, 3, 2, 2, 2, 2, 929 | 5, 7, 5, 7, 11, 11, 11, 11, 6, 5, 6, 5, 1, 1, 1, 1, 930 | 10, 9, 6, 9, 12, 12, 13, 13, 6, 3, 6, 3, 2, 2, 3, 3, 931 | 5, 7, 5, 7, 11, 11, 11, 11, 6, 5, 6, 5, 1, 1, 1, 1, 932 | 10, 9, 6, 9, 12, 12, 13, 13, 6, 3, 6, 3, 2, 2, 3, 3, 933 | 5, 7, 5, 7, 11, 11, 11, 11, 6, 5, 6, 5, 1, 1, 1, 1, 934 | 10, 9, 6, 9, 12, 12, 12, 12, 6, 3, 6, 3, 2, 2, 2, 2, 935 | 5, 7, 5, 7, 11, 11, 11, 11, 6, 5, 6, 5, 1, 1, 1, 1, 936 | 10, 9, 6, 9, 12, 12, 12, 12, 6, 3, 6, 3, 2, 2, 2, 2 937 | }; 938 | 939 | //from https://github.com/fogleman/nes/blob/master/nes/cpu.go 940 | char instructionNames[256][4] = { 941 | //FUT represents unimplemented op codes 942 | "BRK", "ORA", "FUT", "FUT", "FUT", "ORA", "ASL", "FUT", 943 | "PHP", "ORA", "ASL", "FUT", "FUT", "ORA", "ASL", "FUT", 944 | "BPL", "ORA", "FUT", "FUT", "FUT", "ORA", "ASL", "FUT", 945 | "CLC", "ORA", "FUT", "FUT", "FUT", "ORA", "ASL", "FUT", 946 | "JSR", "AND", "FUT", "FUT", "BIT", "AND", "ROL", "FUT", 947 | "PLP", "AND", "ROL", "FUT", "BIT", "AND", "ROL", "FUT", 948 | "BMI", "AND", "FUT", "FUT", "FUT", "AND", "ROL", "FUT", 949 | "SEC", "AND", "FUT", "FUT", "FUT", "AND", "ROL", "FUT", 950 | "RTI", "EOR", "FUT", "FUT", "FUT", "EOR", "LSR", "FUT", 951 | "PHA", "EOR", "LSR", "FUT", "JMP", "EOR", "LSR", "FUT", 952 | "BVC", "EOR", "FUT", "FUT", "FUT", "EOR", "LSR", "FUT", 953 | "CLI", "EOR", "FUT", "FUT", "FUT", "EOR", "LSR", "FUT", 954 | "RTS", "ADC", "FUT", "FUT", "FUT", "ADC", "ROR", "FUT", 955 | "PLA", "ADC", "ROR", "FUT", "JMP", "ADC", "ROR", "FUT", 956 | "BVS", "ADC", "FUT", "FUT", "FUT", "ADC", "ROR", "FUT", 957 | "SEI", "ADC", "FUT", "FUT", "FUT", "ADC", "ROR", "FUT", 958 | "FUT", "STA", "FUT", "FUT", "STY", "STA", "STX", "FUT", 959 | "DEY", "FUT", "TXA", "FUT", "STY", "STA", "STX", "FUT", 960 | "BCC", "STA", "FUT", "FUT", "STY", "STA", "STX", "FUT", 961 | "TYA", "STA", "TXS", "FUT", "FUT", "STA", "FUT", "FUT", 962 | "LDY", "LDA", "LDX", "FUT", "LDY", "LDA", "LDX", "FUT", 963 | "TAY", "LDA", "TAX", "FUT", "LDY", "LDA", "LDX", "FUT", 964 | "BCS", "LDA", "FUT", "FUT", "LDY", "LDA", "LDX", "FUT", 965 | "CLV", "LDA", "TSX", "FUT", "LDY", "LDA", "LDX", "FUT", 966 | "CPY", "CMP", "FUT", "FUT", "CPY", "CMP", "DEC", "FUT", 967 | "INY", "CMP", "DEX", "FUT", "CPY", "CMP", "DEC", "FUT", 968 | "BNE", "CMP", "FUT", "FUT", "FUT", "CMP", "DEC", "FUT", 969 | "CLD", "CMP", "FUT", "FUT", "FUT", "CMP", "DEC", "FUT", 970 | "CPX", "SBC", "FUT", "FUT", "CPX", "SBC", "INC", "FUT", 971 | "INX", "SBC", "NOP", "FUT", "CPX", "SBC", "INC", "FUT", 972 | "BEQ", "SBC", "FUT", "FUT", "FUT", "SBC", "INC", "FUT", 973 | "SED", "SBC", "FUT", "FUT", "FUT", "SBC", "INC", "FUT" 974 | }; 975 | 976 | //from https://github.com/fogleman/nes/blob/master/nes/cpu.go 977 | void (*opcodeToFunction[256])(CPU *c, OP_CODE_INFO *o) = { 978 | brk, ora, fut, fut, fut, ora, asl, fut, 979 | php, ora, asl, fut, fut, ora, asl, fut, 980 | bpl, ora, fut, fut, fut, ora, asl, fut, 981 | clc, ora, fut, fut, fut, ora, asl, fut, 982 | jsr, and, fut, fut, bit, and, rol, fut, 983 | plp, and, rol, fut, bit, and, rol, fut, 984 | bmi, and, fut, fut, fut, and, rol, fut, 985 | sec, and, fut, fut, fut, and, rol, fut, 986 | rti, eor, fut, fut, fut, eor, lsr, fut, 987 | pha, eor, lsr, fut, jmp, eor, lsr, fut, 988 | bvc, eor, fut, fut, fut, eor, lsr, fut, 989 | cli, eor, fut, fut, fut, eor, lsr, fut, 990 | rts, adc, fut, fut, fut, adc, ror, fut, 991 | pla, adc, ror, fut, jmp, adc, ror, fut, 992 | bvs, adc, fut, fut, fut, adc, ror, fut, 993 | sei, adc, fut, fut, fut, adc, ror, fut, 994 | fut, sta, fut, fut, sty, sta, stx, fut, 995 | dey, fut, txa, fut, sty, sta, stx, fut, 996 | bcc, sta, fut, fut, sty, sta, stx, fut, 997 | tya, sta, txs, fut, fut, sta, fut, fut, 998 | ldy, lda, ldx, fut, ldy, lda, ldx, fut, 999 | tay, lda, tax, fut, ldy, lda, ldx, fut, 1000 | bcs, lda, fut, fut, ldy, lda, ldx, fut, 1001 | clv, lda, tsx, fut, ldy, lda, ldx, fut, 1002 | cpy, cmp, fut, fut, cpy, cmp, dec, fut, 1003 | iny, cmp, dex, fut, cpy, cmp, dec, fut, 1004 | bne, cmp, fut, fut, fut, cmp, dec, fut, 1005 | cld, cmp, fut, fut, fut, cmp, dec, fut, 1006 | cpx, sbc, fut, fut, cpx, sbc, inc, fut, 1007 | inx, sbc, nop, fut, cpx, sbc, inc, fut, 1008 | beq, sbc, fut, fut, fut, sbc, inc, fut, 1009 | sed, sbc, fut, fut, fut, sbc, inc, fut 1010 | }; 1011 | -------------------------------------------------------------------------------- /src/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef CPU_H_INCLUDED 2 | #define CPU_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef enum reg { 11 | //enums for 8 bit registers 12 | STATUS, STACK, ACCUM, IND_X, IND_Y 13 | } REG; 14 | 15 | typedef struct cpu { 16 | //CPU registers 17 | uint16_t PC; 18 | int8_t *regs; 19 | int8_t *addressSpace; 20 | } CPU; 21 | 22 | typedef enum mode { 23 | UNUSED, 24 | modeAbsolute, 25 | modeAbsoluteX, 26 | modeAbsoluteY, 27 | modeAccumulator, 28 | modeImmediate, 29 | modeImplied, 30 | modeIndexedIndirect, 31 | modeIndirect, 32 | modeIndirectIndexed, 33 | modeRelative, 34 | modeZeroPage, 35 | modeZeroPageX, 36 | modeZeroPageY 37 | } MODE; 38 | 39 | typedef struct op_code_info { 40 | //holds information that op codes 41 | //need to execute 42 | int8_t operand; 43 | //address that operand is fetched 44 | //from is needed for operations 45 | //like LSR 46 | uint16_t address; 47 | MODE mode; 48 | } OP_CODE_INFO; 49 | 50 | typedef enum flag { 51 | //enums specifying flag bits of the status register 52 | // C = carry 53 | // Z = zero 54 | // I = interrupt enable 55 | // D = decimal mode 56 | // B = enabled on BRK 57 | // V = overflow 58 | // S = sign 59 | C, Z, I, D, B, NOT_USED_FLAG, V, S 60 | } FLAG; 61 | 62 | int main(); 63 | void lsr(CPU *c,OP_CODE_INFO *o); 64 | void ldy(CPU *c,OP_CODE_INFO *o); 65 | void ldx(CPU *c,OP_CODE_INFO *o); 66 | void lda(CPU *c,OP_CODE_INFO *o); 67 | void jsr(CPU *c,OP_CODE_INFO *o); 68 | void jmp(CPU *c,OP_CODE_INFO *o); 69 | void cpy(CPU *c,OP_CODE_INFO *o); 70 | void cpx(CPU *c,OP_CODE_INFO *o); 71 | void cmp(CPU *c,OP_CODE_INFO *o); 72 | void clv(CPU *c,__attribute__((unused))OP_CODE_INFO *o); 73 | void cli(CPU *c,__attribute__((unused))OP_CODE_INFO *o); 74 | void cld(CPU *c,__attribute__((unused))OP_CODE_INFO *o); 75 | void clc(CPU *c,__attribute__((unused))OP_CODE_INFO *o); 76 | void dec(CPU *c, OP_CODE_INFO *o); 77 | void dex(CPU *c, OP_CODE_INFO *o); 78 | void dey(CPU *c, OP_CODE_INFO *o); 79 | void fut(CPU *c, OP_CODE_INFO *o); 80 | void inc(CPU *c, OP_CODE_INFO *o); 81 | void inx(CPU *c, OP_CODE_INFO *o); 82 | void bvs(CPU *c,OP_CODE_INFO *o); 83 | void bvc(CPU *c,OP_CODE_INFO *o); 84 | void brk(CPU *c,OP_CODE_INFO *o); 85 | void bpl(CPU *c,OP_CODE_INFO *o); 86 | void bne(CPU *c,OP_CODE_INFO *o); 87 | void bmi(CPU *c,OP_CODE_INFO *o); 88 | void bit(CPU *c,OP_CODE_INFO *o); 89 | void beq(CPU *c,OP_CODE_INFO *o); 90 | void bcs(CPU *c,OP_CODE_INFO *o); 91 | void bcc(CPU *c,OP_CODE_INFO *o); 92 | void asl(CPU *c,OP_CODE_INFO *o); 93 | void and(CPU *c,OP_CODE_INFO *o); 94 | void adc(CPU *c,OP_CODE_INFO *o); 95 | void nop(CPU *c, OP_CODE_INFO *o); 96 | void ora(CPU *c, OP_CODE_INFO *o); 97 | void pha(CPU *c, OP_CODE_INFO *o); 98 | void php(CPU *c, OP_CODE_INFO *o); 99 | void pla(CPU *c, OP_CODE_INFO *o); 100 | void plp(CPU *c, OP_CODE_INFO *o); 101 | void sbc(CPU *c, OP_CODE_INFO *o); 102 | void sec(CPU *c, OP_CODE_INFO *o); 103 | void sta(CPU *c, OP_CODE_INFO *o); 104 | void stx(CPU *c, OP_CODE_INFO *o); 105 | void tay(CPU *c, OP_CODE_INFO *o); 106 | void tya(CPU *c, OP_CODE_INFO *o); 107 | void txa(CPU *c, OP_CODE_INFO *o); 108 | void PUSH(CPU *c,int8_t operand); 109 | int8_t PULL(CPU *c); 110 | void setZero(CPU *c,int8_t val); 111 | void setSign(CPU *c,int8_t val); 112 | void setOverflow(CPU *c,int8_t a,int8_t b,int8_t val); 113 | void setCarryBCD(CPU *c,int16_t val); 114 | void setCarry(CPU *c,int16_t val); 115 | void write(CPU *c,uint16_t addr,int8_t val); 116 | int8_t read(CPU *c,uint16_t addr); 117 | int8_t getFlag(CPU *c,FLAG name); 118 | void setFlag(CPU *c,FLAG name,int8_t val); 119 | int8_t getRegByte(CPU *c,REG name); 120 | void setRegByte(CPU *c,REG name,int8_t val); 121 | void print(CPU *c); 122 | void printAddressLine(CPU *c, uint16_t beg); 123 | void printAddressSpace(CPU *c, uint16_t beg, uint16_t end); 124 | char * getStatus(CPU *c); 125 | CPU *getCPU(); 126 | void resetCPU(CPU *c); 127 | void freeCPU(CPU *c); 128 | OP_CODE_INFO *getOP_CODE_INFO(int8_t operand, uint16_t address, MODE mode); 129 | void freeOP_CODE_INFO(OP_CODE_INFO *o); 130 | void setRegBit(CPU *c,REG name,int8_t bit,int8_t val); 131 | int8_t getRegBit(CPU *c,REG name,int8_t bit); 132 | char *byte_to_binary(int x); 133 | void run_ops(CPU *c, int16_t end); 134 | void run_op(CPU *c); 135 | 136 | void eor(CPU *c, OP_CODE_INFO *o); 137 | void rol(CPU *c, OP_CODE_INFO *o); 138 | void ror(CPU *c, OP_CODE_INFO *o); 139 | void rts(CPU *c, OP_CODE_INFO *o); 140 | void rti(CPU *c, OP_CODE_INFO *o); 141 | void sei(CPU *c, OP_CODE_INFO *o); 142 | void sty(CPU *c, OP_CODE_INFO *o); 143 | void txs(CPU *c, OP_CODE_INFO *o); 144 | void tax(CPU *c, OP_CODE_INFO *o); 145 | void tsx(CPU *c, OP_CODE_INFO *o); 146 | void iny(CPU *c, OP_CODE_INFO *o); 147 | void sed(CPU *c, OP_CODE_INFO *o); 148 | 149 | extern uint8_t instructionSizes[256]; 150 | extern uint8_t instructionModes[256]; 151 | extern char instructionNames[256][4]; 152 | extern void (*opcodeToFunction[256])(CPU *c, OP_CODE_INFO *o); 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /src/gfx.c: -------------------------------------------------------------------------------- 1 | /* 2 | A simple graphics library for CSE 20211 by Douglas Thain 3 | For complete documentation, see: 4 | http://www.nd.edu/~dthain/courses/cse20211/fall2011/gfx 5 | Version 3, 11/07/2012 - Now much faster at changing colors rapidly. 6 | Version 2, 9/23/2011 - Fixes a bug that could result in jerky animation. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "gfx.h" 14 | 15 | /* 16 | gfx_open creates several X11 objects, and stores them in globals 17 | for use by the other functions in the library. 18 | */ 19 | 20 | static Display *gfx_display=0; 21 | static Window gfx_window; 22 | static GC gfx_gc; 23 | static Colormap gfx_colormap; 24 | static int gfx_fast_color_mode = 0; 25 | 26 | /* These values are saved by gfx_wait then retrieved later by gfx_xpos and gfx_ypos. */ 27 | 28 | static int saved_xpos = 0; 29 | static int saved_ypos = 0; 30 | 31 | /* Open a new graphics window. */ 32 | 33 | void gfx_open( int width, int height, const char *title ) 34 | { 35 | gfx_display = XOpenDisplay(0); 36 | if(!gfx_display) { 37 | fprintf(stderr,"gfx_open: unable to open the graphics window.\n"); 38 | exit(1); 39 | } 40 | 41 | Visual *visual = DefaultVisual(gfx_display,0); 42 | if(visual && visual->class==TrueColor) { 43 | gfx_fast_color_mode = 1; 44 | } else { 45 | gfx_fast_color_mode = 0; 46 | } 47 | 48 | int blackColor = BlackPixel(gfx_display, DefaultScreen(gfx_display)); 49 | int whiteColor = WhitePixel(gfx_display, DefaultScreen(gfx_display)); 50 | 51 | gfx_window = XCreateSimpleWindow(gfx_display, DefaultRootWindow(gfx_display), 0, 0, width, height, 0, blackColor, blackColor); 52 | 53 | XSetWindowAttributes attr; 54 | attr.backing_store = Always; 55 | 56 | XChangeWindowAttributes(gfx_display,gfx_window,CWBackingStore,&attr); 57 | 58 | XStoreName(gfx_display,gfx_window,title); 59 | 60 | XSelectInput(gfx_display, gfx_window, StructureNotifyMask|KeyPressMask|ButtonPressMask); 61 | 62 | XMapWindow(gfx_display,gfx_window); 63 | 64 | gfx_gc = XCreateGC(gfx_display, gfx_window, 0, 0); 65 | 66 | gfx_colormap = DefaultColormap(gfx_display,0); 67 | 68 | XSetForeground(gfx_display, gfx_gc, whiteColor); 69 | 70 | // Wait for the MapNotify event 71 | 72 | for(;;) { 73 | XEvent e; 74 | XNextEvent(gfx_display, &e); 75 | if (e.type == MapNotify) 76 | break; 77 | } 78 | } 79 | 80 | void gfx_rectangle( int x, int y, int width, int height ) 81 | { 82 | XFillRectangle(gfx_display,gfx_window,gfx_gc,x,y,width,height); 83 | } 84 | 85 | void gfx_rectangles( int x, int y, XRectangle *rectangles, int nRectangles) 86 | { 87 | XFillRectangles(gfx_display,gfx_window,gfx_gc,rectangles,nRectangles); 88 | } 89 | 90 | /* Draw a single point at (x,y) */ 91 | 92 | void gfx_point( int x, int y ) 93 | { 94 | XDrawPoint(gfx_display,gfx_window,gfx_gc,x,y); 95 | } 96 | 97 | /* Draw a line from (x1,y1) to (x2,y2) */ 98 | 99 | void gfx_line( int x1, int y1, int x2, int y2 ) 100 | { 101 | XDrawLine(gfx_display,gfx_window,gfx_gc,x1,y1,x2,y2); 102 | } 103 | 104 | /* Change the current drawing color. */ 105 | 106 | void gfx_color( int r, int g, int b ) 107 | { 108 | XColor color; 109 | 110 | if(gfx_fast_color_mode) { 111 | /* If this is a truecolor display, we can just pick the color directly. */ 112 | color.pixel = ((b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16) ); 113 | } else { 114 | /* Otherwise, we have to allocate it from the colormap of the display. */ 115 | color.pixel = 0; 116 | color.red = r<<8; 117 | color.green = g<<8; 118 | color.blue = b<<8; 119 | XAllocColor(gfx_display,gfx_colormap,&color); 120 | } 121 | 122 | XSetForeground(gfx_display, gfx_gc, color.pixel); 123 | } 124 | 125 | /* Clear the graphics window to the background color. */ 126 | 127 | void gfx_clear() 128 | { 129 | XClearWindow(gfx_display,gfx_window); 130 | } 131 | 132 | /* Change the current background color. */ 133 | 134 | void gfx_clear_color( int r, int g, int b ) 135 | { 136 | XColor color; 137 | color.pixel = 0; 138 | color.red = r<<8; 139 | color.green = g<<8; 140 | color.blue = b<<8; 141 | XAllocColor(gfx_display,gfx_colormap,&color); 142 | 143 | XSetWindowAttributes attr; 144 | attr.background_pixel = color.pixel; 145 | XChangeWindowAttributes(gfx_display,gfx_window,CWBackPixel,&attr); 146 | } 147 | 148 | int gfx_event_waiting() 149 | { 150 | XEvent event; 151 | 152 | gfx_flush(); 153 | 154 | while (1) { 155 | if(XCheckMaskEvent(gfx_display,-1,&event)) { 156 | if(event.type==KeyPress) { 157 | XPutBackEvent(gfx_display,&event); 158 | return 1; 159 | } else if (event.type==ButtonPress) { 160 | XPutBackEvent(gfx_display,&event); 161 | return 1; 162 | } else { 163 | return 0; 164 | } 165 | } else { 166 | return 0; 167 | } 168 | } 169 | } 170 | 171 | /* Wait for the user to press a key or mouse button. */ 172 | 173 | char gfx_wait() 174 | { 175 | XEvent event; 176 | 177 | gfx_flush(); 178 | 179 | while(1) { 180 | XNextEvent(gfx_display,&event); 181 | 182 | if(event.type==KeyPress) { 183 | saved_xpos = event.xkey.x; 184 | saved_ypos = event.xkey.y; 185 | return XLookupKeysym(&event.xkey,0); 186 | } else if(event.type==ButtonPress) { 187 | saved_xpos = event.xkey.x; 188 | saved_ypos = event.xkey.y; 189 | return event.xbutton.button; 190 | } 191 | } 192 | } 193 | 194 | /* Return the X and Y coordinates of the last event. */ 195 | 196 | int gfx_xpos() 197 | { 198 | return saved_xpos; 199 | } 200 | 201 | int gfx_ypos() 202 | { 203 | return saved_ypos; 204 | } 205 | 206 | /* Flush all previous output to the window. */ 207 | 208 | void gfx_flush() 209 | { 210 | XFlush(gfx_display); 211 | } 212 | 213 | -------------------------------------------------------------------------------- /src/gfx.h: -------------------------------------------------------------------------------- 1 | /* 2 | A simple graphics library for CSE 20211 by Douglas Thain 3 | For course assignments, you should not change this file. 4 | For complete documentation, see: 5 | http://www.nd.edu/~dthain/courses/cse20211/fall2011/gfx 6 | Version 3, 11/07/2012 - Now much faster at changing colors rapidly. 7 | Version 2, 9/23/2011 - Fixes a bug that could result in jerky animation. 8 | */ 9 | 10 | #ifndef GFX_H 11 | #define GFX_H 12 | 13 | /* Open a new graphics window. */ 14 | void gfx_open( int width, int height, const char *title ); 15 | 16 | /* Draw a point at (x,y) */ 17 | void gfx_point( int x, int y ); 18 | 19 | /* Draw a rectangle with top left corner x, y */ 20 | void gfx_rectangle( int x, int y, int width, int height ); 21 | 22 | /* Draw a line from (x1,y1) to (x2,y2) */ 23 | void gfx_line( int x1, int y1, int x2, int y2 ); 24 | 25 | /* Change the current drawing color. */ 26 | void gfx_color( int red, int green, int blue ); 27 | 28 | /* Clear the graphics window to the background color. */ 29 | void gfx_clear(); 30 | 31 | /* Change the current background color. */ 32 | void gfx_clear_color( int red, int green, int blue ); 33 | 34 | /* Wait for the user to press a key or mouse button. */ 35 | char gfx_wait(); 36 | 37 | /* Return the X and Y coordinates of the last event. */ 38 | int gfx_xpos(); 39 | int gfx_ypos(); 40 | 41 | /* Return the X and Y dimensions of the window. */ 42 | int gfx_xsize(); 43 | int gfx_ysize(); 44 | 45 | /* Check to see if an event is waiting. */ 46 | int gfx_event_waiting(); 47 | 48 | /* Flush all previous output to the window. */ 49 | void gfx_flush(); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "keyboard.h" 5 | 6 | struct termios initial_settings, 7 | new_settings; 8 | 9 | char getChar(){ 10 | //code from http://cboard.cprogramming.com/c-programming/130243-non-blocking-getchar.html 11 | int n; 12 | unsigned char key; 13 | tcgetattr(0,&initial_settings); 14 | new_settings = initial_settings; 15 | new_settings.c_lflag &= ~ICANON; 16 | new_settings.c_lflag &= ~ECHO; 17 | new_settings.c_lflag &= ~ISIG; 18 | new_settings.c_cc[VMIN] = 0; 19 | new_settings.c_cc[VTIME] = 0; 20 | tcsetattr(0, TCSANOW, &new_settings); 21 | n = getchar(); 22 | if(n != EOF) { 23 | key = n; 24 | } else { 25 | key = -1; 26 | } 27 | tcsetattr(0, TCSANOW, &initial_settings); 28 | return key; 29 | } 30 | 31 | char getDirection(){ 32 | //noblocking, reads from user input and returns direction enum 33 | //where val depeneds on if one of wasd keys are pressed 34 | char key = getChar(); 35 | switch(key){ 36 | case 97: 37 | return left; 38 | break; 39 | case 100: 40 | return right; 41 | break; 42 | case 119: 43 | return up; 44 | break; 45 | case 115: 46 | return down; 47 | break; 48 | default: 49 | return none; 50 | break; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARD 2 | #define KEYBOARD 3 | 4 | #include 5 | 6 | struct termios initial_settings, 7 | new_settings; 8 | 9 | enum DIRECTION { 10 | left, 11 | right, 12 | up, 13 | down, 14 | none 15 | }; 16 | 17 | char getChar(); 18 | char getDirection(); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/load_prog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "load_prog.h" 3 | 4 | int get_hex_from_char(char c) { 5 | int hex_val; 6 | if (c-'0' >= 0 && c-'0' <= 9) { 7 | hex_val = c-'0'; 8 | } else if (c-'a' >= 0 && c-'f' <= 0) { 9 | hex_val = c-'a' + 10; 10 | } else { 11 | printf("Invalid hex symbol\n"); 12 | return 0; 13 | } 14 | return hex_val; 15 | } 16 | 17 | int get_hex_from_chars(char *c) { 18 | int hex_val = 0, length; 19 | int i; 20 | for (i = 0; c[i] != '\0' && c[i] != ' ' && c[i] != '\n'; i++) 21 | hex_val = get_hex_from_char(c[i]) + (hex_val << 4); 22 | return hex_val; 23 | } 24 | 25 | int16_t load_program(int argc, char **argv, int8_t *mem, int16_t start) { 26 | /* 27 | * Reads the specified hex dump file and loads it into memory 28 | * mem should have allocated 0xFFFF entries of 1 byte of memory 29 | * Returns the program counter that corresponds to the last 30 | * instruction 31 | */ 32 | if (argc < 2) { 33 | printf("Error: expecting command line argument with hex dump file to be opened.\n"); 34 | return start; 35 | } 36 | if (argc > 2) { 37 | printf("Error: too many command line arguments (only 1 is needed)\n"); 38 | return start; 39 | } 40 | 41 | FILE *hex; 42 | 43 | if ( (hex = fopen(argv[1], "r")) == NULL) { 44 | printf("Error: unable to open file %s\n", argv[1]); 45 | return start; 46 | } 47 | 48 | int16_t pc; 49 | int8_t hex_val; 50 | // records how far into scan buffer the scanner is in 51 | unsigned int bufc = 0; 52 | char scan_buf[6], val; 53 | 54 | pc = start; 55 | 56 | while ((val = getc(hex)) != EOF) { 57 | while (val != '\n' && val != ' ' && val != EOF) { 58 | scan_buf[bufc++] = val; 59 | val = getc(hex); 60 | } 61 | scan_buf[bufc] = '\0'; 62 | if (bufc && scan_buf[bufc-1] != ':') 63 | mem[pc++] = (int8_t) get_hex_from_chars(scan_buf); 64 | bufc = 0; 65 | } 66 | 67 | fclose(hex); 68 | 69 | return pc; 70 | } 71 | 72 | void test_1() { 73 | char *test_words[6] = {"0600: ", "8f", "16", "3f", " 4d", "4d "}; 74 | int8_t testhex = 0; 75 | int i; 76 | for (i = 0; i < sizeof(test_words)/sizeof(test_words[0]); i++) { 77 | testhex = get_hex_from_chars(test_words[i]); 78 | printf("%s\t%x\t%d\n", test_words[i], testhex, testhex); 79 | } 80 | } 81 | 82 | void test_2(int argc, char **argv) { 83 | uint8_t mem[0xffff]; 84 | int16_t start = 0x60, end = load_program(argc, argv, mem, start); 85 | 86 | if (start == end) { 87 | printf("Test 2 failed"); 88 | return; 89 | } 90 | 91 | printf("Loaded program into memory location %x to %x\n", start, end); 92 | int i; 93 | for (i = start; i < end; i++) 94 | printf("%02x ", mem[i]); 95 | printf("\n"); 96 | 97 | printf("This memory should match the input hexdump file \"%s\"\n", argv[1]); 98 | FILE *hexdump = fopen(argv[1], "r"); 99 | char c; 100 | while ((c = getc(hexdump)) != EOF) 101 | printf("%c", c); 102 | fclose(hexdump); 103 | } 104 | -------------------------------------------------------------------------------- /src/load_prog.h: -------------------------------------------------------------------------------- 1 | #ifndef LOAD_PROG_H 2 | #define LOAD_PROG_H 3 | 4 | #define int8_t __int8_t 5 | #define int16_t __int16_t 6 | #define uint8_t __uint8_t 7 | 8 | int get_hex_from_char(char c); 9 | int get_hex_from_chars(char *c); 10 | int16_t load_program(int argc, char **argv, int8_t *mem, int16_t start); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /tests/minunit.h: -------------------------------------------------------------------------------- 1 | /* file: minunit.h */ 2 | #define mu_assert(message, test) do { if (!(test)) return message; } while (0) 3 | #define mu_run_test(test) do { char *message = test(); tests_run++; \ 4 | if (message) return message; } while (0) 5 | #define mu_run_test_with_args(test,arg1,arg2,arg3) do { char *message = test(arg1,arg2,arg3); tests_run++; \ 6 | if (message) return message; } while (0) 7 | extern int tests_run; 8 | -------------------------------------------------------------------------------- /tests/testOPCODES.c: -------------------------------------------------------------------------------- 1 | #include "minunit.h" 2 | #include "../src/cpu.h" 3 | 4 | int tests_run = 0; 5 | 6 | int8_t testADCHelper(CPU *c, int8_t accumByte, int8_t operand){ 7 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 8 | setRegByte(c,ACCUM,accumByte); 9 | adc(c,o); 10 | freeOP_CODE_INFO(o); 11 | return getRegByte(c,ACCUM); 12 | } 13 | 14 | int8_t testSBCHelper(CPU *c, int8_t accumByte, int8_t operand){ 15 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 16 | setRegByte(c,ACCUM,accumByte); 17 | sbc(c,o); 18 | freeOP_CODE_INFO(o); 19 | return getRegByte(c,ACCUM); 20 | } 21 | 22 | char * sprintfStatusCode(char *msg, char *actualStatus, char *correctStatus){ 23 | //takes msg string with two %s' in it somewhere and returns a new string 24 | //with the two %s replaced by correctStatus and actualStatus, which must 25 | //be 8 chars in length 26 | int newLen = strlen(msg) + strlen(actualStatus) + strlen(correctStatus); 27 | char *res = malloc(sizeof(char)*newLen); 28 | sprintf(res,msg,actualStatus,correctStatus); 29 | return res; 30 | } 31 | 32 | static char * testRegStatus(CPU *c, char * correctStatus, char * errMsgBase){ 33 | char * actualStatus = getStatus(c); 34 | char * errMsg = sprintfStatusCode(errMsgBase,actualStatus,correctStatus); 35 | mu_assert(errMsg, !strcmp(correctStatus,actualStatus)); 36 | free(actualStatus); 37 | free(errMsg); 38 | return 0; 39 | } 40 | 41 | static char * ADC1() { 42 | //adding positives, no overflow, no carry 43 | CPU *c = getCPU(); 44 | int8_t accumVal = testADCHelper(c,13,14); 45 | mu_assert("ADC1 err, ACCUM reg != 27", accumVal == 27); 46 | mu_run_test_with_args(testRegStatus,c,"00100000", 47 | " NVUBDIZC NVUBDIZC\nADC1 err, %s != %s"); 48 | free(c); 49 | return 0; 50 | } 51 | 52 | static char * ADC2() { 53 | //adding positive to negative, no overflow, yes carry 54 | CPU *c = getCPU(); 55 | int8_t accumVal = testADCHelper(c,-39,92); 56 | mu_assert("ADC2 err, ACCUM reg != 53", accumVal == 53); 57 | mu_run_test_with_args(testRegStatus,c,"00100001", 58 | " NVUBDIZC NVUBDIZC\nADC2 err, %s != %s"); 59 | free(c); 60 | return 0; 61 | } 62 | 63 | static char * ADC3() { 64 | //adding positives, yes overflow, no carry 65 | CPU *c = getCPU(); 66 | int8_t accumVal = testADCHelper(c,104,45); 67 | mu_assert("ADC3 err, ACCUM reg != -107", accumVal == -107); 68 | mu_run_test_with_args(testRegStatus,c,"11100000", 69 | " NVUBDIZC NVUBDIZC\nADC3 err, %s != %s"); 70 | free(c); 71 | return 0; 72 | } 73 | 74 | static char * ADC4() { 75 | //adding negatives, yes overflow, yes carry 76 | CPU *c = getCPU(); 77 | int8_t accumVal = testADCHelper(c,-103,-69); 78 | mu_assert("ADC4 err, ACCUM reg != 84", accumVal == 84); 79 | mu_run_test_with_args(testRegStatus,c,"01100001", 80 | " NVUBDIZC NVUBDIZC\nADC4 err, %s != %s"); 81 | free(c); 82 | return 0; 83 | } 84 | 85 | static char * ADC5() { 86 | //adding with carry flag, no overflow, no carry 87 | CPU *c = getCPU(); 88 | setFlag(c,C,1); 89 | int8_t accumVal = testADCHelper(c,30,12); 90 | mu_assert("ADC5 err, ACCUM reg != 43", accumVal == 43); 91 | mu_run_test_with_args(testRegStatus,c,"00100000", 92 | " NVUBDIZC NVUBDIZC\nADC5 err, %s != %s"); 93 | free(c); 94 | return 0; 95 | } 96 | 97 | static char * ADC6() { 98 | //adding in DECIMAL mode 99 | CPU *c = getCPU(); 100 | setFlag(c,D,1); 101 | //no overflow 102 | int8_t accumVal = testADCHelper(c,38,66); 103 | mu_assert("ADC6 err, ACCUM reg != 104", accumVal == 104); 104 | mu_run_test_with_args(testRegStatus,c,"00101000", 105 | " NVUBDIZC NVUBDIZC\nADC6 err, %s != %s"); 106 | //overflow 107 | accumVal = testADCHelper(c,52,104); 108 | mu_assert("ADC6 err, ACCUM reg != 2", accumVal == 2); 109 | //NEG flag is one here because the zero and neg flags 110 | //are set before correction for decimal addition overflow 111 | //is done 112 | mu_run_test_with_args(testRegStatus,c,"11101001", 113 | " NVUBDIZC NVUBDIZC\nADC6 err, %s != %s"); 114 | free(c); 115 | return 0; 116 | } 117 | 118 | static char * AND1() { 119 | //test zero reg setting 120 | CPU *c = getCPU(); 121 | int8_t operand = 0x00; 122 | int8_t accum = 0xFF; 123 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 124 | setRegByte(c,ACCUM,accum); 125 | and(c,o); 126 | int8_t accumVal = getRegByte(c,ACCUM); 127 | mu_assert("AND1 err, ACCUM reg != 0", accumVal == 0); 128 | mu_run_test_with_args(testRegStatus,c,"00100010", 129 | " NVUBDIZC NVUBDIZC\nAND1 err, %s != %s"); 130 | freeOP_CODE_INFO(o); 131 | free(c); 132 | return 0; 133 | } 134 | 135 | static char * AND2() { 136 | //test sign flag setting 137 | CPU *c = getCPU(); 138 | int8_t operand = 0x85; 139 | int8_t accum = 0xF1; 140 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 141 | setRegByte(c,ACCUM,accum); 142 | and(c,o); 143 | int8_t accumVal = getRegByte(c,ACCUM); 144 | mu_assert("AND2 err, ACCUM reg != -127", accumVal == -127); 145 | mu_run_test_with_args(testRegStatus,c,"10100000", 146 | " NVUBDIZC NVUBDIZC\nAND2 err, %s != %s"); 147 | freeOP_CODE_INFO(o); 148 | free(c); 149 | return 0; 150 | } 151 | 152 | static char * ASL1() { 153 | //Accumulator addressing mode 154 | CPU *c = getCPU(); 155 | int8_t operand = 0xFF; 156 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeAccumulator); 157 | asl(c,o); 158 | int8_t accumVal = getRegByte(c,ACCUM); 159 | mu_assert("ASL1 err, ACCUM reg != -2", accumVal == -2); 160 | mu_run_test_with_args(testRegStatus,c,"10100001", 161 | " NVUBDIZC NVUBDIZC\nASL1 err, %s != %s"); 162 | freeOP_CODE_INFO(o); 163 | free(c); 164 | return 0; 165 | } 166 | 167 | static char * ASL2() { 168 | //Non modeAccumulator addressing mode 169 | CPU *c = getCPU(); 170 | int8_t operand = 0xFF; 171 | uint16_t address = 0xEFEF; 172 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 173 | asl(c,o); 174 | int8_t accumVal = getRegByte(c,ACCUM); 175 | int8_t addrVal = read(c,address); 176 | mu_assert("ASL2 err, ACCUM reg != 0", accumVal == 0); 177 | mu_assert("ASL2 err, Address val != -2", addrVal == -2); 178 | mu_run_test_with_args(testRegStatus,c,"10100001", 179 | " NVUBDIZC NVUBDIZC\nASL2 err, %s != %s"); 180 | freeOP_CODE_INFO(o); 181 | free(c); 182 | return 0; 183 | } 184 | 185 | static char * BNE1() { 186 | CPU *c = getCPU(); 187 | uint16_t address = 0x8FFE; 188 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 189 | setFlag(c,Z,0); 190 | bne(c,o); 191 | mu_assert("BNE1 err, PC != 0x8FFE", c->PC == 0x8FFE); 192 | freeOP_CODE_INFO(o); 193 | free(c); 194 | return 0; 195 | } 196 | 197 | static char * BNE2() { 198 | CPU *c = getCPU(); 199 | uint16_t address = 0xFFFF; 200 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 201 | setFlag(c,Z,1); 202 | bne(c,o); 203 | mu_assert("BNE2 err, PC != 0", c->PC == 0); 204 | freeOP_CODE_INFO(o); 205 | free(c); 206 | return 0; 207 | } 208 | 209 | static char * BPL1() { 210 | CPU *c = getCPU(); 211 | uint16_t address = 0x8FFE; 212 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 213 | setFlag(c,S,0); 214 | bpl(c,o); 215 | mu_assert("BPL1 err, PC != 0x8FFE", c->PC == 0x8FFE); 216 | freeOP_CODE_INFO(o); 217 | free(c); 218 | return 0; 219 | } 220 | 221 | static char * BPL2() { 222 | CPU *c = getCPU(); 223 | uint16_t address = 0xFFFF; 224 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 225 | setFlag(c,S,1); 226 | bpl(c,o); 227 | mu_assert("BPL2 err, PC != 0", c->PC == 0); 228 | freeOP_CODE_INFO(o); 229 | free(c); 230 | return 0; 231 | } 232 | 233 | static char * BCC1() { 234 | CPU *c = getCPU(); 235 | uint16_t address = 0x8FFE; 236 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 237 | setFlag(c,C,0); 238 | bcc(c,o); 239 | mu_assert("BCC1 err, PC != 0x8FFE", c->PC == 0x8FFE); 240 | freeOP_CODE_INFO(o); 241 | free(c); 242 | return 0; 243 | } 244 | 245 | static char * BCC2() { 246 | CPU *c = getCPU(); 247 | uint16_t address = 0xFFFF; 248 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 249 | setFlag(c,C,1); 250 | bcc(c,o); 251 | mu_assert("BCC2 err, PC != 0", c->PC == 0); 252 | freeOP_CODE_INFO(o); 253 | free(c); 254 | return 0; 255 | } 256 | 257 | static char * BCS1() { 258 | CPU *c = getCPU(); 259 | uint16_t address = 0x8FFE; 260 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 261 | setFlag(c,C,1); 262 | bcs(c,o); 263 | mu_assert("BCS1 err, PC != 0x8FFE", c->PC == 0x8FFE); 264 | freeOP_CODE_INFO(o); 265 | free(c); 266 | return 0; 267 | } 268 | 269 | static char * BCS2() { 270 | CPU *c = getCPU(); 271 | uint16_t address = 0x8FFE; 272 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 273 | setFlag(c,C,0); 274 | bcs(c,o); 275 | mu_assert("BCS2 err, PC != 0", c->PC == 0); 276 | freeOP_CODE_INFO(o); 277 | free(c); 278 | return 0; 279 | } 280 | 281 | static char * BEQ1() { 282 | CPU *c = getCPU(); 283 | uint16_t address = 0x8FFE; 284 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 285 | setFlag(c,Z,1); 286 | beq(c,o); 287 | mu_assert("BEQ1 err, PC != 0x8FFE", c->PC == 0x8FFE); 288 | freeOP_CODE_INFO(o); 289 | free(c); 290 | return 0; 291 | } 292 | 293 | static char * BEQ2() { 294 | CPU *c = getCPU(); 295 | uint16_t address = 0x1111; 296 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 297 | setFlag(c,Z,0); 298 | beq(c,o); 299 | mu_assert("BEQ2 err, PC != 0", c->PC == 0); 300 | freeOP_CODE_INFO(o); 301 | free(c); 302 | return 0; 303 | } 304 | 305 | static char * BIT1() { 306 | CPU *c = getCPU(); 307 | int8_t operand = 0xC0; 308 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 309 | setRegByte(c,ACCUM,0); 310 | bit(c,o); 311 | mu_run_test_with_args(testRegStatus,c,"11100010", 312 | " NVUBDIZC NVUBDIZC\nBIT1 err, %s != %s"); 313 | freeOP_CODE_INFO(o); 314 | free(c); 315 | return 0; 316 | } 317 | 318 | static char * BIT2() { 319 | CPU *c = getCPU(); 320 | int8_t operand = 0x01; 321 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 322 | setRegByte(c,ACCUM,1); 323 | bit(c,o); 324 | mu_run_test_with_args(testRegStatus,c,"00100000", 325 | " NVUBDIZC NVUBDIZC\nBIT2 err, %s != %s"); 326 | freeOP_CODE_INFO(o); 327 | free(c); 328 | return 0; 329 | } 330 | 331 | static char * CLC1() { 332 | CPU *c = getCPU(); 333 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 334 | setFlag(c,C,1); 335 | mu_run_test_with_args(testRegStatus,c,"00100001", 336 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 337 | clc(c,o); 338 | mu_run_test_with_args(testRegStatus,c,"00100000", 339 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 340 | freeOP_CODE_INFO(o); 341 | free(c); 342 | return 0; 343 | } 344 | 345 | static char * DEC1() { 346 | CPU *c = getCPU(); 347 | uint16_t address = 0xEFF; 348 | int8_t operand = -34; 349 | write(c,address,operand); 350 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 351 | dec(c,o); 352 | int8_t accumVal = read(c,address); 353 | mu_assert("DEC1 err, 0xEFF address != -35", accumVal == -35); 354 | mu_run_test_with_args(testRegStatus,c,"10100000", 355 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 356 | freeOP_CODE_INFO(o); 357 | free(c); 358 | return 0; 359 | } 360 | 361 | static char * DEC2() { 362 | CPU *c = getCPU(); 363 | uint16_t address = 0xEFF; 364 | int8_t operand = 1; 365 | write(c,address,operand); 366 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 367 | dec(c,o); 368 | int8_t accumVal = read(c,address); 369 | mu_assert("DEC2 err, ACCUM reg != 0", accumVal == 0); 370 | mu_run_test_with_args(testRegStatus,c,"00100010", 371 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 372 | freeOP_CODE_INFO(o); 373 | free(c); 374 | return 0; 375 | } 376 | 377 | static char * DEC3() { 378 | //decrement X reg by 1 with zero 379 | //in X reg 380 | CPU *c = getCPU(); 381 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 382 | setRegByte(c,ACCUM,0); 383 | dec(c,o); 384 | int8_t accumVal = getRegByte(c,ACCUM); 385 | mu_assert("DEC3 err, ACCUM reg != -1", accumVal == -1); 386 | mu_run_test_with_args(testRegStatus,c,"10100000", 387 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 388 | freeOP_CODE_INFO(o); 389 | free(c); 390 | return 0; 391 | } 392 | 393 | static char * DEX1() { 394 | //decrement X reg by 1 with neg twos complement val 395 | //in X reg 396 | CPU *c = getCPU(); 397 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 398 | setRegByte(c,IND_X,-34); 399 | dex(c,o); 400 | int8_t xVal = getRegByte(c,IND_X); 401 | mu_assert("DEX1 err, IND_X reg != -35", xVal == -35); 402 | mu_run_test_with_args(testRegStatus,c,"10100000", 403 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 404 | freeOP_CODE_INFO(o); 405 | free(c); 406 | return 0; 407 | } 408 | 409 | static char * DEX2() { 410 | //decrement X reg by 1 with positive twos complement val 411 | //in X reg 412 | CPU *c = getCPU(); 413 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 414 | setRegByte(c,IND_X,1); 415 | dex(c,o); 416 | int8_t xVal = getRegByte(c,IND_X); 417 | mu_assert("DEX2 err, IND_X reg != 0", xVal == 0); 418 | mu_run_test_with_args(testRegStatus,c,"00100010", 419 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 420 | freeOP_CODE_INFO(o); 421 | free(c); 422 | return 0; 423 | } 424 | 425 | static char * DEX3() { 426 | //decrement X reg by 1 with zero 427 | //in X reg 428 | CPU *c = getCPU(); 429 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 430 | setRegByte(c,IND_X,0); 431 | dex(c,o); 432 | int8_t xVal = getRegByte(c,IND_X); 433 | mu_assert("DEX3 err, IND_X reg != -1", xVal == -1); 434 | mu_run_test_with_args(testRegStatus,c,"10100000", 435 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 436 | freeOP_CODE_INFO(o); 437 | free(c); 438 | return 0; 439 | } 440 | 441 | static char * DEY1() { 442 | //decrement Y reg by 1 with neg twos complement val 443 | //in Y reg 444 | CPU *c = getCPU(); 445 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 446 | setRegByte(c,IND_Y,-34); 447 | dey(c,o); 448 | int8_t yVal = getRegByte(c,IND_Y); 449 | mu_assert("DEY1 err, IND_Y reg != -35", yVal == -35); 450 | mu_run_test_with_args(testRegStatus,c,"10100000", 451 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 452 | freeOP_CODE_INFO(o); 453 | free(c); 454 | return 0; 455 | } 456 | 457 | static char * DEY2() { 458 | //decrement Y reg by 1 with positive twos complement val 459 | //in Y reg 460 | CPU *c = getCPU(); 461 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 462 | setRegByte(c,IND_Y,1); 463 | dey(c,o); 464 | int8_t yVal = getRegByte(c,IND_Y); 465 | mu_assert("DEY2 err, IND_Y reg != 0", yVal == 0); 466 | mu_run_test_with_args(testRegStatus,c,"00100010", 467 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 468 | freeOP_CODE_INFO(o); 469 | free(c); 470 | return 0; 471 | } 472 | 473 | static char * DEY3() { 474 | //decrement Y reg by 1 with zero 475 | //in Y reg 476 | CPU *c = getCPU(); 477 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 478 | setRegByte(c,IND_Y,0); 479 | dey(c,o); 480 | int8_t yVal = getRegByte(c,IND_Y); 481 | mu_assert("DEY3 err, IND_Y reg != -1", yVal == -1); 482 | mu_run_test_with_args(testRegStatus,c,"10100000", 483 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 484 | freeOP_CODE_INFO(o); 485 | free(c); 486 | return 0; 487 | } 488 | 489 | static char * LDA1() { 490 | //load zero val into accumulator 491 | CPU *c = getCPU(); 492 | int8_t operand = 0x00; 493 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 494 | setRegByte(c,ACCUM,10); 495 | lda(c,o); 496 | int8_t accumVal = getRegByte(c,ACCUM); 497 | mu_assert("LDA1 err, ACCUM reg != 0", accumVal == 0); 498 | mu_run_test_with_args(testRegStatus,c,"00100010", 499 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 500 | freeOP_CODE_INFO(o); 501 | free(c); 502 | return 0; 503 | } 504 | 505 | static char * LDA2() { 506 | //load neg val into accumulator 507 | CPU *c = getCPU(); 508 | int8_t operand = -99; 509 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 510 | lda(c,o); 511 | int8_t accumVal = getRegByte(c,ACCUM); 512 | mu_assert("LDA2 err, ACCUM reg != -99", accumVal == -99); 513 | mu_run_test_with_args(testRegStatus,c,"10100000", 514 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 515 | freeOP_CODE_INFO(o); 516 | free(c); 517 | return 0; 518 | } 519 | 520 | static char * LDX1() { 521 | //load zero val into x reg 522 | CPU *c = getCPU(); 523 | int8_t operand = 0x00; 524 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 525 | setRegByte(c,ACCUM,10); 526 | ldx(c,o); 527 | int8_t xVal = getRegByte(c,IND_X); 528 | mu_assert("LDX1 err, ACCUM reg != 0", xVal == 0); 529 | mu_run_test_with_args(testRegStatus,c,"00100010", 530 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 531 | freeOP_CODE_INFO(o); 532 | free(c); 533 | return 0; 534 | } 535 | 536 | static char * LDX2() { 537 | //load neg val into x reg 538 | CPU *c = getCPU(); 539 | int8_t operand = -99; 540 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 541 | ldx(c,o); 542 | int8_t xVal = getRegByte(c,IND_X); 543 | mu_assert("LDX2 err, ACCUM reg != -99", xVal == -99); 544 | mu_run_test_with_args(testRegStatus,c,"10100000", 545 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 546 | freeOP_CODE_INFO(o); 547 | free(c); 548 | return 0; 549 | } 550 | 551 | static char * LDY1() { 552 | //load zero val into x reg 553 | CPU *c = getCPU(); 554 | int8_t operand = 0x00; 555 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 556 | setRegByte(c,ACCUM,10); 557 | ldy(c,o); 558 | int8_t yVal = getRegByte(c,IND_Y); 559 | mu_assert("LDY1 err, ACCUM reg != 0", yVal == 0); 560 | mu_run_test_with_args(testRegStatus,c,"00100010", 561 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 562 | freeOP_CODE_INFO(o); 563 | free(c); 564 | return 0; 565 | } 566 | 567 | static char * LDY2() { 568 | //load neg val into x reg 569 | CPU *c = getCPU(); 570 | int8_t operand = -99; 571 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 572 | ldy(c,o); 573 | int8_t yVal = getRegByte(c,IND_Y); 574 | mu_assert("LDY2 err, ACCUM reg != -99", yVal == -99); 575 | mu_run_test_with_args(testRegStatus,c,"10100000", 576 | " NVUBDIZC NVUBDIZC\nCLC1 err, %s != %s"); 577 | freeOP_CODE_INFO(o); 578 | free(c); 579 | return 0; 580 | } 581 | 582 | static char * SBC1() { 583 | //pos ACUM, neg operand, no overflow, no carry 584 | CPU *c = getCPU(); 585 | setFlag(c,C,1); 586 | int8_t accumVal = testSBCHelper(c,13,-14); 587 | mu_assert("SBC1 err, ACCUM reg != 27", accumVal == 27); 588 | mu_run_test_with_args(testRegStatus,c,"00100000", 589 | " NVUBDIZC NVUBDIZC\nSBC1 err, %s != %s"); 590 | free(c); 591 | return 0; 592 | } 593 | 594 | static char * SBC2() { 595 | //pos ACUM, neg operand, no overflow, yes carry 596 | CPU *c = getCPU(); 597 | setFlag(c,C,1); 598 | int8_t accumVal = testSBCHelper(c,-39,-92); 599 | mu_assert("SBC2 err, ACCUM reg != 53", accumVal == 53); 600 | mu_run_test_with_args(testRegStatus,c,"00100001", 601 | " NVUBDIZC NVUBDIZC\nSBC2 err, %s != %s"); 602 | free(c); 603 | return 0; 604 | } 605 | 606 | static char * SBC3() { 607 | //pos ACUM, neg operand, yes overflow, no carry 608 | CPU *c = getCPU(); 609 | setFlag(c,C,1); 610 | int8_t accumVal = testSBCHelper(c,104,-45); 611 | mu_assert("SBC3 err, ACCUM reg != -105", accumVal == -107); 612 | mu_run_test_with_args(testRegStatus,c,"11100000", 613 | " NVUBDIZC NVUBDIZC\nSBC3 err, %s != %s"); 614 | free(c); 615 | return 0; 616 | } 617 | 618 | static char * SBC4() { 619 | //neg ACUM, pos operand, yes overflow, yes carry 620 | CPU *c = getCPU(); 621 | setFlag(c,C,1); 622 | int8_t accumVal = testSBCHelper(c,-103,69); 623 | mu_assert("SBC4 err, ACCUM reg != 84", accumVal == 84); 624 | mu_run_test_with_args(testRegStatus,c,"01100001", 625 | " NVUBDIZC NVUBDIZC\nSBC4 err, %s != %s"); 626 | free(c); 627 | return 0; 628 | } 629 | 630 | static char * SBC5() { 631 | //pos ACUM, neg operand, no overflow, carry flag zeroed 632 | CPU *c = getCPU(); 633 | setFlag(c,C,0); 634 | int8_t accumVal = testSBCHelper(c,30,-12); 635 | mu_assert("SBC5 err, ACCUM reg != 41", accumVal == 41); 636 | mu_run_test_with_args(testRegStatus,c,"00100000", 637 | " NVUBDIZC NVUBDIZC\nSBC5 err, %s != %s"); 638 | free(c); 639 | return 0; 640 | } 641 | 642 | static char * SBC6() { 643 | //subtraction in decimal mode 644 | CPU *c = getCPU(); 645 | setFlag(c,D,1); 646 | setFlag(c,C,1); 647 | //no overflow, 66 - 38 in BCD mode 648 | int8_t accumVal = testSBCHelper(c,0x66,0x38); 649 | mu_assert("SBC6 err, ACCUM reg != 0x28", accumVal == 0x28); 650 | mu_run_test_with_args(testRegStatus,c,"00101001", 651 | " NVUBDIZC NVUBDIZC\nSBC6 err, %s != %s"); 652 | free(c); 653 | return 0; 654 | } 655 | 656 | static char * SBC7() { 657 | //subtraction in decimal mode 658 | CPU *c = getCPU(); 659 | setFlag(c,D,1); 660 | setFlag(c,C,1); 661 | //no overflow, 93 - 87 in BCD mode 662 | int8_t accumVal = testSBCHelper(c,0x93,0x87); 663 | mu_assert("SBC7 err, ACCUM reg != 0x06", accumVal == 0x06); 664 | mu_run_test_with_args(testRegStatus,c,"00101001", 665 | " NVUBDIZC NVUBDIZC\nSBC7 err, %s != %s"); 666 | free(c); 667 | return 0; 668 | } 669 | 670 | static char * SEC1() { 671 | CPU *c = getCPU(); 672 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 673 | sec(c,o); 674 | mu_assert("SEC1 err, Carry flag != 1", getFlag(c,C) == 1); 675 | freeOP_CODE_INFO(o); 676 | free(c); 677 | return 0; 678 | } 679 | 680 | static char * TAY1() { 681 | CPU *c = getCPU(); 682 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 683 | setRegByte(c,ACCUM,-1); 684 | tay(c,o); 685 | int8_t yVal = getRegByte(c,IND_Y); 686 | mu_assert("TAY1 err, Y reg != -1", yVal == -1); 687 | mu_run_test_with_args(testRegStatus,c,"10100000", 688 | " NVUBDIZC NVUBDIZC\nTAY1 err, %s != %s"); 689 | freeOP_CODE_INFO(o); 690 | free(c); 691 | return 0; 692 | } 693 | 694 | static char * TYA1() { 695 | CPU *c = getCPU(); 696 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 697 | setRegByte(c,IND_Y,0); 698 | setRegByte(c,ACCUM,-39); 699 | tya(c,o); 700 | int8_t accumVal = getRegByte(c,ACCUM); 701 | mu_assert("TYA1 err, ACCUM reg != 0", accumVal == 0); 702 | mu_run_test_with_args(testRegStatus,c,"00100010", 703 | " NVUBDIZC NVUBDIZC\nTYA1 err, %s != %s"); 704 | freeOP_CODE_INFO(o); 705 | free(c); 706 | return 0; 707 | } 708 | 709 | static char * TXA1() { 710 | CPU *c = getCPU(); 711 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 712 | setRegByte(c,IND_X,-50); 713 | setRegByte(c,ACCUM,39); 714 | txa(c,o); 715 | int8_t accumVal = getRegByte(c,ACCUM); 716 | mu_assert("TXA1 err, ACCUM reg != -50", accumVal == -50); 717 | mu_run_test_with_args(testRegStatus,c,"10100000", 718 | " NVUBDIZC NVUBDIZC\nTXA1 err, %s != %s"); 719 | freeOP_CODE_INFO(o); 720 | free(c); 721 | return 0; 722 | } 723 | 724 | static char * STA1() { 725 | CPU *c = getCPU(); 726 | uint16_t address = 0xFFEE; 727 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 728 | setRegByte(c,ACCUM,-39); 729 | sta(c,o); 730 | int8_t addrVal = read(c,address); 731 | mu_assert("STA1 err, address at 0xFFEE != -39", addrVal == -39); 732 | freeOP_CODE_INFO(o); 733 | free(c); 734 | return 0; 735 | } 736 | 737 | static char * STX1() { 738 | CPU *c = getCPU(); 739 | uint16_t address = 0xFFEE; 740 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 741 | setRegByte(c,IND_X,-39); 742 | stx(c,o); 743 | int8_t addrVal = read(c,address); 744 | mu_assert("STX1 err, address at 0xFFEE != -39", addrVal == -39); 745 | freeOP_CODE_INFO(o); 746 | free(c); 747 | return 0; 748 | } 749 | 750 | static char * CMP1() { 751 | CPU *c = getCPU(); 752 | int8_t operand = 1; 753 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 754 | setRegByte(c,ACCUM,1); 755 | cmp(c,o); 756 | mu_run_test_with_args(testRegStatus,c,"00100011", 757 | " NVUBDIZC NVUBDIZC\nCMP1 err, %s != %s"); 758 | freeOP_CODE_INFO(o); 759 | free(c); 760 | return 0; 761 | } 762 | 763 | static char * CMP2() { 764 | CPU *c = getCPU(); 765 | int8_t operand = 50; 766 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 767 | setRegByte(c,ACCUM,1); 768 | cmp(c,o); 769 | mu_run_test_with_args(testRegStatus,c,"10100000", 770 | " NVUBDIZC NVUBDIZC\nCMP2 err, %s != %s"); 771 | freeOP_CODE_INFO(o); 772 | free(c); 773 | return 0; 774 | } 775 | 776 | static char * CPX1() { 777 | CPU *c = getCPU(); 778 | int8_t operand = 5; 779 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 780 | setRegByte(c,IND_X,8); 781 | cpx(c,o); 782 | mu_run_test_with_args(testRegStatus,c,"00100001", 783 | " NVUBDIZC NVUBDIZC\nCPX1 err, %s != %s"); 784 | freeOP_CODE_INFO(o); 785 | free(c); 786 | return 0; 787 | } 788 | 789 | static char * CPX2() { 790 | CPU *c = getCPU(); 791 | int8_t operand = 75; 792 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,0,modeImmediate); 793 | setRegByte(c,IND_X,59); 794 | cpx(c,o); 795 | mu_run_test_with_args(testRegStatus,c,"10100000", 796 | " NVUBDIZC NVUBDIZC\nCPX2 err, %s != %s"); 797 | freeOP_CODE_INFO(o); 798 | free(c); 799 | return 0; 800 | } 801 | 802 | static char * INC1() { 803 | CPU *c = getCPU(); 804 | uint16_t address = 0xEFF; 805 | int8_t operand = -1; 806 | write(c,address,operand); 807 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 808 | inc(c,o); 809 | int8_t accumVal = read(c,address); 810 | mu_assert("INC1 err, ACCUM reg != 0", accumVal == 0); 811 | mu_run_test_with_args(testRegStatus,c,"00100010", 812 | " NVUBDIZC NVUBDIZC\nINC1 err, %s != %s"); 813 | freeOP_CODE_INFO(o); 814 | free(c); 815 | return 0; 816 | } 817 | 818 | static char * INC2() { 819 | CPU *c = getCPU(); 820 | uint16_t address = 0xEFF; 821 | int8_t operand = -103; 822 | write(c,address,operand); 823 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 824 | inc(c,o); 825 | int8_t accumVal = read(c,address); 826 | mu_assert("INC2 err, ACCUM reg != -102", accumVal == -102); 827 | mu_run_test_with_args(testRegStatus,c,"10100000", 828 | " NVUBDIZC NVUBDIZC\nINC2 err, %s != %s"); 829 | freeOP_CODE_INFO(o); 830 | free(c); 831 | return 0; 832 | } 833 | 834 | static char * INX1() { 835 | CPU *c = getCPU(); 836 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 837 | setRegByte(c,IND_X,-1); 838 | inx(c,o); 839 | int8_t xVal = getRegByte(c,IND_X); 840 | mu_assert("INX1 err, IND_X reg != 0", xVal == 0); 841 | mu_run_test_with_args(testRegStatus,c,"00100010", 842 | " NVUBDIZC NVUBDIZC\nINX1 err, %s != %s"); 843 | freeOP_CODE_INFO(o); 844 | free(c); 845 | return 0; 846 | } 847 | 848 | static char * INX2() { 849 | CPU *c = getCPU(); 850 | OP_CODE_INFO *o = getOP_CODE_INFO(0,0,modeImmediate); 851 | setRegByte(c,IND_X,-103); 852 | inx(c,o); 853 | int8_t xVal = getRegByte(c,IND_X); 854 | mu_assert("INX2 err, IND_X reg != -102", xVal == -102); 855 | mu_run_test_with_args(testRegStatus,c,"10100000", 856 | " NVUBDIZC NVUBDIZC\nINX2 err, %s != %s"); 857 | freeOP_CODE_INFO(o); 858 | free(c); 859 | return 0; 860 | } 861 | 862 | static char * JMP1() { 863 | CPU *c = getCPU(); 864 | uint16_t address = 0xCFEE; 865 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 866 | jmp(c,o); 867 | mu_assert("JMP1 err, PC != 0xCFEE", c->PC == 0xCFEE); 868 | freeOP_CODE_INFO(o); 869 | free(c); 870 | return 0; 871 | } 872 | 873 | static char * JSR1() { 874 | CPU *c = getCPU(); 875 | c->PC = 0xCFEE; 876 | uint16_t address = 0xABAB; 877 | OP_CODE_INFO *o = getOP_CODE_INFO(0,address,modeImmediate); 878 | jsr(c,o); 879 | uint8_t stackPointer = getRegByte(c,STACK); 880 | mu_assert("JSR1 err, Stack Pointer != 0xFD", stackPointer == 0xFD); 881 | mu_assert("JSR1 err, PC != 0xABAB", c->PC == 0xABAB); 882 | uint8_t returnAddressLower = read(c,0x01FE); 883 | uint8_t returnAddressUpper = read(c,0x01FF); 884 | uint16_t returnAddress = (returnAddressUpper << 8) | returnAddressLower; 885 | mu_assert("JSR1 err, Return Address != 0xCFED", returnAddress == 0xCFED); 886 | freeOP_CODE_INFO(o); 887 | free(c); 888 | return 0; 889 | } 890 | 891 | static char * LSR1() { 892 | //test LSR and save to memory address 893 | CPU *c = getCPU(); 894 | uint16_t address = 0xCFEE; 895 | int8_t operand = 0xFF; 896 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 897 | lsr(c,o); 898 | int8_t memVal = read(c,address); 899 | int8_t accumVal = getRegByte(c,ACCUM); 900 | mu_assert("LSR1 err, memVal != 0x7F", memVal == 0x7F); 901 | mu_assert("LSR1 err, accumVal != 0", accumVal == 0); 902 | mu_run_test_with_args(testRegStatus,c,"00100001", 903 | " NVUBDIZC NVUBDIZC\nLSR1 err, %s != %s"); 904 | freeOP_CODE_INFO(o); 905 | free(c); 906 | return 0; 907 | } 908 | 909 | static char * LSR2() { 910 | //test LSR and save to memory address 911 | CPU *c = getCPU(); 912 | uint16_t address = 0xCFEE; 913 | int8_t operand = 0xFF; 914 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeAccumulator); 915 | lsr(c,o); 916 | int8_t memVal = read(c,address); 917 | int8_t accumVal = getRegByte(c,ACCUM); 918 | mu_assert("LSR2 err, memVal != 0", memVal == 0); 919 | mu_assert("LSR2 err, accumVal != 0x7F", accumVal == 0x7F); 920 | mu_run_test_with_args(testRegStatus,c,"00100001", 921 | " NVUBDIZC NVUBDIZC\nLSR2 err, %s != %s"); 922 | freeOP_CODE_INFO(o); 923 | free(c); 924 | return 0; 925 | } 926 | 927 | static char * NOP1() { 928 | CPU *c = getCPU(); 929 | uint16_t address = 0xFFFF; 930 | int8_t operand = 0xFF; 931 | OP_CODE_INFO *o = getOP_CODE_INFO(operand,address,modeImmediate); 932 | int8_t statusBef = getRegByte(c,STATUS); 933 | int8_t stackBef = getRegByte(c,STACK); 934 | int8_t accumBef = getRegByte(c,ACCUM); 935 | int8_t indXBef = getRegByte(c,IND_X); 936 | int8_t indYBef = getRegByte(c,IND_Y); 937 | uint16_t PCBef = c->PC; 938 | nop(c,o); 939 | int8_t statusAft = getRegByte(c,STATUS); 940 | int8_t stackAft = getRegByte(c,STACK); 941 | int8_t accumAft = getRegByte(c,ACCUM); 942 | int8_t indXAft = getRegByte(c,IND_X); 943 | int8_t indYAft = getRegByte(c,IND_Y); 944 | uint16_t PCAft = c->PC; 945 | mu_assert("NOP1 err, STATUS reg changed", statusBef == statusAft); 946 | mu_assert("NOP1 err, STACK reg changed", stackBef == stackAft); 947 | mu_assert("NOP1 err, ACCUM reg changed", accumBef == accumAft); 948 | mu_assert("NOP1 err, IND_X reg changed", indXBef == indXAft); 949 | mu_assert("NOP1 err, IND_Y reg changed", indYBef == indYAft); 950 | mu_assert("NOP1 err, PC changed", PCBef == PCAft); 951 | freeOP_CODE_INFO(o); 952 | free(c); 953 | return 0; 954 | } 955 | 956 | static char * RTS1() { 957 | CPU *c = getCPU(); 958 | c->PC = 0xCFEE; 959 | uint16_t address = 0xABAB; 960 | OP_CODE_INFO *o1 = getOP_CODE_INFO(0,address,modeImmediate); 961 | jsr(c,o1); 962 | OP_CODE_INFO *o2 = getOP_CODE_INFO(0,0,modeImmediate); 963 | rts(c,o2); 964 | mu_assert("RTS1 err, PC != 0xCFEE", c->PC == 0xCFEE); 965 | freeOP_CODE_INFO(o1); 966 | freeOP_CODE_INFO(o2); 967 | free(c); 968 | return 0; 969 | } 970 | 971 | static char * EOR1() { 972 | CPU *c = getCPU(); 973 | c->PC = 0xCFEE; 974 | setRegByte(c,ACCUM,0x3F); 975 | OP_CODE_INFO *o = getOP_CODE_INFO(0x3F,0,modeImmediate); 976 | eor(c,o); 977 | mu_assert("EOR1 err, ACCUM != 0x00", (0xFF & getRegByte(c,ACCUM)) == 0x00); 978 | mu_assert("EOR1 err, SIGN != 0", getFlag(c, S) == 0); 979 | mu_assert("EOR1 err, ZERO != 1", getFlag(c, Z) == 1); 980 | freeOP_CODE_INFO(o); 981 | free(c); 982 | return 0; 983 | } 984 | 985 | static char * EOR2() { 986 | CPU *c = getCPU(); 987 | c->PC = 0xCFEE; 988 | setRegByte(c,ACCUM,0x3F); 989 | OP_CODE_INFO *o = getOP_CODE_INFO(0xFF,0,modeImmediate); 990 | eor(c,o); 991 | mu_assert("EOR2 err, ACCUM != 0xC0", (0xFF & getRegByte(c,ACCUM)) == 0xc0); 992 | mu_assert("EOR2 err, SIGN != 1", getFlag(c, S) == 1); 993 | mu_assert("EOR2 err, ZERO != 0", getFlag(c, Z) == 0); 994 | freeOP_CODE_INFO(o); 995 | free(c); 996 | return 0; 997 | } 998 | 999 | static char * EOR3() { 1000 | CPU *c = getCPU(); 1001 | c->PC = 0xCFEE; 1002 | setRegByte(c,ACCUM,0x8A); 1003 | OP_CODE_INFO *o = getOP_CODE_INFO(0x92,0,modeImmediate); 1004 | eor(c,o); 1005 | mu_assert("EOR2 err, ACCUM != 0x18", (0xFF & getRegByte(c,ACCUM)) == 0x18); 1006 | mu_assert("EOR2 err, SIGN != 0", getFlag(c, S) == 0); 1007 | mu_assert("EOR2 err, ZERO != 0", getFlag(c, Z) == 0); 1008 | freeOP_CODE_INFO(o); 1009 | free(c); 1010 | return 0; 1011 | } 1012 | 1013 | static char * RTI1() { 1014 | CPU *c = getCPU(); 1015 | c->PC = 0x6EFC; 1016 | setRegByte(c, STACK, 0x2); 1017 | c->addressSpace[0x103] = 0x4; 1018 | c->addressSpace[0x104] = 0x00; 1019 | c->addressSpace[0x105] = 0x06; 1020 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1021 | rti(c,o); 1022 | mu_assert("RTI1 err, PC != 0x600", c->PC == 0x600); 1023 | mu_assert("RTI1 err, STATUS != 0x4", getRegByte(c,STATUS) == 0x4); 1024 | freeOP_CODE_INFO(o); 1025 | free(c); 1026 | return 0; 1027 | } 1028 | 1029 | static char * RTI2() { 1030 | CPU *c = getCPU(); 1031 | c->PC = 0xCE66; 1032 | setRegByte(c, STACK, 0x2); 1033 | c->addressSpace[0x103] = 0x3; 1034 | c->addressSpace[0x104] = 0x66; 1035 | c->addressSpace[0x105] = 0x60; 1036 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1037 | rti(c,o); 1038 | mu_assert("RTI2 err, PC != 0x6066", c->PC == 0x6066); 1039 | mu_assert("RTI2 err, STATUS != 0x3", getRegByte(c,STATUS) == 0x3); 1040 | freeOP_CODE_INFO(o); 1041 | free(c); 1042 | return 0; 1043 | } 1044 | 1045 | static char * RTI3() { 1046 | CPU *c = getCPU(); 1047 | c->PC = 0xCE66; 1048 | setRegByte(c, STACK, 0xF0); 1049 | c->addressSpace[0x1F1] = 0xf; 1050 | c->addressSpace[0x1F2] = 0xff; 1051 | c->addressSpace[0x1F3] = 0xff; 1052 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1053 | rti(c,o); 1054 | mu_assert("RTI3 err, PC != 0x6066", c->PC == 0xFFFF); 1055 | mu_assert("RTI3 err, STATUS != 0x3", getRegByte(c,STATUS) == 0xF); 1056 | freeOP_CODE_INFO(o); 1057 | free(c); 1058 | return 0; 1059 | } 1060 | 1061 | static char * ROL1() { 1062 | CPU *c = getCPU(); 1063 | setRegByte(c, ACCUM, 0xA1); 1064 | OP_CODE_INFO *o = getOP_CODE_INFO(0xA1, 0, modeAccumulator); 1065 | rol(c,o); 1066 | mu_assert("ROL1 err, ACCUM != 0x42", (0xFF & getRegByte(c,ACCUM)) == 0x42); 1067 | mu_assert("ROL1 err, CARRY != 1", getFlag(c,C) == 1); 1068 | freeOP_CODE_INFO(o); 1069 | free(c); 1070 | return 0; 1071 | } 1072 | 1073 | static char * ROL2() { 1074 | CPU *c = getCPU(); 1075 | setRegByte(c, ACCUM, 0xA1); 1076 | OP_CODE_INFO *o1 = getOP_CODE_INFO(getRegByte(c,ACCUM) & 0xFF, 0, modeAccumulator); 1077 | rol(c,o1); 1078 | OP_CODE_INFO *o2 = getOP_CODE_INFO(getRegByte(c,ACCUM) & 0xFF, 0, modeAccumulator); 1079 | rol(c,o2); 1080 | mu_assert("ROL2 err, ACCUM != 0x85", (0xFF & getRegByte(c,ACCUM)) == 0x85); 1081 | mu_assert("ROL2 err, CARRY != 0", getFlag(c,C) == 0); 1082 | freeOP_CODE_INFO(o1); 1083 | freeOP_CODE_INFO(o2); 1084 | free(c); 1085 | return 0; 1086 | } 1087 | 1088 | static char * ROR1() { 1089 | CPU *c = getCPU(); 1090 | setRegByte(c, ACCUM, 0xA1); 1091 | OP_CODE_INFO *o = getOP_CODE_INFO(getRegByte(c,ACCUM) & 0xFF, 0, modeAccumulator); 1092 | ror(c,o); 1093 | mu_assert("ROR1 err, ACCUM != 0x50", (0xFF & getRegByte(c,ACCUM)) == 0x50); 1094 | mu_assert("ROR1 err, CARRY != 1", getFlag(c,C) == 1); 1095 | freeOP_CODE_INFO(o); 1096 | free(c); 1097 | return 0; 1098 | } 1099 | 1100 | static char * ROR2() { 1101 | CPU *c = getCPU(); 1102 | setRegByte(c, ACCUM, 0x50); 1103 | setFlag(c,C,1); 1104 | OP_CODE_INFO *o = getOP_CODE_INFO(getRegByte(c,ACCUM) & 0xFF, 0, modeAccumulator); 1105 | ror(c,o); 1106 | mu_assert("ROR2 err, ACCUM != 0xA8", (0xFF & getRegByte(c,ACCUM)) == 0xA8); 1107 | mu_assert("ROR2 err, CARRY != 0", getFlag(c,C) == 0); 1108 | freeOP_CODE_INFO(o); 1109 | free(c); 1110 | return 0; 1111 | } 1112 | 1113 | static char * SEI1() { 1114 | CPU *c = getCPU(); 1115 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1116 | sei(c,o); 1117 | mu_assert("SEI1 err, INTERRUPT != 1", getFlag(c,I) == 1); 1118 | freeOP_CODE_INFO(o); 1119 | free(c); 1120 | return 0; 1121 | } 1122 | 1123 | static char * TXS1() { 1124 | CPU *c = getCPU(); 1125 | setRegByte(c,IND_X,0x99); 1126 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1127 | txs(c,o); 1128 | mu_assert("TXS1 err, STACK != 0x99", (getRegByte(c,STACK)&0xFF) == 0x99); 1129 | freeOP_CODE_INFO(o); 1130 | free(c); 1131 | return 0; 1132 | } 1133 | 1134 | static char * TSX1() { 1135 | CPU *c = getCPU(); 1136 | setRegByte(c,STACK,0x99); 1137 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1138 | tsx(c,o); 1139 | mu_assert("TXS1 err, STACK != 0x99", (getRegByte(c,IND_X)&0xFF) == 0x99); 1140 | freeOP_CODE_INFO(o); 1141 | free(c); 1142 | return 0; 1143 | } 1144 | 1145 | static char * SED1() { 1146 | CPU *c = getCPU(); 1147 | OP_CODE_INFO *o = getOP_CODE_INFO(0, 0, modeImplied); 1148 | sed(c,o); 1149 | mu_assert("SED1 err, DEC != 1", getFlag(c,D) == 1); 1150 | freeOP_CODE_INFO(o); 1151 | free(c); 1152 | return 0; 1153 | } 1154 | 1155 | static char * all_tests() { 1156 | mu_run_test(ADC1); 1157 | mu_run_test(ADC2); 1158 | mu_run_test(ADC3); 1159 | mu_run_test(ADC4); 1160 | mu_run_test(ADC5); 1161 | mu_run_test(ADC6); 1162 | mu_run_test(AND1); 1163 | mu_run_test(AND2); 1164 | mu_run_test(ASL1); 1165 | mu_run_test(ASL2); 1166 | mu_run_test(BCC1); 1167 | mu_run_test(BCC2); 1168 | mu_run_test(BCS1); 1169 | mu_run_test(BCS2); 1170 | mu_run_test(BEQ1); 1171 | mu_run_test(BEQ2); 1172 | mu_run_test(BNE1); 1173 | mu_run_test(BNE2); 1174 | mu_run_test(BPL1); 1175 | mu_run_test(BPL2); 1176 | mu_run_test(BIT1); 1177 | mu_run_test(BIT2); 1178 | mu_run_test(CLC1); 1179 | mu_run_test(CMP1); 1180 | mu_run_test(CMP2); 1181 | mu_run_test(CPX1); 1182 | mu_run_test(CPX2); 1183 | mu_run_test(DEY1); 1184 | mu_run_test(DEY2); 1185 | mu_run_test(DEY3); 1186 | mu_run_test(INC1); 1187 | mu_run_test(INC2); 1188 | mu_run_test(INX1); 1189 | mu_run_test(INX2); 1190 | mu_run_test(JMP1); 1191 | mu_run_test(JSR1); 1192 | mu_run_test(LDA1); 1193 | mu_run_test(LDA2); 1194 | mu_run_test(LDX1); 1195 | mu_run_test(LDX2); 1196 | mu_run_test(LDY1); 1197 | mu_run_test(LDY2); 1198 | mu_run_test(LSR1); 1199 | mu_run_test(LSR2); 1200 | mu_run_test(NOP1); 1201 | mu_run_test(RTS1); 1202 | mu_run_test(SBC1); 1203 | mu_run_test(SBC2); 1204 | mu_run_test(SBC3); 1205 | mu_run_test(SBC4); 1206 | mu_run_test(SBC5); 1207 | mu_run_test(SBC6); 1208 | mu_run_test(SBC7); 1209 | mu_run_test(SEC1); 1210 | mu_run_test(TAY1); 1211 | mu_run_test(TYA1); 1212 | mu_run_test(TXA1); 1213 | mu_run_test(STA1); 1214 | mu_run_test(STX1); 1215 | mu_run_test(EOR1); 1216 | mu_run_test(EOR2); 1217 | mu_run_test(EOR3); 1218 | mu_run_test(RTI1); 1219 | mu_run_test(RTI2); 1220 | mu_run_test(RTI3); 1221 | mu_run_test(ROL1); 1222 | mu_run_test(ROL2); 1223 | mu_run_test(ROR1); 1224 | mu_run_test(SEI1); 1225 | mu_run_test(TXS1); 1226 | mu_run_test(TSX1); 1227 | mu_run_test(SED1); 1228 | return 0; 1229 | } 1230 | 1231 | int main() { 1232 | char *result = all_tests(); 1233 | if (result != 0) { 1234 | printf("%s\n", result); 1235 | } 1236 | else { 1237 | printf("ALL TESTS PASSED\n"); 1238 | } 1239 | printf("Tests run: %d\n", tests_run); 1240 | return result != 0; 1241 | } 1242 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -O3 2 | ../bin/gfx.o: ../src/gfx.c ../src/gfx.h 3 | gcc -c ../src/gfx.c -o ../bin/gfx.o $(CFLAGS) 4 | ../bin/keyboard.o: ../src/keyboard.c ../src/keyboard.h 5 | gcc -c ../src/keyboard.c -o ../bin/keyboard.o $(CFLAGS) 6 | ../bin/load_prog.o: ../src/load_prog.c ../src/load_prog.h 7 | gcc -c ../src/load_prog.c -o ../bin/load_prog.o $(CFLAGS) 8 | ../bin/cpu.o: ../src/cpu.c ../src/cpu.h 9 | gcc -c ../src/cpu.c -o ../bin/cpu.o $(CFLAGS) 10 | 11 | #testOPCODES runs op code test suite 12 | ../bin/testOPCODES.o: ../tests/testOPCODES.c ../tests/minunit.h ../src/cpu.h 13 | gcc -c ../tests/testOPCODES.c -o ../bin/testOPCODES.o 14 | ../bin/testOPCODES: ../bin/cpu.o ../bin/testOPCODES.o 15 | gcc ../bin/cpu.o ../bin/testOPCODES.o -o ../bin/testOPCODES -lX11 -lm 16 | 17 | #runSnake loads and runs snake assembly program 18 | ../bin/runSnake.o: ../snake/runSnake.c ../src/cpu.h ../src/load_prog.h 19 | gcc -c ../snake/runSnake.c -o ../bin/runSnake.o 20 | ../bin/runSnake: ../bin/gfx.o ../bin/keyboard.o ../bin/cpu.o ../bin/load_prog.o ../bin/runSnake.o 21 | gcc ../bin/cpu.o ../bin/keyboard.o ../bin/load_prog.o ../bin/runSnake.o ../bin/gfx.o -o ../bin/runSnake -lX11 -lm $(CFLAGS) 22 | 23 | all: ../bin/testOPCODES ../bin/runSnake 24 | -------------------------------------------------------------------------------- /tools/original-make: -------------------------------------------------------------------------------- 1 | ../bin/gfx.o: ../src/gfx.c ../src/gfx.h 2 | gcc -c ../src/gfx.c -o ../bin/gfx.o 3 | ../bin/keyboard.o: ../src/keyboard.c ../src/keyboard.h 4 | gcc -c ../src/keyboard.c -o ../bin/keyboard.o 5 | ../bin/load_prog.o: ../src/load_prog.c ../src/load_prog.h 6 | gcc -c ../src/load_prog.c -o ../bin/load_prog.o 7 | ../bin/cpu.o: ../src/cpu.c ../src/cpu.h 8 | gcc -c ../src/cpu.c -o ../bin/cpu.o 9 | 10 | #testOPCODES runs op code test suite 11 | ../bin/testOPCODES.o: ../tests/testOPCODES.c ../tests/minunit.h ../src/cpu.h 12 | gcc -c ../tests/testOPCODES.c -o ../bin/testOPCODES.o 13 | ../bin/testOPCODES: ../bin/cpu.o ../bin/testOPCODES.o 14 | gcc ../bin/cpu.o ../bin/testOPCODES.o -o ../bin/testOPCODES -lX11 -lm 15 | 16 | #runSnake loads and runs snake assembly program 17 | ../bin/runSnake.o: ../snake/runSnake.c ../src/cpu.h ../src/load_prog.h 18 | gcc -c ../snake/runSnake.c -o ../bin/runSnake.o 19 | ../bin/runSnake: ../bin/gfx.o ../bin/keyboard.o ../bin/cpu.o ../bin/load_prog.o ../bin/runSnake.o 20 | gcc ../bin/cpu.o ../bin/keyboard.o ../bin/load_prog.o ../bin/runSnake.o ../bin/gfx.o -o ../bin/runSnake -lX11 -lm 21 | 22 | all: ../bin/testOPCODES ../bin/runSnake 23 | --------------------------------------------------------------------------------