-
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