' DRR-NES v0.30 ' A DRR Software Production ' Copyright (c) 1998, 1999 DRR ' All rights reserved. CONST DRR.Software.Version$ = "v0.30" CONST DRR.Software.Build$ = "build 0.30.0028 (99-02-27) -- delta 1" TYPE x86Registers AX AS INTEGER: BX AS INTEGER: CX AS INTEGER: DX AS INTEGER BP AS INTEGER: SI AS INTEGER: DI AS INTEGER: Flags AS INTEGER DS AS INTEGER: ES AS INTEGER END TYPE DECLARE SUB ByeBye () DECLARE SUB Core6502 () DECLARE SUB DrawBitmap (BitmapStyle%, FileName$, ColorsUsed%, BitmapX%, BitmapY%) DECLARE SUB Debugger () DECLARE SUB DrawNESscreen () DECLARE SUB DrawObject (WhichObject%, x1%, y1%, x2%, y2%) DECLARE SUB DrawScrolling (NameTableAddress%, Hscroll%, Vscroll%) DECLARE SUB DrawText (TextFont%, TextToType$, TextX%, TextY%, TextColor%) DECLARE SUB InGameControls () DECLARE SUB InitializeDRRNES () DECLARE SUB InitializeMouse () DECLARE SUB InitializeScreen (WhichMode%) DECLARE SUB InitializeXMS () DECLARE SUB InterruptX (InterruptNumber%, InRegisters AS x86Registers, OutRegisters AS x86Registers) DECLARE SUB LoadCHRROM (SourceBank%, DestinationBank%, LoadSize%) DECLARE SUB LoadPRGROM (SourceBank%, DestinationBank%) DECLARE SUB LoadROM (ROMFileName$) DECLARE FUNCTION MemoryRead% (Address&) DECLARE SUB MemoryWrite (Address&, Value%) DECLARE SUB MouseDriver (AX%, BX%, CX%, DX%) DECLARE FUNCTION Pop% () DECLARE SUB Push (Value%) DECLARE FUNCTION TextBox$ (Column%, Row%, Length%) DECLARE SUB UpdateProgressBar () DECLARE SUB WaitVblank (Waits%) '6502 variables DIM SHARED RegisterA AS INTEGER, RegisterP AS INTEGER, RegisterPC AS LONG DIM SHARED RegisterS AS INTEGER, RegisterX AS INTEGER, RegisterY AS INTEGER DIM SHARED Cycles AS LONG, Instruction AS STRING * 3, SkipLoop AS INTEGER DIM SHARED Opcode AS INTEGER, Argument1 AS INTEGER, Argument2 AS INTEGER DIM SHARED AbsoluteOpcode AS INTEGER, AddressingMode AS INTEGER 'memory variables DIM SHARED PatternTables(8191) AS INTEGER, NameTables(4095) AS INTEGER DIM SHARED RAM(2047) AS INTEGER, SpriteRAM(255) AS INTEGER DIM SHARED MemoryRegisters(31) AS LONG DIM SHARED BackgroundPalette(15) AS INTEGER, SpritePalette(15) AS INTEGER REDIM SHARED ROM(18431) AS INTEGER 'PPU variables DIM SHARED HorizontalScroll AS INTEGER, VerticalScroll AS INTEGER DIM SHARED Frameskip AS INTEGER, SkippedFrames AS INTEGER DIM SHARED Vblank AS INTEGER, VideoPage AS INTEGER DIM SHARED AttributeTable(15, 15) AS INTEGER, Tile(15) AS INTEGER DIM SHARED FPScounter AS INTEGER, ProgramTimer(1) AS SINGLE DIM SHARED Mirroring(3) AS INTEGER 'ROM variables DIM SHARED CHRROMbanks AS INTEGER, PRGROMbanks AS INTEGER, NESFileSize AS LONG DIM SHARED Flags1 AS INTEGER, Flags2 AS INTEGER, OriginalMirroring AS INTEGER DIM SHARED NESROMname AS STRING, Trainer AS INTEGER 'mapper variables DIM SHARED Mapper AS INTEGER, CurrentPRGROMbank(1) AS INTEGER DIM SHARED CurrentCHRROMbank(7) AS INTEGER, WhichMapperRegister AS INTEGER DIM SHARED PRGROMswitching AS INTEGER DIM SHARED MapperRegister AS INTEGER, MapperRegisterBit AS INTEGER DIM SHARED OldPRGROMbank(1) AS INTEGER, CHRROMswitching AS INTEGER 'debugger variables DIM SHARED DebuggerFlag AS INTEGER, DebuggerCount AS INTEGER, Frames AS LONG DIM SHARED MemoryContents(5, 1) AS LONG, OldRegisterPC AS LONG DIM SHARED PaletteCycler AS SINGLE, DisassemblyText AS STRING * 59 DIM SHARED DisasmFile AS STRING, DisasmStatus AS LONG DIM SHARED DisasmPosition AS LONG, ExecuteCPU AS INTEGER DIM SHARED OldDisasmPosition AS LONG, GraphicScroll(240, 16) AS INTEGER 'other variables DIM SHARED Controller(1 TO 2) AS INTEGER DIM SHARED Font0 AS STRING * 4096, Font1 AS STRING * 4096 DIM SHARED Byte AS STRING * 1, PowerOfTwo(7) AS INTEGER, VideoMode AS INTEGER DIM SHARED ExtendedKeyPressed AS INTEGER 'secret variables DIM SHARED CoolMessage AS INTEGER, CoolMessageText AS STRING DIM SHARED CoolMessageText2 AS STRING, CoolMessageText3 AS STRING DIM SHARED FlipColors AS INTEGER, DisplayVersion AS INTEGER 'mouse variables DIM SHARED Mouse(10, 18) AS INTEGER DIM SHARED MouseBackground(10, 18) AS INTEGER DIM SHARED MouseMask(10, 18) AS INTEGER DIM SHARED MouseX AS INTEGER, MouseY AS INTEGER DIM SHARED OldMouseX AS INTEGER, OldMouseY AS INTEGER DIM SHARED MouseButtons AS INTEGER, OldMouseButtons AS INTEGER DIM SHARED NoMouse AS INTEGER CONST FrameCycles% = 29829, VblankCycles% = 26414 'CALL InitializeXMS: END ON ERROR GOTO ErrorHandler RANDOMIZE TIMER: ExecuteCPU = 1 FOR TwoPower% = 0 TO 7: PowerOfTwo(TwoPower%) = 2 ^ TwoPower%: NEXT InitializeScreen 12: InitializeDRRNES: InitializeMouse DrawBitmap 2, "DRR-NES.BMP", 11, 0, 0 DrawText 1, DRR.Software.Version, 0, 464, 10 DrawText 0, "DRR-NES is copyright (c) 1998, 1999 DRR. All rights reserved.", 152, 464, 10 DrawText 1, "For the latest information, visit the official DRR-NES page on DRR's Dimension @", 0, 432, 4 DrawText 1, "-------------------------- http://drr.dragonfire.net --------------------------", 4, 448, 4 WaitVblank 20 FOR PaletteFlash% = 3 TO 5 OUT 967, PaletteFlash% Red% = INP(969): Green% = INP(969): Blue% = INP(969) OUT 968, PaletteFlash% OUT 969, 63: OUT 969, 63: OUT 969, 56 WaitVblank 6 OUT 968, PaletteFlash% OUT 969, Red%: OUT 969, Green%: OUT 969, Blue% NEXT PaletteFlash% WaitVblank 30 LINE (56, 240)-(583, 303), 13, BF DrawObject 40, 54, 236, 587, 307 DrawText 1, "Open an NES ROM image...", 64, 241, 0 DrawText 1, "Open an NES ROM image...", 65, 240, 0 DrawText 1, "Open an NES ROM image...", 65, 241, 0 DrawText 1, "Open an NES ROM image...", 64, 240, 8 DrawText 1, "Enter *.NES ROM filename (including path)....", 80, 254, 0 FileName$ = LTRIM$(RTRIM$(UCASE$(TextBox$(80, 272, 60)))) LINE (72, 256)-(567, 287), 13, BF DrawObject 21, 78, 270, 561, 289 DrawText 1, STRING$(60, "°"), 80, 272, 10 ByteCounter% = LEN(FileName$) IF ByteCounter% = 0 THEN ERROR 253 DO ByteCounter% = ByteCounter% - 1 IF MID$(FileName$, ByteCounter%, 1) = "\" OR ByteCounter% = 1 THEN EXIT DO LOOP NESROMname = RIGHT$(FileName$, LEN(FileName$) - ByteCounter%) LoadROM FileName$ LINE (10, 320)-(209, 399), 13, BF LINE (230, 320)-(429, 399), 13, BF DrawObject 40, 10, 320, 209, 399 DrawObject 40, 230, 320, 429, 399 DrawText 1, "Controller 1", 18, 328, 0 DrawText 1, CHR$(24), 42, 344, 0 DrawText 1, CHR$(27) + " " + CHR$(26) + " V B N M", 26, 360, 0 DrawText 1, CHR$(25), 42, 376, 0 DrawText 1, "Controller 2", 238, 328, 0 DrawText 1, "W", 262, 344, 0 DrawText 1, "A D 1 2 3 4", 246, 360, 0 DrawText 1, "S", 262, 376, 0 DrawText 1, "ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄKeyboard ControlsÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ", 10, 408, 10 DrawText 0, "Press any key to start...", 440, 320, 4 DrawText 1, "[F1] toggles between the", 440, 336, 10 DrawText 1, "debugger/NES screen", 440, 352, 10 DrawText 1, "[F2] toggles the FPS", 440, 368, 10 DrawText 1, "counter & messages", 440, 384, 10 DrawText 1, "[Esc] exits", 440, 400, 10 DO PressedButton$ = UCASE$(INKEY$) SELECT CASE PressedButton$ CASE CHR$(0) + CHR$(&H3B): DebuggerFlag = -1: FPScounter = NOT FPScounter: EXIT DO CASE CHR$(0) + CHR$(&H3C): EXIT DO CASE CHR$(27): ByeBye CASE "" CASE ELSE: FPScounter = NOT FPScounter: EXIT DO END SELECT LOOP IF DebuggerFlag = 0 THEN InitializeScreen 14 Core6502 ErrorHandler: SELECT CASE ERR CASE 52, 53, 75, 253 DrawText 0, "Invalid filename, terminating program...", 80, 254, 0 SLEEP: SCREEN 0: WIDTH 80, 25: SYSTEM CASE 250 InitializeScreen 12 COLOR 5: PRINT "DRR"; : COLOR 3: PRINT "NES": COLOR 14 PRINT "Copyright (c) 1998, 1999 DRR -- All rights reserved.": PRINT COLOR 1: PRINT "**** An invalid opcode was executed. ****" PRINT NESROMname + " attempted to execute the invalid opcode " + HEX$(Opcode) + "." PRINT "Press any key to exit DRR-NES." SLEEP: SCREEN 0: WIDTH 80, 25: SYSTEM CASE 254 InitializeScreen 12 COLOR 5: PRINT "DRR"; : COLOR 3: PRINT "NES": COLOR 14 PRINT "Copyright (c) 1998, 1999 DRR -- All rights reserved.": PRINT COLOR 1: PRINT "**** One or more of the DRR-NES files is missing. ****" PRINT "Make sure that you have ALL of the DRR-NES files in the same directory." PRINT "DRR-NES will now exit so that you can fix the problem." SLEEP: SCREEN 0: WIDTH 80, 25: SYSTEM CASE 76, 255 CLS : COLOR 5: PRINT "DRR"; : COLOR 3: PRINT "NES": COLOR 14 PRINT "Copyright (c) 1998, 1999 DRR -- All rights reserved.": PRINT COLOR 1: PRINT "**** The directory path now listed in C:\DRR-NES.DAT is either incorrect, or" PRINT "some/all of the files necessary to run DRR-NES are missing. *****" COLOR 15: PRINT : INPUT "Type the drive/directory path to this program or type EXIT to exit: ", Path$ Path$ = LTRIM$(RTRIM$(UCASE$(Path$))) IF RIGHT$(FileName$, 1) = "\" THEN FileName$ = LEFT$(FileName$, LEN(FileName$) - 1) IF Path$ = "EXIT" THEN SYSTEM PUT #1, 2, Path$ RESUME NEXT CASE ELSE SCREEN 0: WIDTH 80, 25 PRINT "Warning: An error"; ERR; "occured. Program terminated." END END SELECT FadeColors: DATA 8, 1032, 2056, 1024, 524288, 524294, 2048, 525570, 327680, 132102, 516, 131586, 263172, 394758, 526344 PaletteColors: DATA 0, 63, 8255, 16191, 8192, 4128768, 4128816, 16128, 4138509, 2621440, 1056816, 4128, 1052688, 2105376, 3158064, 4144959 MousePicture: DATA 00,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 DATA 12,00,-1,-1,-1,-1,-1,-1,-1,-1,-1 DATA 12,14,00,-1,-1,-1,-1,-1,-1,-1,-1 DATA 12,14,14,00,-1,-1,-1,-1,-1,-1,-1 DATA 12,15,14,14,00,-1,-1,-1,-1,-1,-1 DATA 12,15,14,14,14,00,-1,-1,-1,-1,-1 DATA 12,15,15,14,14,14,00,-1,-1,-1,-1 DATA 12,15,15,14,14,14,14,00,-1,-1,-1 DATA 12,15,15,15,14,14,14,14,00,-1,-1 DATA 12,15,15,15,14,14,14,14,14,00,-1 DATA 12,15,15,15,00,00,00,00,00,00,00 DATA 12,15,15,00,15,14,00,-1,-1,-1,-1 DATA 12,15,00,-1,12,15,14,00,-1,-1,-1 DATA 12,00,-1,-1,12,15,14,00,-1,-1,-1 DATA 00,-1,-1,-1,-1,12,15,14,00,-1,-1 DATA -1,-1,-1,-1,-1,12,15,14,00,-1,-1 DATA -1,-1,-1,-1,-1,-1,12,15,14,00,-1 DATA -1,-1,-1,-1,-1,-1,12,14,14,00,-1 DATA -1,-1,-1,-1,-1,-1,-1,00,00,00,-1 NESpalette: DATA 117,117,117, 039,027,143, 000,000,171, 071,000,159 DATA 143,000,159, 171,000,019, 167,000,000, 127,011,000 DATA 067,047,000, 000,071,000, 000,081,000, 000,063,023 DATA 027,063,095, 000,000,000, 000,000,000, 000,000,000 DATA 188,188,188, 000,115,239, 035,059,239, 131,000,243 DATA 191,000,191, 231,000,091, 219,043,000, 203,079,015 DATA 139,115,000, 000,151,000, 000,171,000, 000,147,059 DATA 000,131,139, 000,000,000, 000,000,000, 000,000,000 DATA 255,255,255, 063,191,255, 095,151,255, 167,139,253 DATA 247,123,255, 255,119,183, 255,119,099, 255,155,059 DATA 243,191,063, 131,211,019, 079,223,075, 088,248,152 DATA 000,235,219, 000,000,000, 000,000,000, 000,000,000 DATA 255,255,255, 171,231,255, 199,215,255, 215,203,255 DATA 255,199,255, 255,199,219, 255,191,179, 255,219,171 DATA 255,231,163, 227,255,163, 171,243,191, 179,255,207 DATA 159,255,243, 000,000,000, 000,000,000, 000,000,000 DATA 000,000,000,255,000,000,000,255,000,000,000,255 DATA 051,153,255,000,000,153 SUB ByeBye CLOSE #1 IF DisasmStatus THEN CLOSE #2: KILL "Disasm.dis" SCREEN 0: WIDTH 80, 25: SYSTEM END SUB SUB Core6502 DEF SEG = VARSEG(ROM(0)) RegisterPC = PEEK(VARPTR(ROM(0)) + 36861) * 256& + PEEK(VARPTR(ROM(0)) + 36860) RegisterP = 32: RegisterS = 255: MemoryRegisters(2) = 64: Cycles = 7 ProgramTimer(0) = TIMER DO OldRegisterPC = RegisterPC IF Cycles >= FrameCycles THEN SkipLoop = 0 IF DebuggerFlag = 2 THEN DebuggerFlag = 1 MemoryRegisters(2) = MemoryRegisters(2) AND 127: Vblank = NOT Vblank MemoryRegisters(2) = MemoryRegisters(2) OR 64 Frames = Frames + 1 DrawNESscreen IF DebuggerFlag = 0 THEN InGameControls Cycles = Cycles - FrameCycles + 7 IF SkippedFrames = 0 THEN ProgramTimer(0) = TIMER ELSEIF Vblank = 0 AND Cycles >= VblankCycles THEN SkipLoop = 0 IF DebuggerFlag = 2 THEN DebuggerFlag = 1 MemoryRegisters(2) = MemoryRegisters(2) OR 128: Vblank = NOT Vblank MemoryRegisters(2) = MemoryRegisters(2) AND 191 IF MemoryRegisters(0) AND 128 THEN Push RegisterPC \ 256 Push RegisterPC AND 255 Push RegisterP DEF SEG = VARSEG(ROM(0)) RegisterPC = PEEK(VARPTR(ROM(0)) + 36859) * 256& + PEEK(VARPTR(ROM(0)) + 36858) Cycles = Cycles + 7 END IF END IF DEF SEG = VARSEG(ROM(0)) Opcode = PEEK(VARPTR(ROM(0)) + RegisterPC - 28672) Argument1 = PEEK(VARPTR(ROM(0)) + RegisterPC - 28671) Argument2 = PEEK(VARPTR(ROM(0)) + RegisterPC - 28670) AbsoluteOpcode = Opcode AddressingMode = Opcode AND 31 SELECT CASE AddressingMode CASE 0 'immed. AddressingMode = 35 SELECT CASE Opcode CASE &H0 'brk Push RegisterPC \ 256 Push RegisterPC AND 255 RegisterP = RegisterP OR 16 Push RegisterP DEF SEG = VARSEG(ROM(0)) RegisterPC = PEEK(VARPTR(ROM(0)) + 36863) * 256& + PEEK(VARPTR(ROM(0)) + 36862) RegisterPC = RegisterPC + 1 RegisterP = RegisterP OR 4 Cycles = Cycles + 7 CASE &H20 'jsr abs. RegisterPC = RegisterPC + 2 Push RegisterPC \ 256 Push RegisterPC AND 255 RegisterPC = Argument2 * 256& + Argument1 Cycles = Cycles + 6 AddressingMode = 32 CASE &H40 'rti imp. RegisterP = Pop% AND 239 RegisterPC = Pop% RegisterPC = RegisterPC + Pop% * 256& Cycles = Cycles + 6 CASE &H60 'rts imp. RegisterPC = Pop% + 1 RegisterPC = RegisterPC + Pop% * 256& Cycles = Cycles + 6 CASE &H80 ERROR 250 CASE ELSE AddressingMode = 0 MemoryAddress& = -1 AbsoluteOpcode = Opcode + 12 RegisterPC = RegisterPC + 2 END SELECT CASE 1 '(zero pg., x) MemoryAddress& = Argument1 + RegisterX AND 255 MemoryAddress& = MemoryRead%((MemoryAddress& + 1) AND 255) * 256& + MemoryRead%(MemoryAddress&) AbsoluteOpcode = Opcode + 12: Cycles = Cycles + 4: RegisterPC = RegisterPC + 2 CASE 2 'immed. IF Opcode = &HA2 THEN MemoryAddress& = -1 AbsoluteOpcode = Opcode + 12: RegisterPC = RegisterPC + 2 ELSE ERROR 250 END IF CASE 4 TO 6 'zero pg. MemoryAddress& = Argument1 AbsoluteOpcode = Opcode + 8: Cycles = Cycles + 1: RegisterPC = RegisterPC + 2 CASE 8 SELECT CASE Opcode CASE &H8 'php imp. Push RegisterP OR 32: Cycles = Cycles + 3 CASE &H28 'plp imp. RegisterP = Pop%: Cycles = Cycles + 4 CASE &H48 'pha imp. Push RegisterA: Cycles = Cycles + 3 CASE &H68 'pla imp. RegisterA = Pop%: Cycles = Cycles + 4 CASE &H88 'dey imp. RegisterY = RegisterY - 1 AND 255 IF RegisterY THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterY AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HA8 'tay imp. RegisterY = RegisterA IF RegisterY THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterY AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HC8 'iny imp. RegisterY = RegisterY + 1 AND 255 IF RegisterY THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterY AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HE8 'inx imp. RegisterX = RegisterX + 1 AND 255 IF RegisterX THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterX AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 END SELECT RegisterPC = RegisterPC + 1 CASE 9 'immed. MemoryAddress& = -1 AbsoluteOpcode = Opcode + 4: RegisterPC = RegisterPC + 2 CASE 10 'accum. SELECT CASE Opcode CASE &H8A 'txa imp. RegisterA = RegisterX IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE &HAA 'tax imp. RegisterX = RegisterA IF RegisterX THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterX AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE &HCA 'dex imp. RegisterX = RegisterX - 1 AND 255 IF RegisterX THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterX AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE &HEA 'nop imp. Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE ELSE AddressingMode = 10 MemoryAddress& = -2 AbsoluteOpcode = Opcode + 4 Cycles = Cycles - 2 RegisterPC = RegisterPC + 1 END SELECT AddressingMode = 36 CASE 12 TO 14 'abs. MemoryAddress& = Argument2 * 256& + Argument1 AbsoluteOpcode = Opcode: Cycles = Cycles + 2: RegisterPC = RegisterPC + 3 CASE 16 'rel. IF Argument1 AND 128 THEN Argument1 = Argument1 - 256 SELECT CASE Opcode CASE &H10 'bpl rel. IF SkipLoop = 1 AND Argument1 = -5 THEN IF Vblank = 0 THEN Cycles = VblankCycles ELSE Cycles = FrameCycles SkipLoop = -1 END IF IF (RegisterP AND 128) = 0 THEN RegisterPC = RegisterPC + Argument1 CASE &H30 'bmi rel. IF RegisterP AND 128 THEN RegisterPC = RegisterPC + Argument1 CASE &H50 'bvc rel. IF (RegisterP AND 64) = 0 THEN RegisterPC = RegisterPC + Argument1 CASE &H70 'bvs rel. IF RegisterP AND 64 THEN RegisterPC = RegisterPC + Argument1 CASE &H90 'bcc rel. IF (RegisterP AND 1) = 0 THEN RegisterPC = RegisterPC + Argument1 CASE &HB0 'bcs rel. IF RegisterP AND 1 THEN RegisterPC = RegisterPC + Argument1 CASE &HD0 'bne rel. IF (RegisterP AND 2) = 0 THEN RegisterPC = RegisterPC + Argument1 CASE &HF0 'beq rel. IF RegisterP AND 2 THEN RegisterPC = RegisterPC + Argument1 END SELECT AbsoluteOpcode = Opcode: Cycles = Cycles + 2: RegisterPC = RegisterPC + 2 CASE 17 '(zero pg.), y MemoryAddress& = MemoryRead%(Argument1 + 1) * 256& + MemoryRead%(Argument1 + 0) + RegisterY AbsoluteOpcode = Opcode - 4: Cycles = Cycles + 3: RegisterPC = RegisterPC + 2 CASE 20 TO 22 'zero pg., x or zero pg., y IF Opcode = &H96 OR Opcode = &HB6 THEN MemoryAddress& = Argument1 + RegisterY AND 255 ELSE MemoryAddress& = Argument1 + RegisterX AND 255 END IF AbsoluteOpcode = Opcode - 8: Cycles = Cycles + 2: RegisterPC = RegisterPC + 2 CASE 24 SELECT CASE Opcode CASE &H18 'clc imp. RegisterP = RegisterP AND 254 CASE &H38 'sec imp. RegisterP = RegisterP OR 1 CASE &H58 'cli imp. RegisterP = RegisterP AND 251 CASE &H78 'sei imp. RegisterP = RegisterP OR 4 CASE &H98 'tya imp. RegisterA = RegisterY IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 CASE &HB8 'clv imp. RegisterP = RegisterP AND 191 CASE &HD8 'cld imp. RegisterP = RegisterP AND 247 CASE &HF8 'sed imp. RegisterP = RegisterP OR 8 END SELECT Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE 25 'abs., y MemoryAddress& = Argument1 + Argument2 * 256& + RegisterY AbsoluteOpcode = Opcode - 12: Cycles = Cycles + 2: RegisterPC = RegisterPC + 3 CASE 26 'imp. SELECT CASE Opcode CASE &H9A 'txs imp. RegisterS = RegisterX Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE &HBA 'tsx imp. RegisterX = RegisterS IF RegisterX THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterX AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2: RegisterPC = RegisterPC + 1 CASE ELSE ERROR 250 END SELECT CASE 28 TO 30 'abs., x IF Opcode = &HBE THEN MemoryAddress& = Argument1 + Argument2 * 256& + RegisterY ELSE MemoryAddress& = Argument1 + Argument2 * 256& + RegisterX END IF AbsoluteOpcode = Opcode - 16: Cycles = Cycles + 2: RegisterPC = RegisterPC + 3 CASE 3, 7, 11, 15, 19, 23, 27, 31 ERROR 250 END SELECT SELECT CASE AbsoluteOpcode CASE &HC ERROR 250 CASE &HD 'ora RegisterA = RegisterA OR MemoryRead%(MemoryAddress&) IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HE 'asl MemoryData% = MemoryRead%(MemoryAddress&) IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% * 2 AND 255 MemoryWrite MemoryAddress&, MemoryData% IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 4 CASE &H2C 'bit MemoryData% = MemoryRead%(MemoryAddress&) RegisterP = (RegisterP AND 61) OR (MemoryData% AND 192) IF (RegisterA AND MemoryData%) = 0 THEN RegisterP = RegisterP OR 2 Cycles = Cycles + 2 CASE &H2D 'and RegisterA = RegisterA AND MemoryRead%(MemoryAddress&) IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &H2E 'rol MemoryData% = MemoryRead%(MemoryAddress&) * 2 + (RegisterP AND 1) IF MemoryData% AND 256 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% AND 255 MemoryWrite MemoryAddress&, MemoryData% IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 4 CASE &H4C 'jmp IF MemoryAddress& = RegisterPC - 3 THEN IF Vblank = 0 THEN Cycles = VblankCycles ELSE Cycles = FrameCycles SkipLoop = -1 END IF RegisterPC = MemoryAddress& Cycles = Cycles + 1 CASE &H4D 'eor RegisterA = RegisterA XOR MemoryRead%(MemoryAddress&) IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &H4E 'lsr MemoryData% = MemoryRead%(MemoryAddress&) IF MemoryData% AND 1 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% \ 2 MemoryWrite MemoryAddress&, MemoryData% IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 Cycles = Cycles + 4 CASE &H6C 'jmp ind. (&H6C or &H7C) MemoryData% = ((MemoryAddress& AND 255) + 1 AND 255) + MemoryAddress& AND 65280 RegisterPC = MemoryRead%(MemoryAddress& + 1) * 256& + MemoryRead%(MemoryAddress&) Cycles = Cycles + 3 IF Opcode = &H6C THEN AddressingMode = 33 ELSE AddressingMode = 34 CASE &H6D 'adc MemoryData% = MemoryRead%(MemoryAddress&) UnsignedA% = RegisterA + MemoryData% + (RegisterP AND 1) IF RegisterA AND 128 THEN RegisterA = RegisterA - 256 IF MemoryData% AND 128 THEN MemoryData% = MemoryData% - 256 RegisterA = RegisterA + MemoryData% + (RegisterP AND 1) IF RegisterA < -128 OR RegisterA > 127 THEN RegisterP = RegisterP OR 64 ELSE RegisterP = RegisterP AND 191 IF UnsignedA% < 256 THEN RegisterP = RegisterP AND 254 ELSE RegisterP = RegisterP OR 1 RegisterA = UnsignedA% AND 255 IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &H6E 'ror MemoryData% = MemoryRead%(MemoryAddress&) + (RegisterP AND 1) * 256 IF MemoryData% AND 1 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% \ 2 MemoryWrite MemoryAddress&, MemoryData% IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 4 CASE &H8C 'sty MemoryWrite MemoryAddress&, RegisterY Cycles = Cycles + 2 CASE &H8D 'sta MemoryWrite MemoryAddress&, RegisterA Cycles = Cycles + 2 CASE &H8E 'stx MemoryWrite MemoryAddress&, RegisterX Cycles = Cycles + 2 CASE &HAC 'ldy RegisterY = MemoryRead%(MemoryAddress&) IF RegisterY THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterY AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HAD 'lda IF Argument1 = 2 AND Argument2 = 32 THEN SkipLoop = 1 RegisterA = MemoryRead%(MemoryAddress&) IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HAE 'ldx IF Argument1 = 2 AND Argument2 = 32 THEN SkipLoop = 1 RegisterX = MemoryRead%(MemoryAddress&) IF RegisterX THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterX AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HCC 'cpy MemoryData% = RegisterY - MemoryRead%(MemoryAddress&) IF MemoryData% >= 0 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% AND 255 IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HCD 'cmp MemoryData% = RegisterA - MemoryRead%(MemoryAddress&) IF MemoryData% >= 0 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% AND 255 IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HCE 'dec MemoryData% = MemoryRead%(MemoryAddress&) - 1 AND 255 MemoryWrite MemoryAddress&, MemoryData% IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 4 CASE &HEC 'cpx MemoryData% = RegisterX - MemoryRead%(MemoryAddress&) IF MemoryData% >= 0 THEN RegisterP = RegisterP OR 1 ELSE RegisterP = RegisterP AND 254 MemoryData% = MemoryData% AND 255 IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HED 'sbc MemoryData% = MemoryRead%(MemoryAddress&) UnsignedA% = RegisterA - MemoryData% - (RegisterP AND 1 XOR 1) IF RegisterA AND 128 THEN RegisterA = RegisterA - 256 IF MemoryData% AND 128 THEN MemoryData% = MemoryData% - 256 RegisterA = RegisterA - MemoryData% - (RegisterP AND 1 XOR 1) IF RegisterA < -128 OR RegisterA > 127 THEN RegisterP = RegisterP OR 64 ELSE RegisterP = RegisterP AND 191 IF UnsignedA% < 0 THEN RegisterP = RegisterP AND 254 ELSE RegisterP = RegisterP OR 1 RegisterA = UnsignedA% AND 255 IF RegisterA THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF RegisterA AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 2 CASE &HEE 'inc MemoryData% = MemoryRead%(MemoryAddress&) + 1 AND 255 MemoryWrite MemoryAddress&, MemoryData% IF MemoryData% THEN RegisterP = RegisterP AND 253 ELSE RegisterP = RegisterP OR 2 IF MemoryData% AND 128 THEN RegisterP = RegisterP OR 128 ELSE RegisterP = RegisterP AND 127 Cycles = Cycles + 4 END SELECT IF DebuggerFlag = 3 THEN DebuggerCount = DebuggerCount - 1 IF DebuggerCount = 0 THEN DebuggerFlag = 1 END IF IF DebuggerFlag < 0 OR DebuggerFlag = 1 THEN Debugger LOOP END SUB SUB Debugger MouseDriver 7, 0, 0, 629: MouseDriver 8, 0, 0, 461 DO '***** if necessary, initialize the screen mode & debugger display *********** IF DebuggerFlag = -1 THEN InitializeScreen 12 DrawBitmap 1, "DRR-NES.bmp", 11, 320, 344 DrawText 0, "DRR-NES v0.30 -- Copyright (c) 1998, 1999 DRR. All rights reserved.", 0, 464, 10 DrawObject 0, 0, 0, 267, 463 DrawObject 20, 246, 24, 261, 39 DrawObject 20, 246, 40, 261, 423 DrawObject 20, 246, 424, 261, 439 'DrawText 1, "[F1] switches to the main screen.", 0, 292, 15 'DrawText 1, "[F2] executes until Vblank changes.", 0, 308, 15 'DrawText 1, "[F3] executes 100 instructions.", 0, 324, 14 'DrawText 1, "[F4]-[F9] switch memory addresses.", 0, 340, 14 'DrawText 1, "[F10] views the ROM statistics.", 0, 356, 13 'DrawText 1, "The controller keys are toggled.", 0, 372, 13 'DrawText 1, "[Esc] quits the program.", 0, 388, 10 'DrawText 1, "Any other key continues tracing.", 0, 404, 4 FlipColors = 0 IF DisasmStatus = 0 THEN OPEN "Disasm.dis" FOR BINARY AS #2: CLOSE #2 KILL "Disasm.dis" OPEN "Disasm.dis" FOR BINARY AS #2 DisasmText$ = "DRR-NES disassembly of " + LEFT$(NESROMname + SPACE$(12), 12) + CHR$(13) + CHR$(10) + CHR$(13) + CHR$(10) + "Address/Contents Instruction A X Y S P" + CHR$(13) + CHR$(10) PUT #2, 1, DisasmText$ OldDisasmPosition = -1 END IF MouseX = 320: MouseY = 240 OldMouseX = 320: OldMouseY = 240 END IF '***** if necessary, redraw some of the windows ****************************** IF DebuggerFlag = -2 OR DebuggerFlag = -1 THEN LINE (288, 0)-(639, 331), 0, BF DrawObject 40, 288, 0, 639, 79 DrawObject 40, 288, 100, 639, 179 DrawObject 40, 288, 200, 639, 263 DrawObject 40, 288, 284, 639, 331 LINE (292, 4)-(635, 75), 13, BF LINE (292, 104)-(635, 175), 13, BF LINE (292, 204)-(635, 259), 13, BF LINE (292, 288)-(635, 327), 13, BF DrawText 0, "Disassembly of " + NESROMname, 6, 4, 0 DrawText 0, "see DRR-NES.TXT for instructions", 6, 444, 0 DrawText 0, "NES 6502 CPU", 296, 8, 0 DrawText 0, "NES PPU", 296, 108, 0 DrawText 0, "Memory Contents", 296, 208, 0 DrawText 0, "Controller Status", 296, 292, 0 DrawText 1, "(buttons are toggled)", 464, 292, 0 DrawText 1, "[F4]-[F9] change addresses", 424, 208, 0 DebuggerFlag = 1 END IF '***** clear the windows ***************************************************** LINE (248, 42)-(259, 421), 13, BF DrawText 1, CHR$(24), 250, 24, 0 DrawText 1, CHR$(25), 250, 424, 0 IF DisasmStatus - DisasmPosition THEN BoxPosition! = 364 * (1 - ((DisasmStatus - DisasmPosition) / DisasmStatus)) ELSE BoxPosition! = 364 END IF BoxPosition! = INT(BoxPosition!) DrawObject 20, 248, BoxPosition! + 42, 259, BoxPosition! + 57 LINE (292, 224)-(635, 259), 13, BF LINE (292, 308)-(635, 327), 13, BF IF ExecuteCPU THEN LINE (292, 24)-(635, 75), 13, BF LINE (292, 124)-(635, 175), 13, BF DrawText 1, "$ :", 296, 24, 0 DrawText 1, "A: X: Y: S:", 296, 40, 0 DrawText 1, "P: ________ PC: Cycles:", 296, 56, 0 DrawText 1, "Frames: $2000: ________", 296, 124, 0 DrawText 1, "$2001: ________ $2002: ________", 296, 140, 0 DrawText 1, "SPR-RAM: $ Scroll: / VRAM: $", 296, 156, 0 END IF DrawText 1, "p1:", 296, 308, 0: DrawText 1, "p2:", 472, 308, 0 DisasmText$ = SPACE$(58) + CHR$(13) + CHR$(10) '***** part 1 of displaying the current opcode/instruction ******************* IF ExecuteCPU THEN SELECT CASE AbsoluteOpcode CASE &H0: OpcodeText$ = "BRK" CASE &H8: OpcodeText$ = "PHP" CASE &HD: OpcodeText$ = "ORA" CASE &HE: OpcodeText$ = "ASL" CASE &H10: OpcodeText$ = "BPL" CASE &H18: OpcodeText$ = "CLC" CASE &H20: OpcodeText$ = "JSR" CASE &H28: OpcodeText$ = "PLP" CASE &H2C: OpcodeText$ = "BIT" CASE &H2D: OpcodeText$ = "AND" CASE &H2E: OpcodeText$ = "ROL" CASE &H30: OpcodeText$ = "BMI" CASE &H38: OpcodeText$ = "SEC" CASE &H40: OpcodeText$ = "RTI" CASE &H48: OpcodeText$ = "PHA" CASE &H4C: OpcodeText$ = "JMP" CASE &H4D: OpcodeText$ = "EOR" CASE &H4E: OpcodeText$ = "LSR" CASE &H50: OpcodeText$ = "BVC" CASE &H58: OpcodeText$ = "CLI" CASE &H60: OpcodeText$ = "RTS" CASE &H68: OpcodeText$ = "PLA" CASE &H6C: OpcodeText$ = "JMP" CASE &H6D: OpcodeText$ = "ADC" CASE &H6E: OpcodeText$ = "ROR" CASE &H70: OpcodeText$ = "BVS" CASE &H78: OpcodeText$ = "SEI" CASE &H7C: OpcodeText$ = "JMP" CASE &H88: OpcodeText$ = "DEY" CASE &H8A: OpcodeText$ = "TXA" CASE &H8C: OpcodeText$ = "STY" CASE &H8D: OpcodeText$ = "STA" CASE &H8E: OpcodeText$ = "STX" CASE &H90: OpcodeText$ = "BCC" CASE &H98: OpcodeText$ = "TYA" CASE &H9A: OpcodeText$ = "TXS" CASE &HA8: OpcodeText$ = "TAY" CASE &HAA: OpcodeText$ = "TAX" CASE &HAC: OpcodeText$ = "LDY" CASE &HAD: OpcodeText$ = "LDA" CASE &HAE: OpcodeText$ = "LDX" CASE &HB0: OpcodeText$ = "BCS" CASE &HB8: OpcodeText$ = "CLV" CASE &HBA: OpcodeText$ = "TSX" CASE &HC8: OpcodeText$ = "INY" CASE &HCA: OpcodeText$ = "DEX" CASE &HCC: OpcodeText$ = "CPY" CASE &HCD: OpcodeText$ = "CMP" CASE &HCE: OpcodeText$ = "DEC" CASE &HD0: OpcodeText$ = "BNE" CASE &HD8: OpcodeText$ = "CLD" CASE &HE8: OpcodeText$ = "INX" CASE &HEA: OpcodeText$ = "NOP" CASE &HEC: OpcodeText$ = "CPX" CASE &HED: OpcodeText$ = "SBC" CASE &HEE: OpcodeText$ = "INC" CASE &HF0: OpcodeText$ = "BEQ" CASE &HF8: OpcodeText$ = "SED" END SELECT '***** part 2 of displaying the current opcode/instruction ******************* SELECT CASE AddressingMode CASE 0, 2, 9 'immed. OpcodeText$ = OpcodeText$ + " #$" + RIGHT$("0" + HEX$(Argument1), 2) OpcodeBytes% = 2 CASE 1 '(zero pg., x) OpcodeText$ = OpcodeText$ + " ($" + RIGHT$("0" + HEX$(Argument1), 2) + ", X)" OpcodeBytes% = 2 CASE 4 TO 6 'zero pg. OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument1), 2) OpcodeBytes% = 2 CASE 8, 24, 35 'imp. OpcodeBytes% = 1 CASE 10 'accum. OpcodeText$ = OpcodeText$ + " A" OpcodeBytes% = 1 CASE 12 TO 14, 32 'abs. OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument2), 2) + RIGHT$("0" + HEX$(Argument1), 2) OpcodeBytes% = 3 CASE 16 'rel. IF Argument1 < 0 THEN OpcodeText$ = OpcodeText$ + " -$" ELSE OpcodeText$ = OpcodeText$ + " +$" END IF OpcodeText$ = OpcodeText$ + RIGHT$("0" + HEX$(ABS(Argument1)), 2) OpcodeBytes% = 2 CASE 17 '(zero pg.), y OpcodeText$ = OpcodeText$ + " ($" + RIGHT$("0" + HEX$(Argument1), 2) + "), Y" OpcodeBytes% = 2 CASE 20 TO 22 'zero pg., x or zero pg., y IF Opcode = &H96 OR Opcode = &HB6 THEN OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument1), 2) + ", Y" ELSE OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument1), 2) + ", X" END IF OpcodeBytes% = 2 CASE 25 'abs., y OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument2), 2) + RIGHT$("0" + HEX$(Argument1), 2) + ", Y" OpcodeBytes% = 3 CASE 28 TO 30 'abs., x or abs., y IF Opcode = &HBE THEN OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument2), 2) + RIGHT$("0" + HEX$(Argument1), 2) + ", Y" ELSE OpcodeText$ = OpcodeText$ + " $" + RIGHT$("0" + HEX$(Argument2), 2) + RIGHT$("0" + HEX$(Argument1), 2) + ", X" END IF OpcodeBytes% = 3 CASE 33 '(abs.) OpcodeText$ = OpcodeText$ + " ($" + RIGHT$("0" + HEX$(Argument2), 2) + RIGHT$("0" + HEX$(Argument1), 2) + ")" OpcodeBytes% = 3 CASE 34 '(abs., x) OpcodeText$ = OpcodeText$ + " ($" + RIGHT$("0" + HEX$(Argument2), 2) + RIGHT$("0" + HEX$(Argument1), 2) + ", X)" OpcodeBytes% = 3 END SELECT MID$(DisasmText$, 1, 6) = "$" + RIGHT$("000" + HEX$(OldRegisterPC), 4) + ":" MID$(DisasmText$, 18, 14) = OpcodeText$ DrawText 1, MID$(DisasmText$, 2, 4), 304, 24, 0 DrawText 1, OpcodeText$, 432, 24, 0 MID$(DisasmText$, 8, 2) = RIGHT$("0" + HEX$(Opcode), 2) IF OpcodeBytes% >= 2 THEN MID$(DisasmText$, 11, 2) = RIGHT$("0" + HEX$(Argument1), 2) IF OpcodeBytes% = 3 THEN MID$(DisasmText$, 14, 2) = RIGHT$("0" + HEX$(Argument2), 2) DrawText 1, MID$(DisasmText$, 8, 8), 352, 24, 0 '***** the CPU registers ***************************************************** MID$(DisasmText$, 35, 14) = RIGHT$("0" + HEX$(RegisterA), 2) + " " + RIGHT$("0" + HEX$(RegisterX), 2) + " " + RIGHT$("0" + HEX$(RegisterY), 2) + " " + RIGHT$("0" + HEX$(RegisterS), 2) DrawText 1, MID$(DisasmText$, 35, 2), 320, 40, 0 DrawText 1, MID$(DisasmText$, 39, 2), 376, 40, 0 DrawText 1, MID$(DisasmText$, 43, 2), 432, 40, 0 DrawText 1, MID$(DisasmText$, 47, 2), 488, 40, 0 DrawText 1, RIGHT$("000" + HEX$(RegisterPC), 4), 432, 56, 0 MID$(DisasmText$, 51, 8) = "--------" IF RegisterP AND 128 THEN MID$(DisasmText$, 51, 1) = "N" IF RegisterP AND 64 THEN MID$(DisasmText$, 52, 1) = "V" MID$(DisasmText$, 53, 1) = "1" IF RegisterP AND 16 THEN MID$(DisasmText$, 54, 1) = "B" IF RegisterP AND 8 THEN MID$(DisasmText$, 55, 1) = "D" IF RegisterP AND 4 THEN MID$(DisasmText$, 56, 1) = "I" IF RegisterP AND 2 THEN MID$(DisasmText$, 57, 1) = "Z" IF RegisterP AND 1 THEN MID$(DisasmText$, 58, 1) = "C" DrawText 1, MID$(DisasmText$, 51, 8), 320, 56, 0 '***** PPU registers and other miscellaneous stuff ************************** DrawText 1, STR$(Cycles), 536, 56, 0 DrawText 1, STR$(Frames), 352, 124, 0 FOR PowerCount% = 7 TO 0 STEP -1 IF MemoryRegisters(0) AND PowerOfTwo(PowerCount%) THEN DrawText 1, "X", 496 + 8 * (7 - PowerCount%), 124, 0 NEXT PowerCount% FOR PowerCount% = 7 TO 0 STEP -1 IF MemoryRegisters(1) AND PowerOfTwo(PowerCount%) THEN DrawText 1, "X", 352 + 8 * (7 - PowerCount%), 140, 0 NEXT PowerCount% FOR PowerCount% = 7 TO 0 STEP -1 IF MemoryRegisters(2) AND PowerOfTwo(PowerCount%) THEN DrawText 1, "X", 488 + 8 * (7 - PowerCount%), 140, 0 NEXT PowerCount% DrawText 1, RIGHT$("0" + HEX$(MemoryRegisters(3)), 2), 376, 156, 0 DrawText 1, RIGHT$("00" + RIGHT$(STR$(HorizontalScroll), LEN(STR$(HorizontalScroll)) - 1), 3), 472, 156, 0 DrawText 1, RIGHT$("00" + RIGHT$(STR$(VerticalScroll), LEN(STR$(VerticalScroll)) - 1), 3), 504, 156, 0 DrawText 1, RIGHT$("000" + HEX$(MemoryRegisters(6)), 4), 600, 156, 0 END IF '***** memory contents window ************************************************ FOR WhichMC% = 0 TO 5 SELECT CASE MemoryContents(WhichMC%, 0) CASE 1 SELECT CASE MemoryContents(WhichMC%, 1) CASE -32768 TO -1 DEF SEG = VARSEG(ROM(0)) Value% = PEEK(VARPTR(ROM(0)) + MemoryContents(WhichMC%, 1) + 36864) CASE 0 TO 8191 Value% = RAM(MemoryContents(WhichMC%, 1) AND 2047) CASE 28672 TO 32767 DEF SEG = VARSEG(ROM(0)) Value% = PEEK(VARPTR(ROM(0)) + MemoryContents(WhichMC%, 1) - 28672) END SELECT DrawText 1, "cpu$" + RIGHT$("000" + HEX$(MemoryContents(WhichMC%, 1)), 4) + ":" + RIGHT$("0" + HEX$(Value%), 2), 296 + ((WhichMC% MOD 3) * 8 * 14), 224 + ((WhichMC% \ 3) * 16), 0 CASE 2 SELECT CASE MemoryContents(WhichMC%, 1) CASE 0 TO 8191 Value% = PatternTables(MemoryContents(WhichMC%, 1)) CASE 8192 TO 12287 Value% = NameTables(MemoryContents(WhichMC%, 1) - 8192) CASE 16128 TO 16143 Value% = BackgroundPalette(MemoryContents(WhichMC%, 1) AND 15) CASE 16144 TO 16159 Value% = SpritePalette(MemoryContents(WhichMC%, 1) AND 15) END SELECT DrawText 1, "ppu$" + RIGHT$("000" + HEX$(MemoryContents(WhichMC%, 1)), 4) + ":" + RIGHT$("0" + HEX$(Value%), 2), 296 + ((WhichMC% MOD 3) * 8 * 14), 224 + ((WhichMC% \ 3) * 16), 0 CASE 3 Value% = SpriteRAM(MemoryContents(WhichMC%, 1)) DrawText 1, "spr$" + RIGHT$("0" + HEX$(MemoryContents(WhichMC%, 1)), 2) + ":" + RIGHT$("0" + HEX$(Value%), 2), 296 + ((WhichMC% MOD 3) * 8 * 14), 224 + ((WhichMC% \ 3) * 16), 0 END SELECT NEXT WhichMC% '***** the controllers ******************************************************* IF Controller(1) AND 16 THEN DrawText 1, CHR$(24), 320, 308, 0 IF Controller(1) AND 64 THEN DrawText 1, CHR$(27), 328, 308, 0 IF Controller(1) AND 128 THEN DrawText 1, CHR$(26), 336, 308, 0 IF Controller(1) AND 32 THEN DrawText 1, CHR$(25), 344, 308, 0 IF Controller(1) AND 4 THEN DrawText 1, "Sel", 360, 308, 0 IF Controller(1) AND 8 THEN DrawText 1, "Str", 392, 308, 0 IF Controller(1) AND 2 THEN DrawText 1, "B", 424, 308, 0 IF Controller(1) AND 1 THEN DrawText 1, "A", 440, 308, 0 IF Controller(2) AND 16 THEN DrawText 1, CHR$(24), 504, 308, 0 IF Controller(2) AND 64 THEN DrawText 1, CHR$(27), 512, 308, 0 IF Controller(2) AND 128 THEN DrawText 1, CHR$(26), 520, 308, 0 IF Controller(2) AND 32 THEN DrawText 1, CHR$(25), 528, 308, 0 IF Controller(2) AND 4 THEN DrawText 1, "Sel", 544, 308, 0 IF Controller(2) AND 8 THEN DrawText 1, "Str", 576, 308, 0 IF Controller(2) AND 2 THEN DrawText 1, "B", 608, 308, 0 IF Controller(2) AND 1 THEN DrawText 1, "A", 624, 308, 0 '***** draw the disassembly window ******************************************* PUT #2, DisasmStatus * 60 + 93, DisasmText$ IF OldDisasmPosition = DisasmPosition - 1 THEN FOR Disassembly% = 1 TO 25 GET (6, Disassembly% * 16 + 24)-(245, Disassembly% * 16 + 39), GraphicScroll PUT (6, Disassembly% * 16 + 8), GraphicScroll, PSET NEXT Disassembly% GET #2, DisasmPosition * 60 + 93, DisassemblyText IF LEFT$(DisassemblyText, 1) = "*" THEN DisassemblyText = SPACE$(31) LINE (6, 424)-(245, 439), 13, BF DrawText 1, MID$(DisassemblyText, 1, 6) + MID$(DisassemblyText, 8, 24), 6, 424, 0 ELSEIF OldDisasmPosition = DisasmPosition + 1 THEN FOR Disassembly% = 24 TO 0 STEP -1 GET (6, Disassembly% * 16 + 24)-(245, Disassembly% * 16 + 39), GraphicScroll PUT (6, Disassembly% * 16 + 40), GraphicScroll, PSET NEXT Disassembly% LINE (6, 24)-(245, 39), 13, BF IF DisasmPosition - 25 >= 0 THEN GET #2, (DisasmPosition - 25) * 60 + 93, DisassemblyText IF LEFT$(DisassemblyText, 1) = "*" THEN DisassemblyText = SPACE$(31) DrawText 1, MID$(DisassemblyText, 1, 6) + MID$(DisassemblyText, 8, 24), 6, 24, 0 END IF ELSEIF OldDisasmPosition = DisasmPosition THEN GET #2, DisasmPosition * 60 + 93, DisassemblyText IF LEFT$(DisassemblyText, 1) = "*" THEN DisassemblyText = SPACE$(31) LINE (6, 424)-(245, 439), 13, BF DrawText 1, MID$(DisassemblyText, 1, 6) + MID$(DisassemblyText, 8, 24), 6, 424, 0 ELSE LINE (6, 24)-(245, 439), 13, BF FOR Disassembly% = 0 TO 25 IF DisasmPosition - Disassembly% >= 0 THEN GET #2, (DisasmPosition - Disassembly%) * 60 + 93, DisassemblyText IF LEFT$(DisassemblyText, 1) = "*" THEN DisassemblyText = SPACE$(31) DrawText 1, MID$(DisassemblyText, 1, 6) + MID$(DisassemblyText, 8, 24), 6, (25 - Disassembly%) * 16 + 24, 0 END IF NEXT Disassembly% END IF OldDisasmPosition = DisasmPosition IF ExecuteCPU THEN IF DisasmPosition = DisasmStatus THEN DisasmPosition = DisasmPosition + 1 DisasmStatus = DisasmStatus + 1 END IF '***** Check the keyboard and other miscellaneous stuff ********************** ExecuteCPU = 0 DO 'GET (MouseX, MouseY)-(MouseX + 10, MouseY + 18), MouseBackground 'WaitVblank 1 'PUT (MouseX, MouseY), MouseMask, AND 'PUT (MouseX, MouseY), Mouse, OR IF FlipColors THEN IF PaletteCycler < 32 THEN PaletteCycler = PaletteCycler + .25 ELSE PaletteCycler = 0 IF PaletteCycler >= 16 THEN PaletteColor% = 32 - INT(PaletteCycler) ELSE PaletteColor% = INT(PaletteCycler) IF FlipColors = 1 THEN OUT 968, 0 OUT 969, 63 - PaletteColor% OUT 969, 63 - PaletteColor% OUT 969, 63 - PaletteColor% OUT 968, 13 OUT 969, (PaletteColor% \ 2) + 24 OUT 969, (PaletteColor% \ 2) + 24 OUT 969, (PaletteColor% \ 2) + 24 ELSE OUT 968, 0 OUT 969, 0 OUT 969, 0 OUT 969, PaletteColor% END IF END IF 'WaitVblank 1 PressedButton$ = UCASE$(INKEY$) SELECT CASE PressedButton$ CASE CHR$(0) + CHR$(&H3B) IF DisasmPosition = DisasmStatus THEN DisasmPosition = DisasmPosition + 3 SkipText$ = "**** The user exited debugger mode for at least one ****" + CHR$(13) + CHR$(10) PUT #2, DisasmStatus * 60 + 93, SkipText$ DisasmStatus = DisasmStatus + 1 SkipText$ = "**** frame, so a very large section of this ****" + CHR$(13) + CHR$(10) PUT #2, DisasmStatus * 60 + 93, SkipText$ DisasmStatus = DisasmStatus + 1 SkipText$ = "**** disassembly is missing. ****" + CHR$(13) + CHR$(10) PUT #2, DisasmStatus * 60 + 93, SkipText$ DisasmStatus = DisasmStatus + 1 InitializeScreen 14: DebuggerFlag = 0 ExecuteCPU = 1: EXIT DO CASE CHR$(0) + CHR$(&H3C) IF DisasmPosition = DisasmStatus THEN DisasmPosition = DisasmPosition + 2 SkipText$ = "**** The disassembly was paused until the Vblank ****" + CHR$(13) + CHR$(10) PUT #2, DisasmStatus * 60 + 93, SkipText$ DisasmStatus = DisasmStatus + 1 SkipText$ = "**** status changed. ****" + CHR$(13) + CHR$(10) PUT #2, DisasmStatus * 60 + 93, SkipText$ DisasmStatus = DisasmStatus + 1 DebuggerFlag = 2 ExecuteCPU = 1: EXIT DO CASE CHR$(0) + CHR$(&H3D) IF DisasmPosition = DisasmStatus THEN DisasmPosition = DisasmPosition + 1 SkipText$ = "**** The disassembly was paused for 100 instructions. ****" + CHR$(13) + CHR$(10) PUT #2, DisasmStatus * 60 + 93, SkipText$ DisasmStatus = DisasmStatus + 1 DebuggerFlag = 3: DebuggerCount = 100 ExecuteCPU = 1: EXIT DO CASE CHR$(0) + CHR$(&H3E) TO CHR$(0) + CHR$(&H43) WhichMC% = ASC(RIGHT$(PressedButton$, 1)) - 62 LINE (296, 224)-(635, 255), 13, BF DrawText 1, "Press a key to select the address type:", 296, 224, 0 DrawText 1, "[C]PU, [P]PU, or [S]prite Address", 296, 240, 0 DO SELECT CASE UCASE$(INKEY$) CASE "C": MemoryContents(WhichMC%, 0) = 1: BoxSpaces% = 4: EXIT DO CASE "P": MemoryContents(WhichMC%, 0) = 2: BoxSpaces% = 4: EXIT DO CASE "S": MemoryContents(WhichMC%, 0) = 3: BoxSpaces% = 2: EXIT DO END SELECT LOOP LINE (296, 224)-(635, 255), 13, BF DrawText 1, "Enter the address in hexadecimal:", 296, 232, 0 MemoryContents(WhichMC%, 1) = VAL("&H" + TextBox$(600, 232, BoxSpaces%)) EXIT DO CASE CHR$(0) + CHR$(&H44) LINE (288, 0)-(639, 331), 13, BF DrawObject 40, 288, 0, 639, 331 DrawText 0, "NES ROM Information", 296, 8, 0 DrawText 1, "File name: " + NESROMname + " (" + RIGHT$(STR$(NESFileSize), LEN(STR$(NESFileSize)) - 1) + " bytes)", 296, 24, 0 DrawText 1, "Mapper number:" + STR$(Mapper), 296, 40, 0 DrawText 1, "16KB PRG-ROM banks:" + STR$(PRGROMbanks), 296, 56, 0 DrawText 1, "8KB CHR-ROM banks:" + STR$(CHRROMbanks), 296, 72, 0 SELECT CASE OriginalMirroring CASE -1 DrawText 1, "Name Table Mirroring: Single-screen @ $2000", 296, 88, 0 CASE 0 DrawText 1, "Name Table Mirroring: Horizontal", 296, 88, 0 CASE 1 DrawText 1, "Name Table Mirroring: Vertical", 296, 88, 0 END SELECT IF Flags1 AND 2 THEN DrawText 1, "SRAM: Present", 296, 104, 0 ELSE DrawText 1, "SRAM: Not present", 296, 104, 0 IF Flags1 AND 4 THEN DrawText 1, "512 byte trainer: Present", 296, 120, 0 ELSE DrawText 1, "512 byte trainer: Not present", 296, 120, 0 DrawText 0, "Press any key to continue...", 296, 136, 0 DrawText 0, "PRGROM bank @ $8000:" + STR$(CurrentPRGROMbank(0)), 296, 152, 0 DrawText 0, "PRGROM bank @ $C000:" + STR$(CurrentPRGROMbank(1)), 296, 168, 0 DrawText 0, "PRGROM switching:" + STR$(PRGROMswitching), 296, 184, 0 DebuggerFlag = -2 SLEEP EXIT DO CASE CHR$(0) + CHR$(&H47) DisasmPosition = 0 EXIT DO CASE CHR$(0) + CHR$(&H49) IF DisasmPosition > 0 THEN DisasmPosition = DisasmPosition - 1 EXIT DO CASE CHR$(0) + CHR$(&H4F) DisasmPosition = DisasmStatus EXIT DO CASE CHR$(0) + CHR$(&H51) IF DisasmPosition < DisasmStatus THEN DisasmPosition = DisasmPosition + 1 EXIT DO CASE CHR$(9) LINE (288, 0)-(639, 331), 13, BF DrawObject 40, 288, 0, 639, 331 DrawText 0, "Don't you have anything better to do than", 296, 8, 0 DrawText 0, "push random keys looking for secrets?", 296, 24, 0 DrawText 1, "Well, I'll tell you this. When you're", 296, 40, 0 DrawText 1, "in regular (non-debugger) mode, press", 296, 56, 0 DrawText 1, "[F10] whenever you get bored from the", 296, 72, 0 DrawText 1, "sheer slowness of this emulator.", 296, 88, 0 DrawText 0, "Press any key for a cool surprise...", 296, 120, 0 DebuggerFlag = -2 SLEEP IF FlipColors = 1 THEN FlipColors = 2 ELSE FlipColors = 1 IF FlipColors = 1 THEN PALETTE 15, 0 PALETTE 14, 1052688 PALETTE 13, 2105376 PALETTE 12, 3158064 PALETTE 0, 4144959 ELSE PALETTE 0, 0 PALETTE 12, 1052688 PALETTE 13, 2105376 PALETTE 14, 3158064 PALETTE 15, 4144959 END IF EXIT DO CASE CHR$(0) + "H": Controller(1) = Controller(1) XOR 16: EXIT DO CASE CHR$(0) + "K": Controller(1) = Controller(1) XOR 64: EXIT DO CASE CHR$(0) + "M": Controller(1) = Controller(1) XOR 128: EXIT DO CASE CHR$(0) + "P": Controller(1) = Controller(1) XOR 32: EXIT DO CASE "V": Controller(1) = Controller(1) XOR 4: EXIT DO CASE "B": Controller(1) = Controller(1) XOR 8: EXIT DO CASE "N": Controller(1) = Controller(1) XOR 2: EXIT DO CASE "M": Controller(1) = Controller(1) XOR 1: EXIT DO CASE "W": Controller(2) = Controller(2) XOR 16: EXIT DO CASE "A": Controller(2) = Controller(2) XOR 64: EXIT DO CASE "S": Controller(2) = Controller(2) XOR 128: EXIT DO CASE "D": Controller(2) = Controller(2) XOR 32: EXIT DO CASE "1": Controller(2) = Controller(2) XOR 4: EXIT DO CASE "2": Controller(2) = Controller(2) XOR 8: EXIT DO CASE "3": Controller(2) = Controller(2) XOR 2: EXIT DO CASE "4": Controller(2) = Controller(2) XOR 1: EXIT DO CASE CHR$(27): ByeBye CASE "" CASE ELSE: ExecuteCPU = 1: EXIT DO END SELECT 'PUT (MouseX, MouseY), MouseBackground, PSET 'OldMouseX = MouseX: OldMouseY = MouseY: OldMouseButtons = MouseButtons 'MouseDriver 3, MouseButtons, MouseX, MouseY LOOP DEF SEG = 0: POKE &H41A, PEEK(&H41C) IF ExecuteCPU = 1 THEN EXIT DO LOOP END SUB SUB DrawBitmap (BitmapStyle%, FileName$, ColorsUsed%, BitmapX%, BitmapY%) FileHandle% = FREEFILE OPEN FileName$ FOR BINARY AS FileHandle% IF LOF(FileHandle%) = 0 THEN CLOSE FileHandle%: KILL FileName$: ERROR 254 GET FileHandle%, 19, BitmapWidth% GET FileHandle%, 23, BitmapHeight% SEEK FileHandle%, 55 PictureData$ = INPUT$(1024, FileHandle%) FOR PaletteColor% = 0 TO ColorsUsed% FourBytes$ = MID$(PictureData$, PaletteColor% * 4 + 1, 4) OUT 968, PaletteColor% OUT 969, ASC(MID$(FourBytes$, 3, 1)) \ 4 OUT 969, ASC(MID$(FourBytes$, 2, 1)) \ 4 OUT 969, ASC(FourBytes$) \ 4 NEXT PaletteColor% GET FileHandle%, 11, BitmapOffset% SEEK FileHandle%, BitmapOffset% + 1 SELECT CASE BitmapStyle% CASE 1 BitmapWidth% = (((BitmapWidth% - 1) OR 7) + 1) \ 2 FOR Row% = BitmapY% + BitmapHeight% - 1 TO BitmapY% STEP -1 RowData$ = INPUT$(BitmapWidth%, FileHandle%) FOR Column% = 0 TO BitmapWidth% - 1 TwoPixels% = ASC(MID$(RowData$, Column% + 1, 1)) PSET (Column% * 2 + BitmapX%, Row%), TwoPixels% \ 16 PSET (Column% * 2 + BitmapX% + 1, Row%), TwoPixels% AND 15 NEXT Column% NEXT Row% CASE 2 BitmapWidth% = (((BitmapWidth% - 1) OR 7) + 1) \ 2 FOR Row% = (BitmapHeight% - 1) * 2 TO 0 STEP -2 RowData$ = INPUT$(BitmapWidth%, FileHandle%) FOR Column% = 0 TO (BitmapWidth% - 1) * 2 STEP 2 TwoPixels% = ASC(MID$(RowData$, Column% \ 2 + 1, 1)) PSET (Column% * 2, Row%), TwoPixels% \ 16 PSET (Column% * 2 + 1, Row%), TwoPixels% \ 16 PSET (Column% * 2, Row% + 1), TwoPixels% \ 16 PSET (Column% * 2 + 1, Row% + 1), TwoPixels% \ 16 PSET (Column% * 2 + 2, Row%), TwoPixels% AND 15 PSET (Column% * 2 + 3, Row%), TwoPixels% AND 15 PSET (Column% * 2 + 2, Row% + 1), TwoPixels% AND 15 PSET (Column% * 2 + 3, Row% + 1), TwoPixels% AND 15 NEXT Column% NEXT Row% END SELECT CLOSE FileHandle% END SUB SUB DrawNESscreen IF VideoPage THEN DEF SEG = &HA000 ELSE DEF SEG = &HA4F0 SkippedFrames = SkippedFrames + 1 IF SkippedFrames >= Frameskip + 1 THEN SkippedFrames = 0 ELSE EXIT SUB IF DebuggerFlag = 0 THEN SELECT CASE MemoryRegisters(1) AND 224 CASE 0: BGcolor% = 65 CASE 32: BGcolor% = 66 CASE 64: BGcolor% = 67 CASE 128: BGcolor% = 68 END SELECT OUT &H3C4, 2: OUT &H3C5, 15 FOR ClearByte% = 0 TO 19199: POKE ClearByte%, BGcolor%: NEXT IF MemoryRegisters(1) AND 8 THEN IF MemoryRegisters(0) AND 16 THEN PatternTableAddress% = 4096 ELSE PatternTableAddress% = 0 IF HorizontalScroll OR VerticalScroll THEN Htable% = (MemoryRegisters(0) AND 1) * 1024 Vtable% = (MemoryRegisters(0) AND 2) * 1024 DrawScrolling Htable% + Vtable%, 256 - HorizontalScroll, -VerticalScroll DrawScrolling 1024 - Htable% + Vtable%, -HorizontalScroll, -VerticalScroll DrawScrolling 2048 + Htable% - Vtable%, 256 - HorizontalScroll, 240 - VerticalScroll DrawScrolling 3072 - Htable% - Vtable%, -HorizontalScroll, 240 - VerticalScroll ELSE NameTableAddress% = (MemoryRegisters(0) AND 3) * 1024 + Mirroring(MemoryRegisters(0) AND 3) AttributeTableAddress% = NameTableAddress% + 960 FOR AttributeY% = 0 TO 14 STEP 2 FOR AttributeX% = 0 TO 14 STEP 2 AttributeColor% = NameTables(AttributeTableAddress%) AttributeTableAddress% = AttributeTableAddress% + 1 AttributeTable(AttributeX%, AttributeY%) = (AttributeColor% AND 3) * 4 AttributeTable(AttributeX% + 1, AttributeY%) = AttributeColor% AND 12 AttributeTable(AttributeX%, AttributeY% + 1) = (AttributeColor% AND 48) \ 4 AttributeTable(AttributeX% + 1, AttributeY% + 1) = (AttributeColor% AND 192) \ 16 NEXT AttributeX% NEXT AttributeY% IF (MemoryRegisters(1) AND 2) = 0 THEN BGcutoff% = 8 FOR TileY% = 8 TO 224 STEP 8 FOR TileX% = BGcutoff% TO 248 STEP 8 PixelColorHigh% = AttributeTable(TileX% \ 16, TileY% \ 16) TileAddress% = PatternTableAddress% + NameTables(NameTableAddress% + TileY% * 4 + TileX% \ 8) * 16 FOR TileByte% = 0 TO 15: Tile(TileByte%) = PatternTables(TileAddress% + TileByte%): NEXT FOR PixelX% = 0 TO 7 OUT &H3C4, 2: OUT &H3C5, PowerOfTwo(3 - PixelX% AND 3) CurrentPixelX% = (TileX% - PixelX% + 39) \ 4 FOR PixelY% = 0 TO 7 IF Tile(PixelY%) AND PowerOfTwo(PixelX%) THEN PixelColor% = 1 ELSE PixelColor% = 0 IF Tile(PixelY% + 8) AND PowerOfTwo(PixelX%) THEN PixelColor% = PixelColor% + 2 POKE CurrentPixelX% + (TileY% + PixelY%) * 80, BackgroundPalette(PixelColorHigh% + PixelColor%) + 1 NEXT PixelY% NEXT PixelX% NEXT TileX% NEXT TileY% END IF END IF IF MemoryRegisters(1) AND 16 THEN IF (MemoryRegisters(1) AND 4) = 0 THEN SpriteCutOff% = 8 MemoryRegisters(2) = MemoryRegisters(2) OR 64 IF MemoryRegisters(0) AND 32 THEN TwoSprites% = 1 IF MemoryRegisters(0) AND 8 THEN SpriteTableAddress% = 4096 ELSE SpriteTableAddress% = 0 FOR Sprite% = 0 TO 252 STEP 4 TileAddress% = SpriteTableAddress% + (SpriteRAM(Sprite% + 1) - TwoSprites% AND 255) * 16 SpriteFlags% = SpriteRAM(Sprite% + 2): PixelColorHigh% = (SpriteFlags% AND 3) * 4 SpriteX% = SpriteRAM(Sprite% + 3) SpriteY% = SpriteRAM(Sprite%) + 1 FOR TileByte% = 0 TO 15: Tile(TileByte%) = PatternTables(TileAddress% + TileByte%): NEXT IF SpriteFlags% AND 128 THEN FlipY% = 7: StepY% = -1 ELSE FlipY% = 0: StepY% = 1 IF SpriteFlags% AND 64 THEN FlipX% = 0: StepX% = 1 ELSE FlipX% = 7: StepX% = -1 DoubleYflip% = 0 IF FlipY% = 7 AND TwoSprites% = 1 THEN SpriteY% = SpriteY% + 8: FlipY% = 0: StepY% = 1: DoubleYflip% = 1 FOR NumberOfSpritesToDraw% = 0 TO TwoSprites% ActualX% = FlipX% FOR PixelX% = 0 TO 7 IF SpriteX% + ActualX% >= SpriteCutOff% AND SpriteX% + ActualX% <= 255 THEN OUT &H3C4, 2: OUT &H3C5, PowerOfTwo((SpriteX% + ActualX% + 32) AND 3) CurrentPixelX% = (SpriteX% + ActualX% + 32) \ 4 ActualY% = FlipY% FOR PixelY% = 0 TO 7 IF SpriteY% + ActualY% >= 8 AND SpriteY% + ActualY% <= 231 THEN IF Tile(PixelY%) AND PowerOfTwo(PixelX%) THEN PixelColor% = 1 ELSE PixelColor% = 0 IF Tile(PixelY% + 8) AND PowerOfTwo(PixelX%) THEN PixelColor% = PixelColor% + 2 IF PixelColor% THEN POKE CurrentPixelX% + (SpriteY% + ActualY%) * 80, SpritePalette(PixelColorHigh% + PixelColor%) + 1 END IF ActualY% = ActualY% + StepY% NEXT PixelY% END IF ActualX% = ActualX% + StepX% NEXT PixelX% IF TwoSprites% THEN TileAddress% = SpriteTableAddress% + SpriteRAM(Sprite% + 1) * 16 FOR TileByte% = 0 TO 15: Tile(TileByte%) = PatternTables(TileAddress% + TileByte%): NEXT IF DoubleYflip% = 0 THEN SpriteY% = SpriteY% + 8 ELSE SpriteY% = SpriteY% - 8 END IF NEXT NumberOfSpritesToDraw% NEXT Sprite% END IF IF FPScounter THEN ProgramTimer(1) = TIMER - ProgramTimer(0) DrawText 1, "Frameskip:" + STR$(Frameskip), 2, 414, 70 DrawText 1, "Frameskip:" + STR$(Frameskip), 0, 416, 69 IF ProgramTimer(1) = 0 THEN DrawText 1, "QB returned infinity so it's over 18 fps", 2, 446, 70 DrawText 1, "QB returned infinity so it's over 18 fps", 0, 448, 69 ELSE ProgramTimer(1) = 1 / ProgramTimer(1) ProgramTimer(1) = INT(ProgramTimer(1) * 100 * (Frameskip + 1)) / 100 DrawText 1, "Watch QB go!" + STR$(ProgramTimer(1)) + "/60 fps", 2, 446, 70 DrawText 1, "Watch QB go!" + STR$(ProgramTimer(1)) + "/60 fps", 0, 448, 69 END IF IF DisplayVersion THEN DrawText 1, DRR.Software.Build, 1, 0, 70 DrawText 1, DRR.Software.Build, 0, 2, 69 END IF END IF IF CoolMessage THEN IF CoolMessage = 1 THEN WhichCoolMessage% = INT(RND * 15) SELECT CASE WhichCoolMessage% CASE 0 CoolMessageText = "It doesn't matter..." CoolMessageText2 = "" CoolMessageText3 = "" CASE 1 CoolMessageText = "Hey, stop pushing [F10]!" CoolMessageText2 = "It hurts!" CoolMessageText3 = "" CASE 2 CoolMessageText = "Tell DRR that you saw this message, and" CoolMessageText2 = "you could win $500! (yeah right)" CoolMessageText3 = "" CASE 3 CoolMessageText = "Yeah, baby, yeah!" CoolMessageText2 = "" CoolMessageText3 = "" CASE 4 CoolMessageText = "For the last time, I know that DRR-NES" CoolMessageText2 = "is super slow!" CoolMessageText3 = "" CASE 5 CoolMessageText = "I'll rewrite the 6502 CPU core" CoolMessageText2 = "in ASM someday..." CoolMessageText3 = "" CASE 6 CoolMessageText = "Hi Mom and Dad and Eric and John and" CoolMessageText2 = "everybody else!" CoolMessageText3 = "" CASE 7 CoolMessageText = "Come on, go to my web site at:" CoolMessageText2 = "http://drr.dragonfire.net" CoolMessageText3 = "" CASE 8 CoolMessageText = "My brother Michael is the most" CoolMessageText2 = "annoying person to ever exist!" CoolMessageText3 = "" CASE 9 CoolMessageText = "The N64 rules! The PSX sucks!" CoolMessageText2 = "" CoolMessageText3 = "" CASE 10 CoolMessageText = CHR$(14) + " Da da da... " + CHR$(14) CoolMessageText2 = "" CoolMessageText3 = "" CASE 11 CoolMessageText = "Macintoshes and Linux and Amiga" CoolMessageText2 = "and any other lame OS that" CoolMessageText3 = "nobody uses all SUCK!" CASE 12 CoolMessageText = "Oh my god, they killed Kenny!" CoolMessageText2 = "You bastards!" CoolMessageText3 = "BEEF-CAKE!" CASE 13 CoolMessageText = "You must be really bored..." CoolMessageText2 = "" CoolMessageText3 = "" CASE 14 CoolMessageText = "Kick Bill Clinton's sorry ass out of" CoolMessageText2 = "office!" CoolMessageText3 = "" CASE 15 CoolMessageText = "Hi." CoolMessageText2 = "" CoolMessageText3 = "" END SELECT END IF DrawText 1, CoolMessageText, 1, 0, 70 DrawText 1, CoolMessageText, 0, 2, 69 DrawText 1, CoolMessageText2, 1, 32, 70 DrawText 1, CoolMessageText2, 0, 34, 69 DrawText 1, CoolMessageText3, 1, 64, 70 DrawText 1, CoolMessageText3, 0, 66, 69 CoolMessage = CoolMessage + 1 IF CoolMessage = 10 THEN CoolMessage = 0 END IF IF VideoPage THEN OUT &H3D4, 12: OUT &H3D5, &H0 ELSE OUT &H3D4, 12: OUT &H3D5, &H4F VideoPage = NOT VideoPage END IF END SUB SUB DrawObject (WhichObject%, x1%, y1%, x2%, y2%) SELECT CASE WhichObject% CASE 0 LINE (x1%, y1%)-(x2%, y2%), 13, BF LINE (x1%, y1%)-(x2% - 1, y1%), 15 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 15 LINE (x1% + 1, y1% + 1)-(x2% - 2, y1% + 1), 14 LINE (x1% + 1, y1% + 2)-(x1% + 1, y2% - 2), 14 LINE (x2%, y1%)-(x2%, y2%), 0 LINE (x1%, y2%)-(x2% - 1, y2%), 0 LINE (x2% - 1, y1% + 1)-(x2% - 1, y2% - 1), 12 LINE (x1% + 1, y2% - 1)-(x2% - 2, y2% - 1), 12 LINE (x1% + 4, y1% + 22)-(x2% - 4, y1% + 22), 12 LINE (x1% + 4, y1% + 23)-(x1% + 4, y2% - 22), 12 LINE (x1% + 5, y1% + 23)-(x2% - 5, y1% + 23), 0 LINE (x1% + 5, y1% + 24)-(x1% + 5, y2% - 23), 0 LINE (x2% - 4, y1% + 23)-(x2% - 4, y2% - 22), 14 LINE (x1% + 5, y2% - 22)-(x2% - 5, y2% - 22), 14 LINE (x2% - 5, y1% + 24)-(x2% - 5, y2% - 23), 15 LINE (x1% + 6, y2% - 23)-(x2% - 6, y2% - 23), 15 CASE 10 LINE (x1%, y1%)-(x2% - 1, y1%), 15 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 15 LINE (x2%, y1%)-(x2%, y2%), 0 LINE (x1%, y2%)-(x2% - 1, y2%), 0 CASE 11 LINE (x1%, y1%)-(x2% - 1, y1%), 0 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 0 LINE (x2%, y1%)-(x2%, y2%), 15 LINE (x1%, y2%)-(x2% - 1, y2%), 15 CASE 20 LINE (x1%, y1%)-(x2% - 1, y1%), 15 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 15 LINE (x1% + 1, y1% + 1)-(x2% - 2, y1% + 1), 14 LINE (x1% + 1, y1% + 2)-(x1% + 1, y2% - 2), 14 LINE (x2%, y1%)-(x2%, y2%), 0 LINE (x1%, y2%)-(x2% - 1, y2%), 0 LINE (x2% - 1, y1% + 1)-(x2% - 1, y2% - 1), 12 LINE (x1% + 1, y2% - 1)-(x2% - 2, y2% - 1), 12 CASE 21 LINE (x1%, y1%)-(x2% - 1, y1%), 0 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 0 LINE (x1% + 1, y1% + 1)-(x2% - 2, y1% + 1), 12 LINE (x1% + 1, y1% + 2)-(x1% + 1, y2% - 2), 12 LINE (x2%, y1%)-(x2%, y2%), 15 LINE (x1%, y2%)-(x2% - 1, y2%), 15 LINE (x2% - 1, y1% + 1)-(x2% - 1, y2% - 1), 14 LINE (x1% + 1, y2% - 1)-(x2% - 2, y2% - 1), 14 CASE 40 LINE (x1%, y1%)-(x2% - 1, y1%), 15 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 15 LINE (x1% + 1, y1% + 1)-(x2% - 2, y1% + 1), 15 LINE (x1% + 1, y1% + 2)-(x1% + 1, y2% - 2), 15 LINE (x1% + 2, y1% + 2)-(x2% - 3, y1% + 2), 14 LINE (x1% + 2, y1% + 3)-(x1% + 2, y2% - 3), 14 LINE (x1% + 3, y1% + 3)-(x2% - 4, y1% + 3), 14 LINE (x1% + 3, y1% + 4)-(x1% + 3, y2% - 4), 14 LINE (x2%, y1%)-(x2%, y2%), 0 LINE (x1%, y2%)-(x2% - 1, y2%), 0 LINE (x2% - 1, y1% + 1)-(x2% - 1, y2% - 1), 0 LINE (x1% + 1, y2% - 1)-(x2% - 2, y2% - 1), 0 LINE (x2% - 2, y1% + 2)-(x2% - 2, y2% - 2), 12 LINE (x1% + 2, y2% - 2)-(x2% - 3, y2% - 2), 12 LINE (x2% - 3, y1% + 3)-(x2% - 3, y2% - 3), 12 LINE (x1% + 3, y2% - 3)-(x2% - 4, y2% - 3), 12 CASE 41 LINE (x1%, y1%)-(x2% - 1, y1%), 0 LINE (x1%, y1% + 1)-(x1%, y2% - 1), 0 LINE (x1% + 1, y1% + 1)-(x2% - 2, y1% + 1), 0 LINE (x1% + 1, y1% + 2)-(x1% + 1, y2% - 2), 0 LINE (x1% + 2, y1% + 2)-(x2% - 3, y1% + 2), 12 LINE (x1% + 2, y1% + 3)-(x1% + 2, y2% - 3), 12 LINE (x1% + 3, y1% + 3)-(x2% - 4, y1% + 3), 12 LINE (x1% + 3, y1% + 4)-(x1% + 3, y2% - 4), 12 LINE (x2%, y1%)-(x2%, y2%), 15 LINE (x1%, y2%)-(x2% - 1, y2%), 15 LINE (x2% - 1, y1% + 1)-(x2% - 1, y2% - 1), 15 LINE (x1% + 1, y2% - 1)-(x2% - 2, y2% - 1), 15 LINE (x2% - 2, y1% + 2)-(x2% - 2, y2% - 2), 14 LINE (x1% + 2, y2% - 2)-(x2% - 3, y2% - 2), 14 LINE (x2% - 3, y1% + 3)-(x2% - 3, y2% - 3), 14 LINE (x1% + 3, y2% - 3)-(x2% - 4, y2% - 3), 14 END SELECT END SUB SUB DrawScrolling (NameTableAddress%, Hscroll%, Vscroll%) IF MemoryRegisters(0) AND 16 THEN PatternTableAddress% = 4096 ELSE PatternTableAddress% = 0 IF (MemoryRegisters(1) AND 2) = 0 THEN BGcutoff% = 40 ELSE BGcutoff% = 32 NameTableAddress% = NameTableAddress% + Mirroring(NameTableAddress% \ 1024) IF DebuggerFlag = 0 THEN AttributeTableAddress% = NameTableAddress% + 960 FOR AttributeY% = 0 TO 14 STEP 2 FOR AttributeX% = 0 TO 14 STEP 2 AttributeColor% = NameTables(AttributeTableAddress%) AttributeTableAddress% = AttributeTableAddress% + 1 AttributeTable(AttributeX%, AttributeY%) = (AttributeColor% AND 3) * 4 AttributeTable(AttributeX% + 1, AttributeY%) = AttributeColor% AND 12 AttributeTable(AttributeX%, AttributeY% + 1) = (AttributeColor% AND 48) \ 4 AttributeTable(AttributeX% + 1, AttributeY% + 1) = (AttributeColor% AND 192) \ 16 NEXT AttributeX% NEXT AttributeY% FOR TileY% = 0 TO 232 STEP 8 IF TileY% + Vscroll% >= -7 AND TileY% + Vscroll% <= 239 THEN FOR TileX% = 0 TO 248 STEP 8 IF TileX% + Hscroll% >= -8 AND TileX% + Hscroll% <= 255 THEN PixelColorHigh% = AttributeTable(TileX% \ 16, TileY% \ 16) TileAddress% = PatternTableAddress% + NameTables(NameTableAddress% + TileY% * 4 + TileX% \ 8) * 16 FOR TileByte% = 0 TO 15: Tile(TileByte%) = PatternTables(TileAddress% + TileByte%): NEXT FOR PixelX% = 0 TO 7 CurrentPixelX% = (TileX% - PixelX% + Hscroll% + 39) IF CurrentPixelX% >= BGcutoff% AND CurrentPixelX% < 288 THEN OUT &H3C4, 2: OUT &H3C5, PowerOfTwo(CurrentPixelX% AND 3) TwoExpPixelX% = PowerOfTwo(PixelX%) FOR PixelY% = 0 TO 7 CurrentPixelY% = TileY% + PixelY% + Vscroll% IF CurrentPixelY% >= 8 AND CurrentPixelY% < 232 THEN IF Tile(PixelY%) AND TwoExpPixelX% THEN PixelColor% = 1 ELSE PixelColor% = 0 IF Tile(PixelY% + 8) AND TwoExpPixelX% THEN PixelColor% = PixelColor% + 2 POKE CurrentPixelX% \ 4 + CurrentPixelY% * 80, BackgroundPalette(PixelColorHigh% + PixelColor%) + 1 END IF NEXT PixelY% END IF NEXT PixelX% END IF NEXT TileX% END IF NEXT TileY% END IF END SUB SUB DrawText (TextFont%, TextToType$, TextX%, TextY%, TextColor%) SELECT CASE VideoMode CASE 12 IF TextFont% = 0 THEN DEF SEG = VARSEG(Font0): FontOffset% = VARPTR(Font0) ELSE DEF SEG = VARSEG(Font1): FontOffset% = VARPTR(Font1) FOR TextCharacter% = 1 TO LEN(TextToType$) X% = (TextCharacter% - 1) * 8 + TextX% ASCIIcode% = ASC(MID$(TextToType$, TextCharacter%, 1)) FOR Y% = TextY% TO TextY% + 15 TextPixels% = PEEK(FontOffset% + ASCIIcode% * 16& + Y% - TextY%) IF TextPixels% AND 128 THEN PSET (X%, Y%), TextColor% IF TextPixels% AND 64 THEN PSET (X% + 1, Y%), TextColor% IF TextPixels% AND 32 THEN PSET (X% + 2, Y%), TextColor% IF TextPixels% AND 16 THEN PSET (X% + 3, Y%), TextColor% IF TextPixels% AND 8 THEN PSET (X% + 4, Y%), TextColor% IF TextPixels% AND 4 THEN PSET (X% + 5, Y%), TextColor% IF TextPixels% AND 2 THEN PSET (X% + 6, Y%), TextColor% IF TextPixels% AND 1 THEN PSET (X% + 7, Y%), TextColor% NEXT Y% NEXT TextCharacter% CASE 14 TextX% = TextX% \ 2: TextY% = TextY% \ 2 IF TextFont% = 0 THEN DEF SEG = VARSEG(Font0): FontOffset% = VARPTR(Font0) ELSE DEF SEG = VARSEG(Font1): FontOffset% = VARPTR(Font1) FOR TextCharacter% = 1 TO LEN(TextToType$) CharacterX% = ((TextCharacter% - 1) * 8 + TextX%) ASCIIcode% = ASC(MID$(TextToType$, TextCharacter%, 1)) FOR Y% = TextY% * 80 TO (TextY% + 15) * 80 STEP 80 IF TextFont% = 0 THEN DEF SEG = VARSEG(Font0) ELSE DEF SEG = VARSEG(Font1) TextPixels% = PEEK(FontOffset% + ASCIIcode% * 16& + (Y% \ 80) - TextY%) IF VideoPage THEN DEF SEG = &HA000 ELSE DEF SEG = &HA4F0 FOR X% = CharacterX% TO CharacterX% + 7 OUT &H3C4, 2: OUT &H3C5, PowerOfTwo(X% AND 3) IF TextPixels% AND PowerOfTwo(7 - (X% - CharacterX%)) THEN POKE X% \ 4 + Y%, TextColor% NEXT X% NEXT Y% NEXT TextCharacter% END SELECT END SUB SUB InGameControls 'DO WHILE INP(&H64) AND 1 ' IF ExtendedKeyPressed = 1 THEN ' ExtendedKeyPressed = 0 ' SELECT CASE INP(&H60) ' CASE 72: Controller(1) = Controller(1) OR 16 ' CASE 74: IF Frameskip > 0 THEN Frameskip = Frameskip - 1 ' CASE 75: Controller(1) = Controller(1) OR 64 ' CASE 77: Controller(1) = Controller(1) OR 128 ' CASE 78: Frameskip = Frameskip + 1 ' CASE 80: Controller(1) = Controller(1) OR 32 ' CASE 200: Controller(1) = Controller(1) AND 239 ' CASE 203: Controller(1) = Controller(1) AND 191 ' CASE 205: Controller(1) = Controller(1) AND 127 ' CASE 208: Controller(1) = Controller(1) AND 223 ' END SELECT ' ELSE ' SELECT CASE INP(&H60) ' CASE 1: ByeBye ' CASE 2: Controller(2) = Controller(2) OR 4 ' CASE 3: Controller(2) = Controller(2) OR 8 ' CASE 4: Controller(2) = Controller(2) OR 2 ' CASE 5: Controller(2) = Controller(2) OR 1 ' CASE 17: Controller(2) = Controller(2) OR 16 ' CASE 30: Controller(2) = Controller(2) OR 64 ' CASE 31: Controller(2) = Controller(2) OR 32 ' CASE 32: Controller(2) = Controller(2) OR 128 ' CASE 47: Controller(1) = Controller(1) OR 4 ' CASE 48: Controller(1) = Controller(1) OR 8 ' CASE 49: Controller(1) = Controller(1) OR 2 ' CASE 50: Controller(1) = Controller(1) OR 1 ' CASE 59: DebuggerFlag = -1: Debugger: EXIT SUB ' CASE 60: FPScounter = NOT FPScounter ' CASE 70: ByeBye ' CASE 88: IF CoolMessage = 0 THEN CoolMessage = 1 ' CASE 130: Controller(2) = Controller(2) AND 251 ' CASE 131: Controller(2) = Controller(2) AND 247 ' CASE 132: Controller(2) = Controller(2) AND 253 ' CASE 133: Controller(2) = Controller(2) AND 254 ' CASE 145: Controller(2) = Controller(2) AND 239 ' CASE 158: Controller(2) = Controller(2) AND 191 ' CASE 159: Controller(2) = Controller(2) AND 127 ' CASE 160: Controller(2) = Controller(2) AND 223 ' CASE 175: Controller(1) = Controller(1) AND 251 ' CASE 176: Controller(1) = Controller(1) AND 247 ' CASE 177: Controller(1) = Controller(1) AND 253 ' CASE 178: Controller(1) = Controller(1) AND 254 ' CASE 224: ExtendedKeyPressed = 1 ' CASE 225: ByeBye ' END SELECT ' END IF 'LOOP 'EXIT SUB 'old controls Controller(1) = 0: Controller(2) = 0 SELECT CASE UCASE$(INKEY$) CASE "~": DisplayVersion = 1 CASE CHR$(0) + "H": Controller(1) = Controller(1) OR 16 CASE CHR$(0) + "K": Controller(1) = Controller(1) OR 64 CASE CHR$(0) + "M": Controller(1) = Controller(1) OR 128 CASE CHR$(0) + "P": Controller(1) = Controller(1) OR 32 CASE "V": Controller(1) = Controller(1) OR 4 CASE "B": Controller(1) = Controller(1) OR 8 CASE "N": Controller(1) = Controller(1) OR 2 CASE "M": Controller(1) = Controller(1) OR 1 CASE "W": Controller(2) = Controller(2) OR 16 CASE "A": Controller(2) = Controller(2) OR 64 CASE "S": Controller(2) = Controller(2) OR 128 CASE "D": Controller(2) = Controller(2) OR 32 CASE "1": Controller(2) = Controller(2) OR 4 CASE "2": Controller(2) = Controller(2) OR 8 CASE "3": Controller(2) = Controller(2) OR 2 CASE "4": Controller(2) = Controller(2) OR 1 CASE "+": Frameskip = Frameskip + 1 CASE "-": IF Frameskip > 0 THEN Frameskip = Frameskip - 1 CASE CHR$(27): ByeBye CASE CHR$(0) + CHR$(&H3B): DebuggerFlag = -1: Debugger: EXIT SUB CASE CHR$(0) + CHR$(&H3C): FPScounter = NOT FPScounter CASE CHR$(0) + CHR$(&H44): IF CoolMessage = 0 THEN CoolMessage = 1 END SELECT DEF SEG = 0: POKE &H41A, PEEK(&H41C) MouseDriver 3, MouseButtons, MouseX, MouseY 'IF MouseButtons THEN ByeBye END SUB SUB InitializeDRRNES OPEN "C:\DRR-NES.DAT" FOR RANDOM AS #1 IF LOF(1) = 0 THEN CLS : COLOR 5: PRINT "DRR"; : COLOR 3: PRINT "NES": COLOR 14 PRINT "Copyright (c) 1998, 1999 DRR -- All rights reserved.": PRINT COLOR 1: PRINT "**** First time setup ****" COLOR 15: PRINT : INPUT "Type the drive/directory path to this program or type EXIT to exit: ", FileName$ FileName$ = LTRIM$(RTRIM$(UCASE$(FileName$))) IF RIGHT$(FileName$, 1) = "\" THEN FileName$ = LEFT$(FileName$, LEN(FileName$) - 1) IF FileName$ = "EXIT" THEN SCREEN 0: WIDTH 80, 25: SYSTEM Identifier$ = "DRR-NES Data File" PUT #1, 1, Identifier$: PUT #1, 2, FileName$ END IF DO UhOh% = 0 GET #1, 2, Path$ CHDRIVE LEFT$(Path$, 1) CHDIR Path$ OPEN "FONT0000.DSF" FOR BINARY AS #2 IF LOF(2) = 0 THEN CLOSE #2: KILL "FONT0000.DSF": UhOh% = 1: ERROR 255 IF UhOh% = 0 THEN OPEN "FONT0001.DSF" FOR BINARY AS #3 IF LOF(3) = 0 THEN CLOSE #3: KILL "FONT0001.DSF": UhOh% = 1: ERROR 255 END IF LOOP WHILE UhOh% SEEK #2, 51 DEF SEG = VARSEG(Font0): FontOffset% = VARPTR(Font0) FOR ASCIIcode% = 0 TO 255 SixteenBytes$ = INPUT$(16, #2) FOR FontByte% = 0 TO 15 POKE FontOffset% + ASCIIcode% * 16& + FontByte%, ASC(MID$(SixteenBytes$, FontByte% + 1, 1)) NEXT FontByte% NEXT ASCIIcode% SEEK #3, 51 DEF SEG = VARSEG(Font1): FontOffset% = VARPTR(Font1) FOR ASCIIcode% = 0 TO 255 SixteenBytes$ = INPUT$(16, #3) FOR FontByte% = 0 TO 15 POKE FontOffset% + ASCIIcode% * 16& + FontByte%, ASC(MID$(SixteenBytes$, FontByte% + 1, 1)) NEXT FontByte% NEXT ASCIIcode% CLOSE #1: CLOSE #2: CLOSE #3 END SUB SUB InitializeMouse DEF SEG = 0 MouseSegment& = 256& * PEEK(207) + PEEK(206) MouseOffset& = 256& * PEEK(205) + PEEK(204) DEF SEG = MouseSegment& IF (MouseSegment& = 0 AND MouseOffset& = 0) OR PEEK(MouseOffset&) = 207 THEN NoMouse = 1 MouseDriver 7, 0, 0, 629: MouseDriver 8, 0, 0, 461 RESTORE MousePicture FOR Y% = 0 TO 18 FOR X% = 0 TO 10 READ Mouse(X%, Y%) IF Mouse(X%, Y%) = -1 THEN Mouse(X%, Y%) = 0 PSET (X%, Y%), Mouse(X%, Y%) NEXT X% NEXT Y% GET (0, 0)-(10, 18), Mouse RESTORE MousePicture FOR Y% = 0 TO 18 FOR X% = 0 TO 10 READ MouseMask(X%, Y%) IF MouseMask(X%, Y%) = -1 THEN MouseMask(X%, Y%) = 15 ELSE MouseMask(X%, Y%) = 0 PSET (X%, Y%), MouseMask(X%, Y%) NEXT X% NEXT Y% GET (0, 0)-(10, 18), MouseMask CLS END SUB SUB InitializeScreen (WhichMode%) SELECT CASE WhichMode% CASE 12 SCREEN 12: CLS RESTORE PaletteColors FOR PaletteColor% = 0 TO 15 READ ColorValue&: OUT 968, PaletteColor% OUT 969, ColorValue& AND 63 OUT 969, (ColorValue& \ 256) AND 63 OUT 969, ColorValue& \ 65536 NEXT PaletteColor% COLOR 15 CASE 14 SCREEN 13 OUT &H3C4, &H4: OUT &H3C5, &H6 OUT &H3C4, &H2: OUT &H3C5, &HF: CLS OUT &H3C4, 0: OUT &H3C5, &H1 OUT &H3C2, &HE3 OUT &H3C4, 0: OUT &H3C5, &H3 OUT &H3D4, &H11: OUT &H3D5, INP(&H3D5) AND &H7F OUT &H3D4, &H6: OUT &H3D5, &HD OUT &H3D4, &H7: OUT &H3D5, &H3E OUT &H3D4, &H9: OUT &H3D5, &H41 OUT &H3D4, &H10: OUT &H3D5, &HEA OUT &H3D4, &H11: OUT &H3D5, &HAC OUT &H3D4, &H12: OUT &H3D5, &HDF OUT &H3D4, &H14: OUT &H3D5, 0 OUT &H3D4, &H15: OUT &H3D5, &HE7 OUT &H3D4, &H16: OUT &H3D5, &H6 OUT &H3D4, &H17: OUT &H3D5, &HE3 OUT &H3D4, 12: OUT &H3D5, &H0 IF VideoPage THEN OUT &H3D4, 12: OUT &H3D5, &H0 ELSE OUT &H3D4, 12: OUT &H3D5, &H4F RESTORE NESpalette FOR NESpaletteColor% = 1 TO 70 READ Red%, Green%, Blue%: OUT 968, NESpaletteColor% OUT 969, Red% \ 4: OUT 969, Green% \ 4: OUT 969, Blue% \ 4 NEXT NESpaletteColor% END SELECT VideoMode = WhichMode% END SUB SUB InitializeXMS CLS DIM XMSRegisters AS x86Registers XMSRegisters.AX = &H4300 InterruptX &H2F, XMSRegisters, XMSRegisters IF XMSRegisters.AX AND 128 THEN PRINT "XMS available! :)" ELSE PRINT "XMS unavailable... :(": EXIT SUB XMSRegisters.AX = &H4310 InterruptX &H2F, XMSRegisters, XMSRegisters PRINT "XMS address: "; RIGHT$("000" + HEX$(XMSRegisters.ES), 4); ":"; RIGHT$("000" + HEX$(XMSRegisters.BX), 4) ' Unfortunately, QBasic allows no way of directly calling the XMS APIs ' _and_ reading/writing the registers at the same time. ' The only way I see of accessing the extended memory is to write a short ' ASM program that does the dirty work for me. :S This will be very tough ' because I have very little experience in writing ASM. :( END SUB SUB LoadCHRROM (SourceBank%, DestinationBank%, LoadSize%) SEEK #1, PRGROMbanks * 16384& + Trainer + 17 + SourceBank% * LoadSize% CHRROM$ = INPUT$(LoadSize%, #1) PatternTableAddress% = DestinationBank% * LoadSize% FOR LoadByte% = 0 TO LoadSize% - 1 PatternTables(PatternTableAddress% + LoadByte%) = ASC(MID$(CHRROM$, LoadByte% + 1, 1)) NEXT LoadByte% END SUB SUB LoadPRGROM (SourceBank%, DestinationBank%) ROMSegment% = VARSEG(ROM(0)): ROMOffset& = VARPTR(ROM(0)) + DestinationBank% * 16384& + 4096 SEEK #1, SourceBank% * 16384& + Trainer + 17: PRGROM$ = INPUT$(16384, #1) DEF SEG = ROMSegment% FOR LoadByte% = 0 TO 16383 Value% = ASC(MID$(PRGROM$, LoadByte% + 1, 1)) POKE ROMOffset& + LoadByte%, Value% NEXT LoadByte% END SUB SUB LoadROM (ROMFileName$) OPEN ROMFileName$ FOR BINARY AS #1 IF LOF(1) = 0 THEN DrawText 0, "Invalid filename, terminating program...", 80, 254, 0 CLOSE #1: KILL ROMFileName$: SLEEP: SCREEN 0: WIDTH 80, 25: SYSTEM END IF IF INPUT$(4, #1) <> "NES" + CHR$(26) THEN DrawText 0, "Invalid ROM header, terminating program...", 80, 254, 0 CLOSE #1: KILL ROMFileName$: SLEEP: SCREEN 0: WIDTH 80, 25: SYSTEM END IF DrawText 1, "Loading ROM...", 80, 254, 1 NESFileSize = LOF(1) PRGROMbanks = ASC(INPUT$(1, #1)) CHRROMbanks = ASC(INPUT$(1, #1)) Flags1 = ASC(INPUT$(1, #1)) Flags2 = ASC(INPUT$(1, #1)) OriginalMirroring = Flags1 AND 1 IF Flags1 AND 4 THEN Trainer = 512 IF Flags1 AND 8 THEN OriginalMirroring = -1 IF OriginalMirroring = 1 THEN Mirroring(0) = 0: Mirroring(1) = 0 Mirroring(2) = -2048: Mirroring(3) = -2048 ELSEIF OriginalMirroring = 0 THEN Mirroring(0) = 0: Mirroring(1) = -1024 Mirroring(2) = 0: Mirroring(3) = -1024 ELSE Mirroring(0) = 0: Mirroring(1) = -1024 Mirroring(2) = -2048: Mirroring(3) = -3072 END IF Mapper = Flags1 \ 16 '+ (Flags2% AND 240) SEEK #1, 17 IF Trainer THEN Buffer$ = INPUT$(512, #1) FOR LoadByte% = 0 TO 511 Value% = ASC(MID$(Buffer$, LoadByte% + 1, 1)) DEF SEG = VARSEG(ROM(0)) POKE VARPTR(ROM(0)) + LoadByte%, Value% NEXT LoadByte% END IF SELECT CASE Mapper CASE 1, 2 CurrentPRGROMbank(0) = 0: CurrentPRGROMbank(1) = PRGROMbanks - 1 LoadPRGROM 0, 0: LoadPRGROM PRGROMbanks - 1, 1 PRGROMswitching = 1 IF CHRROMbanks THEN LoadCHRROM 0, 0, 8192 CASE ELSE '0, 3, 7, 8, 11 IF PRGROMbanks = 1 THEN LoadPRGROM 0, 1 ELSE LoadPRGROM 0, 0: LoadPRGROM 1, 1 IF CHRROMbanks THEN LoadCHRROM 0, 0, 8192 END SELECT END SUB FUNCTION MemoryRead% (Address&) SELECT CASE Address& CASE -2 MemoryRead% = RegisterA CASE -1 MemoryRead% = Argument1 CASE &H0 TO &H1FFF MemoryRead% = RAM(Address&) CASE &H2000, &H2001 MemoryRead% = MemoryRegisters(Address& AND 7) CASE &H2002 MemoryRead% = MemoryRegisters(2) IF Vblank = 0 AND ((MemoryRegisters(0) AND 128) = 0) THEN MemoryRegisters(0) = MemoryRegisters(0) AND 252 MemoryRegisters(2) = MemoryRegisters(2) AND 127 MemoryRegisters(5) = 0 CASE &H2004 'IF Vblank THEN MemoryRead% = SpriteRAM(MemoryRegisters(3)) MemoryRegisters(3) = MemoryRegisters(3) + 1 AND 255 'END IF CASE &H2007 'IF Vblank THEN IF MemoryRegisters(6) AND &H4000 THEN MemoryRegisters(6) = MemoryRegisters(6) - &H4000 SELECT CASE MemoryRegisters(6) CASE &H0 TO &H1FFF MemoryRead% = PatternTables(MemoryRegisters(6)) CASE &H2000 TO &H2FFF PPUaddress& = MemoryRegisters(6) - &H2000 MemoryRead% = NameTables(PPUaddress& + Mirroring(PPUaddress& \ 1024)) CASE &H3F00 TO &H3F0F MemoryRead% = BackgroundPalette(MemoryRegisters(6) AND 15) CASE &H3F10 TO &H3F1F MemoryRead% = SpritePalette(MemoryRegisters(6) AND 15) 'CASE &H3F20 TO &H3FFF ' MemoryRegisters(6) = MemoryRegisters(6) AND &H3F1F ' MemoryRead% = MemoryRead%(Address&) END SELECT IF MemoryRegisters(7) THEN IF MemoryRegisters(0) AND 4 THEN MemoryRegisters(6) = MemoryRegisters(6) + 32 ELSE MemoryRegisters(6) = MemoryRegisters(6) + 1 ELSE MemoryRegisters(7) = 1 END IF 'END IF CASE &H2008 TO &H3FFF MemoryRead% = MemoryRead%(Address& AND &H2007) CASE &H4016 SELECT CASE MemoryRegisters(30) CASE 0 TO 7: IF Controller(1) AND PowerOfTwo(MemoryRegisters(30)) THEN MemoryRead% = &H41 ELSE MemoryRead% = 0 CASE -1, 8 TO 17, 20 TO 22: MemoryRead% = 0 CASE 18: MemoryRead% = 0 CASE 19: MemoryRead% = 1 CASE 23: MemoryRead% = 0: MemoryRegisters(30) = -2 END SELECT MemoryRegisters(30) = MemoryRegisters(30) + 1 CASE &H4017 SELECT CASE MemoryRegisters(31) CASE 0 TO 7: IF Controller(2) AND PowerOfTwo(MemoryRegisters(31)) THEN MemoryRead% = &H41 ELSE MemoryRead% = 0 CASE -1, 8 TO 17, 20 TO 22: MemoryRead% = 0 CASE 18: MemoryRead% = 1 CASE 19: MemoryRead% = 0 CASE 23: MemoryRead% = 0: MemoryRegisters(31) = -2 END SELECT CASE 28672 TO 29183, 32768 TO 65535 DEF SEG = VARSEG(ROM(0)) MemoryRead% = PEEK(VARPTR(ROM(0)) + Address& - 28672) CASE IS > 65535 Address& = Address& AND 65535 MemoryRead% = MemoryRead%(Address&) END SELECT END FUNCTION SUB MemoryWrite (Address&, Value%) SELECT CASE Address& CASE -2 RegisterA = Value% CASE -1 ERROR 250 CASE &H0 TO &H1FFF RAM(Address&) = Value% CASE &H2000, &H2001, &H2003 MemoryRegisters(Address& AND 7) = Value% CASE &H2004 'IF Vblank THEN SpriteRAM(MemoryRegisters(3)) = Value% MemoryRegisters(3) = MemoryRegisters(3) + 1 AND 255 'END IF CASE &H2005 'IF Vblank THEN IF MemoryRegisters(5) THEN IF Value% < 240 THEN VerticalScroll = Value% ELSE HorizontalScroll = Value% END IF MemoryRegisters(5) = NOT MemoryRegisters(5) 'END IF CASE &H2006 'IF Vblank THEN MemoryRegisters(6) = (MemoryRegisters(6) AND 255) * 256 + Value% MemoryRegisters(7) = 0 'END IF CASE &H2007 'IF Vblank THEN IF MemoryRegisters(6) AND &H4000 THEN MemoryRegisters(6) = MemoryRegisters(6) - &H4000 SELECT CASE MemoryRegisters(6) CASE &H0 TO &H1FFF PatternTables(MemoryRegisters(6)) = Value% CASE &H2000 TO &H2FFF PPUaddress& = MemoryRegisters(6) - &H2000 NameTables(PPUaddress& + Mirroring(PPUaddress& \ 1024)) = Value% CASE &H3F00 TO &H3F1F IF Value% < &H40 THEN IF (MemoryRegisters(6) AND 3) = 0 THEN BackgroundPalette(0) = Value% BackgroundPalette(4) = Value% BackgroundPalette(8) = Value% BackgroundPalette(12) = Value% SpritePalette(0) = Value% SpritePalette(4) = Value% SpritePalette(8) = Value% SpritePalette(12) = Value% ELSE IF MemoryRegisters(6) AND &H10 THEN SpritePalette(MemoryRegisters(6) AND 15) = Value% ELSE BackgroundPalette(MemoryRegisters(6) AND 15) = Value% END IF END IF END IF 'CASE &H3F20 TO &H3FFF END SELECT IF MemoryRegisters(0) AND 4 THEN MemoryRegisters(6) = MemoryRegisters(6) + 32 ELSE MemoryRegisters(6) = MemoryRegisters(6) + 1 'END IF CASE &H2008 TO &H3FFF Address& = Address& AND &H2007 MemoryWrite Address&, Value% CASE &H4014 'IF Vblank THEN TransferAddress& = Value% * 256& FOR TransferByte% = 0 TO 255 Value% = MemoryRead%(TransferAddress& + TransferByte%) SpriteRAM(TransferByte%) = Value% NEXT TransferByte% 'END IF CASE &H4016 IF Value% AND 1 THEN MemoryRegisters(30) = -1 ELSEIF MemoryRegisters(30) = -1 THEN MemoryRegisters(30) = 0 END IF CASE &H4017 IF Value% AND 1 THEN MemoryRegisters(30) = -1 ELSEIF MemoryRegisters(30) = -1 THEN MemoryRegisters(30) = 0 END IF CASE IS > 65535 Address& = Address& AND 65535 MemoryWrite Address&, Value% CASE ELSE SELECT CASE Mapper CASE 1 Address& = Address& \ 8192 - 4 IF WhichMapperRegister <> Address& THEN WhichMapperRegister = Address& MapperRegisterBit = 0: MapperRegister = 0 END IF IF Value% AND 1 THEN MapperRegister = MapperRegister OR PowerOfTwo(MapperRegisterBit) MapperRegisterBit = MapperRegisterBit + 1 IF MapperRegisterBit = 5 THEN IF Address& = 0 THEN OldPRGROMbank(0) = CurrentPRGROMbank(0) OldPRGROMbank(1) = CurrentPRGROMbank(1) IF MapperRegister AND 2 THEN IF MapperRegister AND 1 THEN Mirroring(0) = 0: Mirroring(1) = 0 Mirroring(2) = -2048: Mirroring(3) = -2048 ELSE Mirroring(0) = 0: Mirroring(1) = -1024 Mirroring(2) = 0: Mirroring(3) = -1024 END IF ELSE Mirroring(0) = 0: Mirroring(1) = -1024 Mirroring(2) = -2048: Mirroring(3) = -3072 END IF IF MapperRegister AND 8 THEN IF MapperRegister AND 4 THEN IF PRGROMswitching = 1 THEN CurrentPRGROMbank(0) = CurrentPRGROMbank(1) CurrentPRGROMbank(1) = PRGROMbanks - 1 ELSE IF PRGROMswitching = 0 OR PRGROMswitching = 2 THEN CurrentPRGROMbank(1) = CurrentPRGROMbank(0) CurrentPRGROMbank(0) = 0 END IF IF OldPRGROMbank(0) <> CurrentPRGROMbank(0) THEN LoadPRGROM CurrentPRGROMbank(0), 0 IF OldPRGROMbank(1) <> CurrentPRGROMbank(1) THEN LoadPRGROM CurrentPRGROMbank(1), 1 IF MapperRegister AND 4 THEN PRGROMswitching = 1 ELSE PRGROMswitching = 0 ELSE IF PRGROMswitching = 0 THEN CurrentPRGROMbank(0) = CurrentPRGROMbank(1) CurrentPRGROMbank(1) = -1 IF OldPRGROMbank(0) <> CurrentPRGROMbank(0) THEN LoadPRGROM CurrentPRGROMbank(0) AND 14, 0 IF OldPRGROMbank(1) <> CurrentPRGROMbank(1) THEN LoadPRGROM (CurrentPRGROMbank(0) AND 14) + 1, 1 PRGROMswitching = 2 END IF IF CHRROMswitching <> MapperRegister AND 16 THEN IF MapperRegister AND 16 THEN CHRROMswitching = 1 CurrentCHRROMbank(0) = CurrentCHRROMbank(0) CurrentCHRROMbank(1) = CurrentCHRROMbank(0) + 1 ELSE CHRROMswitching = 0 CurrentCHRROMbank(0) = CurrentCHRROMbank(0) END IF END IF ELSEIF Address& = 1 THEN IF CHRROMbanks <> 0 AND CurrentCHRROMbank(0) <> (MapperRegister AND 15) THEN CurrentCHRROMbank(0) = MapperRegister AND 15 IF CHRROMswitching THEN LoadCHRROM 0, CurrentCHRROMbank(0) \ 2, 4096 ELSE LoadCHRROM 0, CurrentCHRROMbank(0), 8192 END IF END IF ELSEIF Address& = 2 THEN IF CHRROMbanks <> 0 AND CurrentCHRROMbank(1) <> (MapperRegister AND 15) THEN CurrentCHRROMbank(1) = MapperRegister AND 15 IF CHRROMswitching THEN LoadCHRROM 1, CurrentCHRROMbank(1), 4096 END IF ELSEIF Address& = 3 THEN IF PRGROMswitching = 1 THEN IF CurrentPRGROMbank(0) <> MapperRegister AND 15 THEN CurrentPRGROMbank(0) = MapperRegister AND 15 LoadPRGROM CurrentPRGROMbank(0), 0 END IF ELSEIF PRGROMswitching = 0 THEN IF CurrentPRGROMbank(1) <> MapperRegister AND 15 THEN CurrentPRGROMbank(1) = MapperRegister AND 15 LoadPRGROM CurrentPRGROMbank(1), 1 END IF ELSEIF PRGROMswitching = 2 THEN IF CurrentPRGROMbank(0) <> MapperRegister AND 14 THEN CurrentPRGROMbank(0) = MapperRegister AND 14 LoadPRGROM CurrentPRGROMbank(0), 0 LoadPRGROM CurrentPRGROMbank(0) + 1, 1 END IF END IF END IF MapperRegisterBit = 0: MapperRegister = 0 END IF CASE 2 IF Address& AND 32768 THEN IF Value% <> CurrentPRGROMbank(0) THEN LoadPRGROM Value%, 0 CurrentPRGROMbank(0) = Value% END IF END IF CASE 3 IF Address& AND 32768 THEN IF Value% <> CurrentCHRROMbank(0) THEN LoadCHRROM Value%, 0, 8192 CurrentCHRROMbank(0) = Value% END IF END IF CASE 7 IF Address& AND 32768 THEN IF Value% AND 15 <> CurrentPRGROMbank(0) THEN CurrentPRGROMbank(0) = Value% AND 15 LoadPRGROM Value% * 2, 0 LoadPRGROM Value% * 2 + 1, 1 END IF IF Value% AND 16 THEN Mirroring(0) = 1024: Mirroring(1) = 0 Mirroring(2) = -1024: Mirroring(3) = -2048 ELSE Mirroring(0) = 0: Mirroring(1) = -1024 Mirroring(2) = -2048: Mirroring(3) = -3072 END IF END IF CASE 8 IF Address& AND 32768 THEN IF Value% \ 8 <> CurrentPRGROMbank(0) THEN LoadPRGROM Value%, 0 CurrentPRGROMbank(0) = Value% \ 8 END IF IF Value% AND 7 <> CurrentCHRROMbank(0) THEN LoadCHRROM Value% AND 7, 0, 8192 CurrentCHRROMbank(0) = Value% AND 7 END IF END IF CASE 11 IF Address& AND 32768 THEN IF Value% AND 15 <> CurrentPRGROMbank(0) THEN CurrentPRGROMbank(0) = Value% AND 15 LoadPRGROM Value% * 2, 0 LoadPRGROM Value% * 2 + 1, 1 END IF IF Value% \ 16 <> CurrentCHRROMbank(0) THEN CurrentCHRROMbank(0) = Value% \ 16 LoadCHRROM Value% \ 16, 0, 8192 END IF END IF END SELECT END SELECT END SUB SUB MouseDriver (AX%, BX%, CX%, DX%) IF NoMouse THEN EXIT SUB DIM MouseRegisters AS x86Registers MouseRegisters.AX = AX% MouseRegisters.BX = BX% MouseRegisters.CX = CX% MouseRegisters.DX = DX% InterruptX &H33, MouseRegisters, MouseRegisters AX% = MouseRegisters.AX BX% = MouseRegisters.BX CX% = MouseRegisters.CX DX% = MouseRegisters.DX END SUB FUNCTION Pop% RegisterS = RegisterS + 1 AND 255 Pop% = RAM(RegisterS + 256) 'DEF SEG = VARSEG(RAM) 'Pop% = PEEK(VARPTR(RAM) + RegisterS + 256) END FUNCTION SUB Push (Value%) 'DEF SEG = VARSEG(RAM) 'POKE VARPTR(RAM) + RegisterS + 256, Value% RAM(RegisterS + 256) = Value% RegisterS = RegisterS - 1 AND 255 END SUB FUNCTION TextBox$ (Column%, Row%, Length%) DrawObject 21, Column% - 2, Row% - 2, Column% + Length% * 8 + 1, Row% + 17 DrawText 1, STRING$(Length%, "°"), Column%, Row%, 10 CursorPosition% = Column% DO DO PressedButton$ = INKEY$ IF PressedButton$ <> "" THEN EXIT DO LOOP SELECT CASE ASC(PressedButton$) CASE 8 IF CursorPosition% > Column% THEN TextString$ = LEFT$(TextString$, LEN(TextString$) - 1) CursorPosition% = CursorPosition% - 8 LINE (CursorPosition%, Row%)-(CursorPosition% + 7, Row% + 15), 13, BF DrawText 1, "°", CursorPosition%, Row%, 10 END IF CASE 13: EXIT DO CASE 32 TO 126 IF CursorPosition% < Column% + Length% * 8 THEN TextString$ = TextString$ + PressedButton$ DrawText 0, PressedButton$, CursorPosition%, Row%, 0 CursorPosition% = CursorPosition% + 8 END IF END SELECT LOOP TextBox$ = TextString$ END FUNCTION SUB WaitVblank (Waits%) FOR Counter% = 1 TO Waits% WAIT &H3DA, 8, 8: WAIT &H3DA, 8 NEXT Counter% END SUB