-
Notifications
You must be signed in to change notification settings - Fork 0
hwirth/demon
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
DEMON - Debugger/Monitor for the Commodore C-64 copy(l)eft 2019 by http://harald.ist.org/ INDEX ===== 0. Index 1. Introduction 1.1 Overview 1.2 Special features of Demon 2. File list 3. Mode of operation 3.1 General description 3.2 Execution of the client program 3.3 Output screen 3.4 Context records and snapshots 3.5 Opcode matrix and alignment gap 4. Development environment, building Demon 5. Coding conventions 5.1 ZP pointers $f7..$ff 5.2 Temp byte at $02 5.3 .strbuf = tape_buffer 5.4 Default names 5.5 Debug comments, indentation 6. Help file syntax 6.1 Load address placeholder 6.2 Section names 6.3 Load other help files 6.4 Linking back to main help 6.5 End of help file 6.6 Example help file 7. Monitor commands 7.1 Not yet implemented 7.2 FC3 Monitor Commands 8. Known bugs 9. TODO 10. Reference material 1. INTRODUCTION =============== 1.1 OVERVIEW ------------ Demon is a so called "Monitor", which is a specific type of assembler used in machines with little memory. It allows for direct manipulation of RAM contents, assembly/disassembly of machine language instructions and more. Unlike modern assemblers, everything input is stored directly in memory and can be called immediately without further processing. See "List of commands" for a full list of features. Demon provides a range of experimental features, which can be toggled on or off in demon.a:!zone OPTIONS . Some of these features would not be included in a professional monitor due to memory constrainments, while they provide only some convenience or nice looks. Other features are there, because I wanted to try things out, e.g. context switching. 1.2 SPECIAL FEATURES OF DEMON ----------------------------- I love working on a real C64, but writing larger programs in FC3's monitor is very tedious, because inserting code is a lot of work. Demon tries to improve the situation by providing some functions, common monitor porgrams are lacking: 1) Inserting/deleting instructions with automatic code relocation 2) Step debugger/break points 3) Normally running machine programs can be interrupted with the RESTORE key 4) Help function providing C64 related reference material 5) Disassembly shows typical CPU cycles and affected flags for instructions 6) Direct mode: Immediate execution of instructions 7) Context switching: Zero page, stack, video RAM, etc. are separated between Demon and the client program - when the user starts a program, the run-time environment is restored from a backup ("snapshot") 2. FILE_LIST ============ demon.a Main file, includes everything else. Init and exit functions Contains a list of compile time options toolbox_conf.a Color settings and selecting of Toolbox modules to link in variables.a Global variables for all files main_menu.a The main function. Handles keyboard input and cursor movement mmfn_scroll.a Scroll through memory contents mmfn_fnkey.a User definable function keys. Also provides elfn_function_key eval_line.a Command line parsing and helpers for command functions elfn_*.a Individual command handlers opcode_matrix.a Definitions for the 6502 instruction set system_state.a Run-time context switching functions and snapshot handling self_test.a Verifies, if assembly/disassembly works correctly test_programs.a Small routines for loading to heap debug.a Helper functions for the developer of Demon *.txt Source files for help text. Needs conversion to PETSCII before they can be used. The main file is main.hlp . For conversion, "petcom" (a small C program) is used, which I found online. 3. MODE OF OPERATION ==================== 3.1 GENERAL DESCRIPTION ----------------------- After initialization, the user is greeted with a boot message and the current contents of the CPU registers. All commands are a single letter followed by parameters, usually at least one memory address. After entering or loading a program (the "client" program), one can simply run it or single-step through the individual instructions. The main loop of Demon is main_menu.a:main_menu . It handles user input and calls the command line parsing function eval_line.a:mmfn_eval_line , when Return is pressed. The line, the cursor is currently in, will be analyzed and appropriate action will be taken. When an error is found, the cursor will be placed over the first offending character and it will blink in red. When the user tries to leave the screen by pressing a cursor key while on the edge of the screen, displaying of memory contents will be continued. This is handled by the functions in mmfn_scroll.a . 3.2 EXECUTION OF THE CLIENT PROGRAM ----------------------------------- Most of the work for this is done in elfn_go.a and system_state.a . With the go-command ("G"), a program can be started. Demon uses two process contexts: "Client" and "Monitor". When a program is started, CPU state, zero page contents, stack and VIC configuration are swapped. Switching of contexts is handled in system_state.a . While context swapping isn't exactly necessary for the operation of a Monitor, it allows for a strict separation of run-time environments for the monitor and the client program, providing a separate output screen that isn't disturbed by the data displayed and commands entered while in monitor mode. The context switching routines could be used to build a real multitasking system, too. Single-stepping is realized by replacing the instruction following the current one with a BRK. A backup copy of the original instruction is kept for restoring later. When a BRK is encountered by the client program, custom_brk_handler will be called via an interrupt. It then determines the program counter of the client by looking up the return address for the interrupt on the stack. It is stored it in the client context record (client_ctxrec) and replaced with the address of elfn_go.a:elfn_go:brk_return , thus returning control to Demon, when the interrupt routine executes the RTI instruction and the client program is resumed. A normally running program can be interrupted by pressing the RESTORE key. This will trigger an NMI, which will end up in custom_nmi_handler . It then injects a new break point to the client program, thus having control returned to Demon like it was a normal break point placed while single-stepping. 3.3 OUTPUT SCREEN ----------------- Before the client program is started (or single stepped), its output screen is restored. This will flicker, when single-stepping. I could place the VRAM of both contexts in different locations and have the client "silently" write to its own screen, but CRAM (color information) is always at $D800, so no perfect solution for this is possible. You can view the output screen by pressing the "Arrow-Up" key, while in normal Monitor mode. 3.4 CONTEXT RECORDS and SNAPSHOTS --------------------------------- CPU state is kept in a context record (client_ctxrec, monitor_ctxrec) and is updated, when a switch happens. A full copy of the system state is stored in client_snapshot and monitor_snapshot , which are stowed away in the RAM beneath the KERNAL ROM at $e000..$ffff. Each snapshot contains a copy of VRAM and CRAM (screen contents and color information), the zero page and stack for the context, as well as a copy of the hardware registers of the VIC chip and the context record of the according process. Since the RAM beneath the ROMs cannot be accessed by default, the snapshot routines have to disable the ROMs, which leaves the interrupt table at $fffa..$ffff without vectors for the IRQs, so a small "catch-all" ISR is provided while the ROMs are turned off, just in case an unexpected interrupt happens. 3.5 OPCODE MATRIX and ALIGNMENT GAP ----------------------------------- The tables opcode_matrix and amode_matrix are aligned to an address (a mod 256) == 0. This way, an opcode read from memory can directly be used as index into these tables without further conversion. This may create a gap of unused bytes above opcode_matrix . The size of this gap is shown in the boot message as "G=xxx", if it is non-zero. 4. DEVELOPMENT ENVIRONMENT, BUILDING DEMON ========================================== Demon is written using the ACME assembler, source files use TAB indentation, assuming a tab width of 8 space characters. 4.1 FILE HIERARCHY ------------------ ./demon/build.sh Restart Vice, convert help, call ACME ./demon/prepare_symbols.sh Convert acme symbols (no longer needed) ./demon/_prepare_symbols.php (don't ask) ./demon/dev/*.{a,txt} Demon source ./demon/dev/README This very file ./toolbox/dev/*.a User interface library ./../DISK/*.hlp Drive 10 in Vice, host fs access ./../DISK/demon.prg 4.2 BUILD.SH ------------ hmw@cursor/sda8:/data/project/c64/sources/demon/dev $ ../build.sh demon Building 'demon' in /data/project/c64/sources/demon/dev help_main.txt: 2021 ../../../DISK/main.hlp help_vic.txt: 1445 ../../../DISK/vic.hlp help_zp.txt: 3639 ../../../DISK/zp.hlp Restarting emulator... Attaching ../disk1.d64 to drive 8 17768 LOC (11601 + 6167) Saving 15823 (0x3dcf) bytes (0x801 - 0x45d0 exclusive). Converting ACME symbols to VICE format...done. Autostarting program and launching telnet connection to debugger... Compilation finished successfully. hmw@cursor/sda8:/data/project/c64/sources/demon/dev $ 4.1 GEANY --------- Base path: /data/project/c64/sources/demon/dev File name: /data/project/c64/sources/demon/demon.geany Build/Set Build Commands/Independent Commands/Make: ../build.sh demon ../disk1.d64 (Default hotkey Shift+F9) 5. CODING CONVENTIONS ===================== 5.1 ZP pointers $f7..$ff ------------------------ $f7..$fa are assigned to the RS232 KERNAL functions and are pretty safe to overwrite. $fb..$ff are designated "free bytes for operating system" and "temporary BASIC storage" and also seem not to affect the system, when destroyed. Toolbox functions use these ZP pointers, too, but they should restore them before returning to the caller, so we can use them freely. Some functions use $f3..$f6, but they back up and restore the contents. These bytes are designated "Pointer to current position in color RAM" and "Pointer to keyboard decoding table". 5.2 Temp byte at $02 -------------------- ZP byte $02 is not used by the KERNAL or BASIC interpreter. In our code, we only use it for short term purposes. That means, there should never be a call to another function, while we hold a value in $02, preventing conflicts. 5.3 .strbuf = TAPE_BUFFER ------------------------- The system uses $33c..$3fb as a buffer when loading/saving data from/to the Datasette. Demon uses this area for temporary storing strings. Alternatively, we may be able to use $200 - $258 ("System/BASIC input buffer"), but that is untested. 5.4 Default names ----------------- .sptr Source pointer .tptr Target pointer .bptr Begin pointer .eptr End pointer .strbuf String buffer, currently using TAPE_BUFFER = $033c..$03fb 5.5 Debug comments, indentation ------------------------------- Grep all files for a double semicolon (";;") to find locations, that need improvement. Wrongly indented code indicates temporary code for debugging (typically changing border colors with INC $d020). Sometimes I temprarily wrongly indent parts of the code, while actively working on a function. Before increasing the version number of Demon, those parts should be cleaned up, though. In case of main_menu.a:main_menu , parts of the code are wrongly indented to separate it from the "pure" menu function; I plan to move the menu to the Toolbox library, where it will provide hooks, so custom functionality needs not to be mixed in anymore. 6. HELP FILE SYNTAX =================== Help files will be converted to PETSCII in build.sh via a call to a C-program named "petcom". Note, that you cannot use upper case letters for text. Help files will be loaded to $c000..$cfff, so the maximum size for each file is 4096 bytes. build.sh will show files sizes. 6.1 LOAD ADDRESS PLACEHOLDER ---------------------------- At the moment, the loading routine assumes two bytes load address at the start of the file, so the first two bytes in the help file must be placeholders. Two dashes are typically used for this. 6.2 SECTION NAMES ----------------- A section name is introduced with a capital "X". The first section should be a "nameless" section, so the command "?" without parameter will show something. Since the first two bytes are placeholders, the first line consists of two dashes and an "X": --X The first, nameless section should list the sections available in the help file. Section names ("topics") may contain space characters, which can be used to define sub-sections. If a section needs several pages, you could define the sections like so: "Xvic 1", "Xvic 2", ... If the user requests a topic, that is not found, the search is repeated a second time with the current help file name (without extension) prepended to the original query term: Assuming, "help.hlp" is loaded, and no section 3 ("X3") exits, issuing ?3 will trigger a second pass searching for "help 3", same as entering ?help 3 The help file will have to provide a section named "Xhelp 3" for this to work. 6.3 LOAD OTHER HELP FILES ------------------------- If a topic does not fit into the current help file, you can trigger automatic loading of another file, by placing am upper case "L" followed by the file name without extension in the according section. E.g. section BIG is stored in another file, the section would look like: Xbig Lbig Section- and file-name don't have to be identical, but it makes sense to name them identically. 6.4 LINKING BACK TO MAIN HELP ----------------------------- Each file should provide a link back to the main help file, or the user won't be able to view the main help topics again. Typically you provide a section named "?" which loads the main help file. You should mention the back command in the first "empty" section, too. See example below. X? Lmain 6.5 END OF HELP FILE -------------------- The help function should abort, when $d000 is reached, but for faster processing, each help file should end in a line containing two upper case "X". 6.6 EXAMPLE HELP FILE --------------------- --X topics: top1 top2 main help: ?? X? Lmain Xtop1 topic 1 subtopics: 1 2 Xtop1 1 subtopic 1-1 Xtop1 2 subtopic 1-2 Xtop2 topic 2 XX 7. MONITOR COMMANDS =================== In case, this list isn't up to date, you can check for all implemented commands in eval_line.a:mmfn_eval_line:.function_table . aAAAA INSTR Assemble new instruction to memory +AAAA INSTR Assemble and relocate following code (see W command) -AAAA Delete one instruction and relocate following code bAAAA [EEEE] Show memory in binary or as sprite data dAAAA [AAAA] Disassemble memory fAAAA EEEE PP [PP...] Fill memory area with pattern g[AAAA] Start/Step program (at given address or current PC) i[+/-] Show status, enable/disable illegal opcodes k[N [Text]] List/clear/set custom function key l"fname" DD [AAAA] Load file from disk mAAAA [AAAA] Hexdump of memory r Show processor status s"fname" DD AAAA EEEE Save memory area to file tAAAA EEEE TTTT Copy memory uAAAA EEEE TTTT Copy memory and adjust absolute addresses (Relocate) wAAAA EEEE Set working window for insert mode >INSTR Direct mode: Execute instruction immediately #D[D[D[D[D] DEC --> HEX $HH[HH] HEX --> DEC *[AAAA [Name]] Symbols ?[TOPIC] Show help 7.1 NOT YET IMPLEMENTED ----------------------- 'SCREEN Enter text and store as screen code "PETSCII Enter text and store in PETSCII format @DOSCMD Send command to floppy drive 7.2 FC3 Monitor Commands ------------------------ As a reference for expanding Demon, here is a command list of the Monitor of the Final Cartridge III. We will try to keep our commands compatible: A Assemble C Compare D Disassemble EC Edit Character ES Edit Sprite F Fill Memory G Go H Hunt I Interrogate (Show memory as text) L Load M Memory dump O Back switch OD Disk monitor P Print memory (hard copy) R Registers S Save T Transfer X Exit # DEC-->HEX $ HEX-->DEC @ DOS command *R Read block *W Write block 8. KNOWN BUGS ============= *) When assembling an instruction with relative address (branch instructions), the range is not checked. If the target is outside the +/- 127 bytes range, an incorrect target address is calculated while no error is indicated. This should be solved, when assemble.a:get_amode is being rewritten. *) When inserting code, branches that jump across the insertion location, are not being recalculated. *) Direct mode does not catch dangerous instructions like RTS, RTI, branches, etc. *) When the client disables interrupts (SEI), break points will no work 9. TODO ======= ;--REDUCING-CODE-SIZE---------------------------------------------------------- [ ] .is_hex_digit [ ] 2-byte Skip: CPX # 5 CPX # 5 CPX #5 BEQ t1 BEQ t1 BEQ t1 LDA #$4d LDA #$4d LDA #$4d BNE t2 .byte $2c --> BIT $53ad t1 LDA #$53 LDA #$53 -----------^ t2 JSR bsout JSR bsout JSR bsout -------------------------------------------------- [ ] Toolbox: Get rid of puts, rewrite based on bsout [ ] Opcode maxtrix: Combine address mode and cycles (low/high nibbles) [ ] Opcode maxtrix: Combine cycles and amode: Don't use $80 flag for ignore opcode, but number the amodes for unwanted ops $a, $b and use BCC instead of AND [ ] Disassemble: Get rid of .cctr, use .X instead ;--GENERAL--------------------------------------------------------------------- [ ] Help: 4K [ ] Help: If WS includes $c000+, refuse to load [!] Illegal opcodes --> runtime switch [!] Check snapshot chip registers areas for off-by-one size [!] assemble: aREL out of range not caught [!] assemble: rewrite find_amode https://www.c64-wiki.com/wiki/Adress_mode aIMP OPC aIMM OPC #$ll aABS OPC $hhll aABX OPC $hhll,X aABY OPC $hhll,Y aZP OPC $ll aZPX OPC $ll,X aZPY OPC $ll,Y (Invalid according to Vice) aREL OPC $hhll (OPC $rr) aIND OPC ($hhll) aINX OPC ($ll,X) aINY OPC ($ll),Y [!] Scroll (down): When hibyte of addr changes --> bugs [!] panic+divider: writes outside vram-->crash [!] panic: restart properly, fix sptr [!] panic: reset menu color properly [!] panic: don't copy monitor context to client on restart [!] Save: with load address [!] When USE_IRQ is disabled, call_get_key does not work in mmfn_output_screen [!] Verify aREL [!] assemble.a:.find_space - what if aIMM and #0 following instead of space Check assemble.a:.skip_numbers, if changing .find_space! [!] Invalid amode: put cursor to first bad char instead of EOL [!] Status save/restore is missing sprite vectors in VRAM (only #1000 bytes saved) [!] Move context data to top of memory (below catch-all-ISR) [?] $00 and $01 not saved in snapshot - correct for that [?] Disable NMI while in STEPMODE_IDLE [?] When keyboard handling is done in the IRQ by ourselves, change to using R/S to interrupt a running client routine instead of using Restore-NMI [?] Second, optional param: only if spaces! [ ] Help: Show opcode info procedurally (Popcodes) ;--TOOLBOX--------------------------------------------------------------------- [!] puts_v/cptr @ZP - don't scatter them around, also - backup befor client? [!] Set IRQ lines according to scroll_area [!] Restore IRQ before G, show in R [ ] print_menu: top right string, right align (make function for that?) [ ] print_menu: without IRQ, bottom menu line is empty ;--SYMBOLS--------------------------------------------------------------------- [?] Zeropage symbols [ ] *<cmd char> --> function table [ ] *K KERNAL-, *B BASIC-symbols, *Z Zeropage (Load them from disk) [~] eval_line can't call symbol_to_address , because the line is screen code [!] Test: try adding a new symbol, when list is full ;--MEMORY-LAYOUT--------------------------------------------------------------- [ ] Load @ $a000, disable basic; Entry point, NMI? [ ] Store help and lists under I/O, dynamically init keys, puts - I/O? [?] Copy KERNAL to RAM below ROM, so we can set breakpoints ;--HELP------------------------------------------------------------------------ [!] Fix drive nuber (currently hardcoded to 10) ;--SCROLL---------------------------------------------------------------------- [!] Dump scroll up faster than down!? [?] Insert: update lines below inserted on screen ;--RELOCATE-------------------------------------------------------------------- [!] Also update branches, if they jump over the insert location [ ] Relocate: Only change high byte for speed improvement [ ] Speed up transfer: First/last partial page extra, rest in 256-loop [ ] Update symbols ;--STEPPER--------------------------------------------------------------------- [!] Save xzp [ ] Step: Show affected memory cells, cycles (total) [ ] Move VRAM of Monitor, so client can write without screen switch or catch access to VRAM/CRAM (like a phantom register) [ ] Command: ret (step until RTS/RTI was executed - watch out for IRQ?) [ ] Direct mode: JMP, BEQ, RET, RTI? --> single step mode [ ] Breakpoint list: After each step check, if stop is needed [ ] Check for KIL when setting break points and warn or something [ ] STEPMODE_STEP: List watches in 3 colors: no change, client wrote, someone else wrote. Command: toggle automatic watches display: Don't, show all, show changed, show condition met ;------------------------------------------------------------------------------ [ ] Fullscreen step: Like ARES. Show regs in window, RVS for current op [ ] R/S while tracing [ ] Watches, break conditions [ ] Toggle break point for this line [ ] Show break points, watches in disassembly [ ] Show nr. total cycles via BRK-stepper [ ] Edit watches, break conditions [ ] Trace: tr <list of opcs>, showing only those while running ;--FEATURES-------------------------------------------------------------------- [ ] VERIFY [ ] d1000-, dw (disass workspace) [.] Reference on disk (KERNAL/BASIC routines, ZP addresses, I/O, Opcodes, etc) [ ] Scrollable dirlist [ ] Hexdump, colors: Visualize used Stack space [?] Use client_bank for disassembly/assembly, hexdump [ ] Initialize only the first time when demon is started, except init message [ ] Line read in: Stop copying to buffer, when a ':' is encountered [ ] @08.1:dc<command> ;------------------------------------------------------------------------------ [ ] Handle keyboard manually, get rid of KERNAL/BASIC [ ] Handle keyboard in IRQ -> R/S, window/context switch, etc [ ] Load/save symbols from disk [ ] Edit symbols [ ] Assembly: symbol/break point/watch for this line with special chars at end [ ] Relocate monitor (on the fly) [ ] Sprites, Text (scr, pet - convert block), charset [ ] ISR for user's code? NMI? [ ] "Who jumps here?" [ ] Printer support [ ] Floppy (sector, disked, FRAM/FROM) (like a bank) [ ] Syntax highlight, show special ops in color, like JMP, RTS, Bxx, BRK ;------------------------------------------------------------------------------ [ ] Pseudo instructions: .byte, .word, .char, .text [ ] Show/enter byte: aaaa bb $bb ;--CODE FOLDING---------------------------------------------------------------- [ ] Scan for subroutines [ ] Offset in disassemble, scroll-stop [ ] Fetch function: follow all jumps in case of multiple RTSs? [ ] Dividing line after JMP, RTS, RTI [ ] Symbols [ ] Named KERNAL/BASIC calls [ ] Named Toolbox calls ;--MULTITASKING---------------------------------------------------------------- [ ] Multiple contexts [ ] Save context to disk (save_state + program code) [ ] &[AAAA] Dispatch process [ ] Process can return early, if it needs to be called only every n context switches, thus providing more CPU time to other threads [ ] Priority: Give this thread +/- n time slices [ ] Task switching/Multitasking (assigned windows per context) [ ] Multitasking/Windows/Screens: Colors, crsrpos, rvs state, upper/lower case Stack, Vectors, Regs, I/O ports (SID, CIA), ROM config [ ] SpriteEd, Fumble, CharGen - external apps loaded from disk, when needed [ ] Client context: requested stack size (or a compile time switch) [?] Save only used stack and give the client always the full stack [ ] Segment management ;--MISC. IDEAS----------------------------------------------------------------- [ ] Convert machine code to pseudo asm without addresses, but only symbols, keeping everything relocatable when closing editor. Starting ed: Fetch routine to buffer for faster editing without moving all functions when inserting new stuff, when leaving ed, rearrange the whole program [ ] Keep track of touched mem when assembling; Automatic save with SYS2061 ;------------------------------------------------------------------------------ [ ] Redcode Jitter/Pseudo Opcode converter [ ] ICWS94, 2048 cells:16K RAM: OOOO MMMm mmAA AAAA AAAA ABBB BBBB BBBB [ ] 2048 cells...multicolor mode? bitmap mode? https://www.c64-wiki.de/wiki/SMON 10. REFERENCE MATERIAL ====================== SNAPSHOTS configured to save ZP+Stack, without XZP $200-$3ff ------------------------------------------------------------ ;client: e000-ea7c monitor: ea7d-f4f9 ; zp e7d0-e9cf zp f24d-f44c ; vic e9d0-ea00 vic f44d-f47d ; sid1 ea01-ea52 sid1 f47e-f4cf ; cia1 ea53-ea72 cia1 f4d0-f4ef ; context ea73-ea7c context f4f0-f4f9 ACME CROSSASSEMBLER ------------------- https://sourceforge.net/p/acme-crossass/code-0/16/tree/trunk/docs/QuickRef.txt https://sourceforge.net/p/acme-crossass/code-0/16/tree/trunk/docs/AllPOs.txt https://sourceforge.net/p/acme-crossass/code-0/16/tree/trunk/docs/AddrModes.txt https://sourceforge.net/p/acme-crossass/code-0/16/tree/trunk/docs/Illegals.txt https://sourceforge.net/p/acme-crossass/code-0/16/tree/trunk/docs/Errors.txt Die Speicheraufteilung des C64 im Normalzustand - für genauere Informationen siehe PLA. $FFFF = 65535 ┌───────────────┬───────────────┐ │---------------│|||||||||||||||│ ||| = wird z.B. bei PEEK gelesen │---------------│|||||||||||||||│ --- = wird z.B. bei POKE geschrieben │---------------│|||||||||||||||│ +++ = lesend + schreibend │---------------│||| KERNAL ||||│ sonst = von BASIC aus nicht erreichbar │---------------│|||||||||||||||│ │---------------│|||||||||||||||│ │---------------│|||||||||||||||│ $E000 = 57344 ├───────────────┼───────────────┼───────────────┐ │ │ │+++++++++++++++│ │ │ CHAR │+++++ I/O +++++│ │ │ │+++++++++++++++│ $D000 = 53248 ├───────────────┼───────────────┴───────────────┘ │+++++++++++++++│ │+++++++++++++++│ │+++++++++++++++│ $C000 = 49152 ├───────────────┼───────────────┐ │---------------│|||||||||||||||│ │---------------│|||||||||||||||│ │---------------│||| BASIC- ||||│ │---------------│||| ROM ||||│ │---------------│|||||||||||||||│ │---------------│|||||||||||||||│ │---------------│|||||||||||||||│ $A000 = 40960 ├───────────────┼───────────────┘ │+++++++++++++++│ │+++ BASIC- ++++│ │+++ RAM ++++│ \ . . - Details in Speicherbelegung (BASIC) . . / . . │+++ BASIC- ++++│ │+++ RAM ++++│ $0800 = 2048 │+++++++++++++++│-┐ $0400 = 1024 │+++++++++++++++│-┘Bildschirmspeicher $0000 └───────────────┘-┘Zeropage und Erweiterte Zeropage $4000 = 16384 EOF get_instruction_length ;------------------------------------------------------------------------------ ; IN: .A int8 Opcode ; OUT: .A int8 Length of instruction STY $02 ; Back up .Y !ifdef ILLEGAL_OPCODES { LDY illegal_opcs BNE .skip_illegals PHA ; Remember opcode TAY LDA opcode_matrix,Y CMP # $38*3 ; First illegal opcode string index BCS .ret_1 PLA ; Restore opcode JMP .skip_illegals .ret_1 PLA JMP .return_1 .skip_illegals } TAY LDA amode_matrix,Y CMP #aIMM BCC .return_1 CMP #aABS BCC .return_2 .return_3 LDA # 3 BNE .done ; Will always jump .return_2 LDA # 2 BNE .done ; Will always jump .return_1 LDA # 1 .done LDY $02 ; Restore .Y RTS !if (0) { !ifdef WORKSPACE { ;============================================================================== !zone WORKSPACE_INSERT ;============================================================================== ; .sptr=5, offs=2 ; ws_s | ws_e ; | .---->----. | Pointer from area below to above sptr ; 1 2 3 4 5 6 7 8 9 ; '----<----' Pointer from area above to below sptr ; ; 1 2 3 4 5 6 7 8 9 Step 1: Relocate [sptr, ws_e] --> (sptr + offset) ; 1 2 3 4 5 6 7 8 9 Step 2: Pseudo-reloc [ws_s, ws_e] --> (ws_s + offs) ;------------------------------------------------------------------------------ .bptr = $c1 ; Shared with relocate! .wptr = $c3 ; Shared with relocate! .sptr = $f7 ; .eptr = $f9 ; Shared w. relocate, transfer! .tptr = $fb ; .offset = $fd workspace_insert ;------------------------------------------------------------------------------ ; IN: .X/.A int16 Address for new room ; .Y int8 Number of bytes to make room for ; OUT: CARRY Boolean FALSE, if within workspace window STX .sptr ; Save parameters STA .sptr+1 STY .offset ;------------------------------------------------------------------------------ ; Step 1: Relocate [sptr, ws_e] --> (sptr + offset) JSR save_zp_pointers ; sptr is already set LDA workspace_end ; eptr := ws_e STA .eptr STA .wptr LDA workspace_end+1 STA .eptr+1 STA .wptr+1 CLC ; .tptr := sptr + offset LDA .sptr ADC .offset STA .tptr LDA .sptr+1 ADC # 0 STA .tptr+1 JSR start_relocate JSR restore_zp_pointers ;------------------------------------------------------------------------------ ; Step 2: Pseudo-reloc [ws_s, sptr-1] --> (ws_s + offs) CLC LDA .sptr ; Copy .sptr . It will move and we STA .bptr ; need to check, if an address is in LDA .sptr+1 ; the moved block. STA .bptr+1 SEC ; eptr := sptr - 1 LDA .sptr SBC # 1 STA .eptr LDA .sptr+1 SBC # 0 STA .eptr+1 SEC ; sptr := ws_s LDA workspace_start ; tptr := ws_s + offset STA .tptr SBC .offset STA .sptr LDA workspace_start+1 STA .tptr+1 SBC # 0 STA .sptr+1 LDA workspace_end STA .wptr LDA workspace_end+1 STA .wptr+1 !if (1) { ;; SEC ; Calculate offset for operands LDA .tptr SBC .sptr STA .offset LDA .tptr+1 SBC .sptr+1 STA .offset+1 } LDA workspace_start STA .sptr LDA workspace_start+1 STA .sptr+1 JMP start_adjust ;RTS } !ifdef WORKSPACE { ;============================================================================== !zone WORKSPACE_DELETE ;============================================================================== ; .sptr=5, offs=2 ; ws_s | ws_e ; | .---->----. | Pointer from area below to above sptr ; 1 2 3 4 5 6 7 8 9 ; '----<----' Pointer from area above to below sptr ; ; 1 2 3 4 5 6 7 8 9 Step 1: Relocate [sptr+offset, ws_e] --> sptr ; 1 2 3 4 7 8 9 Step 2: Pseudo-reloc [ws_s, ws_e] --> (ws_s - offs) ;------------------------------------------------------------------------------ .bptr = $c1 ; Shared with relocate! .wptr = $c3 ; Shared with relocate! .sptr = $f7 ; .eptr = $f9 ; Shared w. relocate, transfer! .tptr = $fb ; .offset = $fd .error JMP line_show_error workspace_delete ;------------------------------------------------------------------------------ LDY # 1 JSR line_expect_int16 BCS .error STX .sptr STA .sptr+1 JSR line_expect_int16 BCS .delete_one ; Only one parameter was given STX .eptr STA .eptr+1 ;------------------------------------------------------------------------------ ; Walk memory, checking instruction lengths to adjust .eptr, ; so we don't delete a partial instruction at the end LDA .sptr STA .tptr LDA .sptr+1 STA .tptr+1 LDY # 0 .loop_walk LDA (.tptr),Y ; Get opcode JSR get_instruction_length CLC ADC .tptr STA .tptr LDA .tptr+1 ADC # 0 STA .tptr+1 ; CMP .eptr+1 BCC .loop_walk ; tptr hi < eptr hi? Not at end. BEQ .check_walk_lo ; tptr hi = eptr hi? Check low bytes BCS .end_walk ; tptr hi > eptr hi? Above end. .check_walk_lo LDA .tptr CMP .eptr BCC .loop_walk ; tptr lo < eptr lo? Not at end. BEQ .loop_walk ; tptr lo = eptr lo? End, go overshoot .end_walk LDA .tptr ; wptr STA .eptr LDA .tptr+1 STA .eptr+1 JMP .start_del ;------------------------------------------------------------------------------ ; Only one parameter was given, deleting just one instruction .delete_one LDY # 0 LDA (.sptr),Y ; Get opcode JSR get_instruction_length CLC ADC .sptr STA .eptr LDA .sptr+1 ADC # 0 STA .eptr+1 ;------------------------------------------------------------------------------ ; Step 1: Relocate [sptr+offset, ws_e] --> sptr .start_del SEC LDA .eptr SBC .sptr STA .offset LDA .eptr+1 SBC .sptr+1 STA .offset+1 JSR save_zp_pointers LDA .sptr ; .tptr := sptr STA .tptr LDA .sptr+1 STA .tptr+1 CLC ; sptr := sptr + offset LDA .sptr ADC .offset STA .sptr LDA .sptr+1 ADC .offset+1 STA .sptr+1 LDA workspace_end ; eptr := ws_e STA .eptr STA .wptr LDA workspace_end+1 STA .eptr+1 STA .wptr+1 JSR start_relocate JSR restore_zp_pointers ;------------------------------------------------------------------------------ ; Step 2: Pseudo-reloc [ws_s, ws_e] --> (ws_s + offs) CLC LDA .sptr ; Copy .sptr . It will move and we STA .bptr ; need to check, if an address is in LDA .sptr+1 ; the moved block. STA .bptr+1 SEC ; eptr := sptr - 1 LDA .sptr SBC # 1 STA .eptr LDA .sptr+1 SBC # 0 STA .eptr+1 SEC ; sptr := ws_s LDA workspace_start ; tptr := ws_s + offset STA .tptr SBC .offset STA .sptr LDA workspace_start+1 STA .tptr+1 SBC # 0 STA .sptr+1 LDA workspace_end STA .wptr LDA workspace_end+1 STA .wptr+1 !if (1) { ;; SEC ; Calculate offset for operands LDA .sptr SBC .tptr STA .offset LDA .sptr+1 SBC .tptr+1 STA .offset+1 } LDA workspace_start STA .sptr LDA workspace_start+1 STA .sptr+1 JMP start_adjust ;RTS } }
About
Debugger/Monitor for the C64
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published