Skip to content

gummyworm/monster

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 

Repository files navigation

MONster

hello

Table of Contents


Overview

MONster is an all-in-one editor/assembler/debugger for the Commodore Vic-20. The design philosophy is uncompromising maximalism. This is the polar opposite of most existing Vic-20 assemblers, which, though impressive in their own right, are mostly designed with memory efficiency in mind. Virtually any feature that I deem valuable in an editor/assembler is included.

Some of its features are:

  • 40 column bitmap-based editor
  • vi-like keybindings
  • breakpoint editor
  • interactive visual debugger
  • memory viewer/editor
  • file I/O (save/load)
  • directory viewer
  • symbol viewer
  • auto-formatter and realtime syntax checking
  • macro support
  • user program/source/editor isolation
  • many more...

The source code is stored in a gap buffer to allow for efficient insertion/deletion.


Requirements

For now MONster requires a Final Expansion to function. It could easily be modified for other 512k+ carts. Much of this RAM is used to store the multiple source code buffers (up to 8), but it is also used to store debug info and some code.

The banked memory allows the user program to execute in almost complete isolation. This means that, although this environment consumes a vast amount of memory itself, everything except address $9c02 (the bank select register) is preserved when control moves between the editor and the user program. Moreso even than small monitor cartridges, the program itself is virtually unaware of the resident tooling.

Building

Building the source requires ca65. The easiest way to install this is to install the latest release of cc65. I've tested with v2.18.

Build Steps

  1. Clone this repo git clone https://github.com/gummyworm/monster.git
  2. cd to the directory you cloned to and run make

Running

The Makefile will generate a PRG. You may write this to your disk of choice and load it as you would any other program on your Vic-20: LOAD "MONSTER.PRG",8,1

If you wish to run it in an emulator (VICE), ensure that VICE is installed on your machine and run make start from the root of the project.


Editor Overview

The editor is a substantial part of this assembler. In addition to offering a high-density 40-column display, it has, by 8-bit standards, advanced navigation functionality.

Command shortcuts

Below are the basic commands along with their associated key combinations. These commands are available regardless of insertion mode (see the Editor Modes section below for more info on modes).

Key Name Description
C= + b Set Breakpoint sets a breakpoint at the current line
C= + c Refresh refrehshes the screen by redrawing the source buffer
C= + h Help displays the help menu
C= + l List list directory, shows the files on the current disk
C= + n New buffer creates a new source buffer and sets it as the active buffer
C= + q Close buffer closes the current buffer and opens the next one that is open
C= + v MemView enters the memory viewer/editor (press <- to exit)
C= + y Show Symbols lists the symbol table for the assembled program
F3 Assemble assembles the code in the buffer to memory
F4 Debug assembles the code in the buffer to memory with debug info
F5 Show buffers displays a list of the currently open buffers
C= + + Next Drive Selects the next drive (limited to #15)
C= + - Prev Drive Selects the previous drive (limited to #8)
: Ex Command Accepts a command + argument(s) and executes the command

Ex Commands

The following commands are entered at the "Ex Command" prompt (accessed with the : key). Most accept an argument (as described in each commands description below)

Key Name Args Description
a Assemble File Filename assembles the given filename
d Start Debugger Symbol to debug at (optional) begins debugging at the given label
D Disassemble Start address, End address Disassembles the given address range
e Edit Filename loads the buffer with the contents of the given file
g Goto Symbol to run at (optional) executes the program at the address of the given symbol
r Rename Name renames the buffer to the given name
s Save Filename saves the buffer to the given filename
x Scratch Filename scratches (deletes) the given filename

Assemble File (a)

Assembles the contents of the given file. This is functionally the same as opening the given file and assembling it with debug information (F4).

Invoking the debugger will invoke it for the last assembled file (not the current source buffer) in this scenario. The debugger cares about the active debug information not the active file.

Example: :a HELLO.S

Start Debugger

Begins debugging at the given symbol using the active debug information.

If no symbol is given, the program will begin and the debugger invoked at the lowest defined origin (.ORG) in the program. See Debugger for more details on debugging.

Example: :d START

Disassemble (D)

Disassembles the contents of the virtual memory between the given range. e.g. :D $1001, $1040. Expressions may be used in addtion to literal addresses. This could be useful if your program modifies itself at rutime.

Example: :D PSTART, PEND

Edit (e)

Loads the given filename to a new buffer and activates it.

Example: :e HELLO.S

Rename (r)

Renames the active buffer to the given name. Example: :r TEST2.S

Save (s)

Saves the active buffer to a file with the given name. If no name is given, the active buffer's name is used.

Adding an @ to this command (S@) will delete the file before saving. This allows you to overwrite the existing file if it exists.

Examples: :s NEW.S :s@ OLD.S

Scratch (x)

Deletes the file of the given name. Example: :x TEST.S


Editor Modes

The editor is a modal editor, that is, it behaves differently depending on which mode it is in. The modes are all accessed from the default mode (called COMMAND mode) and each returns to the base COMMAND mode when the <- key is pressed. Below is a list of the modes along with the key that enters that mode

Command Mode

Command mode is the default mode. The primary function of command mode is to navigate around the source code and to enter other modes. Navigation behaves similar to vi and many basic vi commands are supported. The following keys are handled in COMMAND mode.

Key Name Description
HOME Home moves the cursor to column 0
C= + m Goto line prompts for a line number and moves the cursor to that line
C= + [1-8] Goto Buffer opens the buffer corresponding to the number key that is pressed
C= + < Prev Buffer opens the buffer before the active one (if there is one)
C= + > Next Buffer opens the buffer after the active one (if there is one)
C= + i Jump up jumps forward to the next source position that was "jumped" to
C= + o Jump back jumps back to the last source position that was "jumped" to
$ End of Line moves the cursor to the end of the current line
;; Banner inserts a banner (full line of semicolons) below the cursor
gg Top of File moves the cursor to the first character in the file
G End of File moves the cursor to the last line in the file
h Left moves the cursor left
j Down moves the cursor down
k Up moves the cursor up
l Right moves the cursor right
H Home moves the cursor to the top left of the screen
L Last moves the cursor to the bottom left of the screen
dw Delete Word deletes the next word
dd Delete Line deletes the next line
0 Column 0 moves the cursor to the first column of the current line
a append char enters insert mode and moves to the next character
A append line enters insert mode and moves to the last character in the current line
o open line opens a new line below the cursror and moves to it
O open line ^ opens a new line above the cursor and moves to it
p paste below pastes the contents of the copy-buffer to the line below the cursor
P paste above pastes the contents of the copy-buffer to the line above the cursor
I Insert line enters insert mode and moves to the first character in the current line
[ Prev Block moves to the previous empty line or start of file if there isn't one
] Next Block moves to the next empty line or end of file if there isn't one

Insert Mode (i, a, etc.)

Entering insert mode allows the user to enter text at the cursor location. Keystrokes are interpreted as their corresponding ASCII character value in this mode, so there are no special commands accessed via them.

Visual Mode (v)

In VISUAL mode (accessed via v in COMMAND mode), the user can select a block of text which may then be deleted or copied. Below is the table of supported commands while in visual mode. The <- key will return the user to to COMMAND mode.

Key Name Description
d delete deletes the selected text and copies it to the copy buffer
y yank copies the selected text (in VISUAL mode) to the copy buffer

Visual Line Mode (V)

VISUAL LINE, which is entered with the SHIFT - v key combination from COMMAND mode is similar to VISUAL mode, but selections include only entire lines. Upon entering VISUAL LINE mode, the current row is selected. Navigating to rows above or below will select additional lines. The delete and yank keys behave the same as they do in VISUAL mode.


Copy buffer

When text is deleted (delete line, delete word) or yanked, it is stored to a buffer where it may be recalled by the paste commands (p, paste below and P paste above). When the paste command is executed, the buffer is cleared.

Jump Lists

When the user "jumps" to a different position in the source (gg, G, goto line, find, [, and ]) the editor tracks this new position. To recall these jump points there are two commands. These are jump-forward (C= + i) and jump-backward (C= + o).


Assembler Overview

Syntax

The assembler syntax is very similar to any other major assembler. For basic instructions, the canonical 6502 assembly syntax is supported. That means '$' denotes a hex value, '#' and immediate operand, parentheses an indirect address, etc. :vs

Expressions

Operands, in addition to basic values and labels, may contain an expression, which is evaluated to a value to generate the operand for the generated binary.

('+', '-', '*', '/' respectively), which are evaluated with proper operator precedence.

Expressions may contain parentheses, which are evaluated as you would expect, but note that if the entire expression is enclosed in parentheses, the assembler will interpret this as indirect addressing. For example:

JMP (1+3)	; jump-indirect to the address in memory address (4)
JMP 1+3 	; jump-absolute to address 4

Immediate-addressing makes no sense with indirect addressing mode, so the assembler will allow you to enclose the whole expression in parentheses for expressions that are defined with a '#' prefix (e.g. LDA #(2+4))

In addition to hexadecimal values, decimal values, and labels, character literals may be used in expressions. These are represented as a character enquoted within single quotes. LDA #'x' Character literals must contain exactly one character and always resolve to a 1 byte value.

Formatting

Spacing is not important, but instructions are auto-formatted to be indented by two spaces. Labels and directives are, by convention, not indented. The formatter will also take care of this.

Labels

Labels begin with either an alpha-character or, in the case of local labels, a '@' character. They are limited to 8 characters, which is primarily a formatting consideration (this limitation allows all labels to coexist with an instruction on a single line without bumping the instruction beyond its normal home in column 10.

Local labels are defined by prefixing the label with a '@' symbol. This does count toward the 8-character label limit. Local labels are valid until the next non-local label is defined as shown in the following example.

PROC0:
@L0:
    DEX
    BNE L0
    RTS
PROC1:
@L0:
    DEY
    BNE L0
    RTS

Note that the scope of the @L0 defined under PROC0 is valid until the next non-local label (PROC1) at which point the name is recylced and may be used again.

Because of the way local labels are implemented they are not totally inaccessible. They can be accessed by prepending the global label that encapsulates them. This can be used to emulate structural data types e.g.

PLAYER
@X: .db 0
@Y: .db 0

GAME:
	LDA PLAYER@X

Directives

Directives begin with a . character and instead of being directly assembled, as with an instruction, tell the assembler to generate some special code or data based on the operands.

Some directives (.MAC and .REP) generate a variable amount of code or data based on the value of their operands. For these directives, the expressions used as arguments must be resolvable in pass 1 of the assembler. This means any labels used in the expression must be declared before the directive.

The following example illustrates why this is necessary:

.REP NUM, I
  ASL
.ENDREP
.EQU NUM 5

Note that NUM is not declared until after the .REP directive. Because of this the assembler does not know how many times to repeat the ASL. We could assume the label is an arbitrary 16-bit value as we do with labels that are undefined in pass 1, but any subsequent labels would have the wrong address if we guessed any number other than 5.


List of Directives

.DB expression, ..., expression

Defines a sequence of bytes from the comma-separated list that follows.

Examples:

code generated binary
.DB $00, $01, $02 $00 $01 $02
.DB "HI",0 $48 $49 $00

.DW expression, ..., expression

deines a sequence of words from the comma-separated list that |

Examples:

code generated binary
.DW $00, $01, $02 $00 $00 $01 $00 $02 $00

.ENDIF

Ends a .IF block

See .IF

.EQU name expression

Defines a constant which may be used in expressions

.EQU BITMAP $1100
  LDA #$00
  STA BITMAP+20

.IF expression

Evaluates the expression Conditionally assembles the lines between this directive and its matching .ENDIF.

.IF NTSC
.EQU CYCLES_PER_LINE 65
.EQU LINES 261
.ELSE
.EQU CYCLES_PER_LINE 71
.EQU LINES 312
.ENDIF

.IFDEF label

Evaluates to TRUE if label is defined. This is different from .IF because label may be defined to be 0 and this will still evaluate to TRUE. This can be useful inside macros to determine if a paramter was provided or not.

.INC filename

Includes a file at the line of the directive. The file is loaded line-by-line from disk and assembled as if the code was copy/pasted in place of the include directive.

.INC "KERNAL.INC"
  LDA #$00
  JSR CHROUT

.INCBIN filename

Includes the binary file. The binary contents are stored at the current location of the assembly target when this directive is encountered

.EQ BITMAP $1100
  LDX #$07
L0:
  LDA SPRITES,X
  STA BITMAP,X
  DEX
  BPL L0

SPRITES:
.INCBIN "SPRITES.BIN"

.MAC name param 1, ..., param n

Defines a macro

.MAC LDXY VAL
  LDX #<VAL
  LDY #>VAL
.ENDMAC

  LDXY $1234

Will generate the following code:

  LDX #$34
  LDY #$12

Macro definitions begin with the .MAC directive followed by the name of the macro and a comma-separated list of the parameters for the macro.

Macros are invoked with the name of the macro followed by a comma-separated list of the parameters.

.ORG expression

Sets the address to assemble code to

.ORG $1000
; start up code

.ORG $2000
; main code

.RORG expression

Sets the address the code will run at when executed. This is useful for code that will be relocated prior to execution.

.ORG $1000
.RORG $00
  ; some tight loop
  LDA #$01
  STA *+3
  LDA #$00
  STA $900F

Note that the .RORG directive must follow the .ORG directive in order to avoid the virtual PC being overwritten. .ORG will set the virtual PC to the same location as the physical PC.

.REP expression [, iterator name]

Assembles the code between this directive and .ENDREP for the given number of times.

.REP 3
  ASL
.ENDREP

Becomes

  ASL
  ASL
  ASL

An optional parameter can be given that will be assigned the value of the current iteration of repetition during assembly.

.REP 5,I
   INC $F0+I
.ENDREP

Becomes

  INC $F0
  INC $F1
  INC $F2
  INC $F3
  INC $F4

Macros

Macros offer a conveinient way to abstract patterns that you find yourself frequently writing.

They may be recursive as in this example:

.MAC LDXY VAL
	LDX VAL
	LDY VAL+1
.ENDMAC

.MAC STXY ADDR
	STX ADDR
	STY ADDR+1
.ENDMAC

.MAC SET DST, SRC
	LDXY SRC
	STXY DST
.ENDMAC

You may omit arguments to a macro if your macro knows how to deal with less than the maximum number it expects as in this example:

.MAC SAVEBYTES A, B, C
.IFDEF A
	LDA A
	PHA
.ENDIF
.IFDEF B
	LDA B
	PHA
.ENDIF
.IFDEF C
	LDA C
	PHA
.ENDIF
.ENDMAC

Example program

Here is a basic hello world program to demonstrate some of the assembler's features

.ORG $1400
MSG:
.DB "HELLO WORLD!",0
START:
  JSR $E5B5
  LDX #$00
  LDA #' '
CLR:
  STA $1000,X
  STA $1100,X
  DEX
  BNE CLR
DISP:
  LDA MSG,X
  BEQ DONE
  JSR $FFD2
  INX
  BNE DISP
DONE:
  JMP DONE

Files

Monster holds the active source file in memory (for editing), but assembles all included files directly from file. Files are stored with $0d line endings, but if you save your file with UNIX style line-endings, they will be automatically converted when the file is read in.

As with any work done with Commodore disk I/O, it is wise to regularly back up your files

Drive Selection (C= + + and C= + -)

Selects the next or previous drive (within the valid range of 8-15). C= + + (plus) selects the next available drive and C= + - (minus) selects the previous available drive.

Directory Viewer (C= + L)

The directory viewer offers a paginated view of all files on the disk. Pressing RETURN while the row of the desired file is highlighted will load that file into a new buffer and activate that buffer.


Symbol Viewer

The symbol viewer, activated with C= + Y, displays all the labels in the program along with their corresponding address. The up/down cursor keys navigate between pages of symbols. The back-arrow key returns to the debugger.


Debugger

debugger.mov

The debugger allows you to step through code, set breakpoints, and watch data as you execute your program. Due to the size of the data needed to store the debug information, this feature requires a Final Expansion (512k RAM expansion).

The debugger is enabled by pressing the C= + D key combination. This will prompt the user for a label name, which will be used as the start address for debugging. If no label name is provided, execution will begin at the base origin of the program (the lowest value set by any .ORG directive)

When you enter the debugger, you will be presented with a view of the state of the processor at the current step or breakpoint. This include the state of the registers (A, X, Y, P, SP, and PC) as well as any effective address that was calculated for reading/writing by the last instruction.

While debugging, most navigation commands work as normal. Breakpoints may be set as they would in the editor prior to assembly, and they will be installed in realtime.

Both the debugger and the user program's RAM is saved/restored when control transfers between the two. That is the screen data ($1000-$2000), the zeropage, and color RAM.

Editor navigation behaves as normal while debugging (albeit with slightly less real estate due to the debug information displayed at the bottom of the screen.)


Debug Commands

The following commands are supported by the debugger and are accessed by their respective Key in the table below.

Key Name Description
F1 Source View maximizes the screen area for viewing the source code
F2 Register Editor enters the register editor
F3 Mem View activates the memory window, which takes control until <- is pressed
F5 Break View displays the breakpoints that have been set and allows them to be enabled/disabled
C=+g Go begins execution at the cursor
C=+s StepOver steps to the next instruction. If it is a JSR, continues AFTER the target subroutine
C=+z Step steps to the next instruction.
C=-r Reset Stopwatch resets the value of the stopwatch to 0
C=+t Trace like GO but the debugger takes control between each instruction
<- Exit exits the debugger and returns to the editor
SPACE Swap prog swaps in the internal memory for the user program (allows user to see screen state)

Register Editor (F2)

Pressing F2 moves the cursor to the register contents and allows the user to enter new values for them. Pressing RETURN will confirm the new register values and update them to those values the next time the user program is invoked. Pressing <- will abort this process and leave the old register values intact.

Stopwatch

Next to the registers, under the CLK label, is a 24-bit counter that displays the number of cycles executed by the instructions that have been STEP'd into. The stopwatch can be reset to 0 with the C= + r key combination.

Note that the number of cylces is displayed in decimal unlike the rest of the information in the debug view, which is displayed in hexadecimal.


Stepping through code

Step Into (C= + z)

Stepping is a common way to debug a program line-by-line. Stepping into code (C= + z) will, if possible, return to the debugger after the next instruction (the one currently highlighted if we have debug information) is executed. There is a scenario where this is not possible: if the next instruction is in ROM. In this case, step into behaves the same as step over: execution begins after the current instruction. Note that because we don't know what will happen in ROM, it is possible execution will never return to the debugger.

Keeping in mind the aforementioned caveat with ROM, stepping into code gives us a lot of information about the instructions we are executed. The debugger behaves almost as a 6502 simulator in this scenario. When an instruction that affects a given register, that register is highlighted even if the register value hasn't changed. The same is true of watches. We can activate a watch even if we don't store a new value to it. In fact, we can activate them when a value is loaded.

Step Over (C= + s)

Step over behaves the same as step into, but if the next instruction is a subroutine call (JSR), execution continues until the instruction after the JSR (after the subroutine returns).

Go (C= + g)

The go command begins execution and returns to the debugger only when a breakpoint is encountered.

Trace (C= + t)

Trace is similar to GO, but the debugger executes the program as a series of STEPs instead of running the program binary directly. This is useful because it allows the debugger to break if any watched memory location is accessed.

Notes on memory swapping

While the debugger and user program have isolated memory banks in the address space above $1fff, the RAM below this, [$00, $2000), is internal to the Vic-20 and cannot be swapped out between debug steps. The debugger has no choice but to share this address space with the user program as it is also the only RAM that is visible to the video chip (the VIC-I). It also contains the stack and zeropage, which we could avoid, but as long as we need to use the $10th-$20th pages of RAM, it makes sense to handle them in the same way.

To handle this, the debugger calculates the bytes that need to be saved in between steps and saves these values in between calls to the program. Values that will be used by the user program are then swapped in so that the program behaves as if the debugger is not running. The full internal state of the user program and debugger occupy buffers in the debugger and are available to be swapped in/out on command with the C= + SPACE key combination. This is useful if you'd like to see what the internal RAM state, which is the only place that the screen state may live, looks like at the current step in the program.

If we aren't stepping into code in RAM (go, step over) we are unable to calculate the addresses that will be affected when we hand over control to the user program, we instead save the entire debugger state of the internal RAM and restore the entire user state. Although this is a rather large amount of memory, it is mitigated by being handled by a mostly unrolled loop and therefore takes only a fraction of a second to occur. Nonetheless, it is apparent when this is happening if you've changed the setup of the VIC registers, or anything in the VIC's visible address range, as the screen will briefly flash with the state of the user program.


Auxiliary Views

Within the debugger, there are 3 auxiliary views that may be activated with the function keys. Each shows information about the machine or debug state that may be useful to the user. Each viewer also contains an editor, which is activated with the keys enumerated below next to their corresponding editor.

Pressing the <- key will return the user from the auxiliary editor to the source code editor. And F1 will hide the active viewer to maximize the source editor's screen size.

Memory Viewer (F3 while debugging)

The memory viewer displays the contents of RAM at a given address. The memory viewer is updated upon reentry to the debugger (if active). Memory values may be updated by navigating to the value the user wishes to change and overwriting it with a new hex value. The change occurs immediately.

In addition to hexadecimal keys to edit memory values, the following commands are supported within the memory viewer:

Shortcut Name Description
C= + w Add watch Add watch to the highlighted address
/ Find Value Seeks from current memory address for given value
<- Exit Returns to the debugger
^ (up-arrow) Set Addr Sets the viewer's address to the given value

Set Watch (C= + w)

Watches may be placed while navigating in the memory editor. This is done by pressing the C= + w key-combination while the cursor is on the desired byte to watch. See the Watch Viewer section for more information on watches.

Find Value (/)

Prompts the user for an 8 or 16 bit value (determined by the number of characters provided) and looks for that value in memory. If it is found, the memory view is updated to begin at the first address that was found containing the specified value.

Note that when seeking for a 16 bit value, the value is searched in little-endian format. If the input for the search is given as $1234 the result will be the first occurrence of the byte value $34 followed by $12.

Set Address (^/up-arrow)

Moves the cursor to the address of the viewer, then prompts the user for a new value to set the memory viewer to. Pressing RETURN confirms the new address and <- cancels and returns the user to the editor without changing the address

Breakpoint Viewer (F5 while debugging)

The breakpoint viewer displays all the breakpoints that have been set by the user. A circle is displayed next to those that are currently active. The user simply navigates the list with the cursor keys and presses RETURN to toggle those which he/she wishes to enable/disable.

Note that breakpoints correspond to the debug information generated with the F4 command. If the line numbers change after this information is generated, breakpoints are unlikely to behave in expected ways.

Watch Viewer (F7 while debugging)

The watch viewer displays all watches that have been set in the memory viewer. The current value of a watch is shown along with its previous value (if it has changed since the debugger last took over).

A watched address (or range) will also be prefixed with a '!' if it was modified during the trace or step. This is especially important for knowing that a range was modified as ranges do not list the previous or current values for the watch.

The following keys are supported within the watch viewer:

Shortcut Name Description
C= + w Add watch Prompt the user for expressions to watch
RETURN Select/Edit Enters the memory editor at the watch's address
<- Exit Returns to the debugger

Add Watch (C= + w)

While in the watch editor, the C= + w key combination prompts the user for an address or address range to watch. These are given as expressions, so you may provide, for example myval+3 to set a watch at the address of the label myval plus 3. To set a watch for an address range, simply provide two expressions, separated by a comma, at the prompt. If the expression(s) are invalid, no watch is added.

Edit Watch (RETURN)

Pressing RETURN will invoke the memory editor at the location of the watch that was selected. Returning from the memory editor will return the user back to the watch editor.


Breakpoints

Breakpoints may be set/removed during both normal editing and while debugging. Setting a breakpoint inserts a special character into the source buffer, which tells the assembler, during assembly, to generate a breakpoint for the line that this character resides on.

Because the breakpoint is represented as a character within the source code itself, it will automatically move as lines are inserted and deleted. The character itself is not editable (the cursor will not move to breakpoint characters). You may remove it by toggling the breakpoint off or by deleting the entire line.

NOTE: Debug information is only generated for instructions NOT data. This means that, for example, you can set a breakpoint on LDA #$00 or a macro that expands to such an instruction, but setting one on .DB $00 will have no effect.

Toggle Breakpoint (C= + b)

During normal editing, breakpoints may be set and removed with the C= + b key combination. A breakpoint symbol (a filled circle) is placed at the beginning of a line to indicate that a breakpoint has been added. Pressing the same key combination (C= + b) will also remove a breakpoint if it is pressed while on a line that already has one.


Watches

Watches are set within the memory editor (F3). When the cursor is over the desired byte to watch, the user may press C= + w to add a watch to the address of the byte under the cursor. A beep will confirm that the watch was added, and the watch may be seen by activating the watch editor (F7).

The viewer will display the old value and what it was changed to.

When a value is changed the watch view is activated to alert the user to the alteration. If a read or write is detected while stepping into the code, we also activate the viewer.

About

A 40 column editor, macro-assembler and debugger for the Commodore Vic-20

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published