mirror of
https://github.com/forth-ev/VolksForth.git
synced 2025-02-14 08:31:22 +00:00
Merge pull request #52 from pzembrod/x16-r47
Changes for release 6502-C64 3.9.6
This commit is contained in:
commit
f8dd7b31b1
@ -19,6 +19,7 @@ test_files = $(wildcard tests/*.f*)
|
||||
test_files_petscii = $(patsubst tests/%, cbmfiles/%, $(test_files))
|
||||
test_logs = $(patsubst %, test-%.log, $(vf_flavours))
|
||||
test_resuls = $(patsubst %, test-%.result, $(vf_flavours))
|
||||
test_keyboard_input = some 12345 keys
|
||||
|
||||
release_zipfile = volksforth-6502-c64-release.zip
|
||||
|
||||
@ -35,6 +36,7 @@ clean:
|
||||
rm -f *.log *.result *.golden
|
||||
rm -f cbmfiles/c??-testbase
|
||||
rm -f disks/scratch.d64 emulator/sdcard.img
|
||||
rm -f tests/golden/mycore*.golden
|
||||
|
||||
|
||||
# Convenience targets
|
||||
@ -43,6 +45,8 @@ binaries: $(vf_binaries)
|
||||
|
||||
test: $(test_resuls)
|
||||
|
||||
alltests: test test-v4th-x16-tsk.result
|
||||
|
||||
test64: std64 blk64
|
||||
|
||||
blk64: test-v4thblk-c64.result
|
||||
@ -62,6 +66,18 @@ run-testbase: emulator/testbase.T64
|
||||
run-testbase16: emulator/testbase16.T64
|
||||
VICE=xplus4 emulator/run-in-vice.sh testbase16
|
||||
|
||||
run-c64: emulator/v4th-c64.T64 $(all_src_files_petscii)
|
||||
emulator/run-in-vice.sh v4th-c64
|
||||
|
||||
run-c16+: emulator/v4th-c16+.T64 $(all_src_files_petscii)
|
||||
VICE=xplus4 emulator/run-in-vice.sh v4th-c16+
|
||||
|
||||
run-c16-: emulator/v4th-c16-.T64 $(all_src_files_petscii)
|
||||
VICE=xplus4 emulator/run-in-vice.sh v4th-c16-
|
||||
|
||||
run-x16: cbmfiles/v4th-x16 $(all_src_files_petscii) | emulator/sdcard.img
|
||||
emulator/run-in-x16emu.sh v4th-x16
|
||||
|
||||
|
||||
release: tmp/$(release_zipfile) COPYING RELEASE_NOTES.md
|
||||
rm -rf release
|
||||
@ -124,57 +140,57 @@ cbmfiles/v4th-x16e:
|
||||
|
||||
# Core test targets
|
||||
|
||||
$(test_logs): $(test_files_petscii) emulator/run-in-vice.sh
|
||||
$(test_logs): $(test_files_petscii) $(wildcard emulator/run-in-*.sh)
|
||||
|
||||
test-v4thblk-c64.log: emulator/v4thblk-c64.T64 disks/empty.d64
|
||||
rm -f cbmfiles/test.log disks/scratch.d64
|
||||
cp disks/empty.d64 disks/scratch.d64
|
||||
DISK9=scratch emulator/run-in-vice.sh v4thblk-c64 \
|
||||
"include run-blk-tests.fth\n1234567890"
|
||||
"include run-blk-tests.fth\n$(test_keyboard_input)"
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4th-c64.log: emulator/v4th-c64.T64
|
||||
rm -f cbmfiles/test.log
|
||||
emulator/run-in-vice.sh v4th-c64 \
|
||||
"include run-std-tests.fth\n1234567890"
|
||||
"include run-std-tests.fth\n$(test_keyboard_input)"
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4thblk-c16+.log: emulator/v4thblk-c16+.T64 disks/empty.d64
|
||||
rm -f cbmfiles/test.log disks/scratch.d64
|
||||
cp disks/empty.d64 disks/scratch.d64
|
||||
VICE=xplus4 DISK9=scratch emulator/run-in-vice.sh v4thblk-c16+ \
|
||||
"include run-blk-tests.fth\n1234567890"
|
||||
"include run-blk-tests.fth\n$(test_keyboard_input)"
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4th-c16+.log: emulator/v4th-c16+.T64
|
||||
rm -f cbmfiles/test.log
|
||||
VICE=xplus4 emulator/run-in-vice.sh v4th-c16+ \
|
||||
"include run-std-tests.fth\n1234567890"
|
||||
"include run-std-tests.fth\n$(test_keyboard_input)"
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4thblk-c16-.log: emulator/v4thblk-c16-.T64
|
||||
rm -f cbmfiles/test.log
|
||||
VICE=xplus4 emulator/run-in-vice.sh v4thblk-c16- \
|
||||
"include run-min-tests.fth\n1234567890"
|
||||
"include run-min-tests.fth\n$(test_keyboard_input)"
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4th-c16-.log: emulator/v4th-c16-.T64
|
||||
rm -f cbmfiles/test.log
|
||||
VICE=xplus4 emulator/run-in-vice.sh v4th-c16- \
|
||||
"include run-std-tests.fth\n1234567890"
|
||||
"include run-std-tests.fth\n$(test_keyboard_input)"
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4th-x16.log: cbmfiles/v4th-x16 emulator/sdcard.img
|
||||
test-v4th-x16.log: cbmfiles/v4th-x16 | emulator/sdcard.img
|
||||
rm -f cbmfiles/test.log
|
||||
emulator/run-in-x16emu.sh v4th-x16 \
|
||||
"include run-std-tests.fth\n1234567890"
|
||||
"include run-std-tests.fth\n$(test_keyboard_input)"
|
||||
mcopy -i emulator/sdcard.img ::TEST.LOG cbmfiles/test.log
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4th-x16e.log: cbmfiles/v4th-x16e emulator/sdcard.img
|
||||
test-v4th-x16e.log: cbmfiles/v4th-x16e | emulator/sdcard.img
|
||||
rm -f cbmfiles/test.log
|
||||
emulator/run-in-x16emu.sh v4th-x16e \
|
||||
"include run-std-tests.fth\n1234567890"
|
||||
"include run-std-tests.fth\n$(test_keyboard_input)"
|
||||
mcopy -i emulator/sdcard.img ::TEST.LOG cbmfiles/test.log
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
@ -190,35 +206,60 @@ emulator/sdcard.img: emulator/sdcard.sfdisk
|
||||
mv $@.tmp $@
|
||||
|
||||
test-v4thblk-c64.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double block report-blk)
|
||||
prelim mycore-echo coreext double block report-blk)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4th-c64.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double report-noblk)
|
||||
prelim mycore-echo coreext double report-noblk)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4thblk-c16+.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double block report-blk)
|
||||
prelim mycore-echo coreext double block report-blk)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4th-c16+.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double report-noblk)
|
||||
prelim mycore-echo coreext double report-noblk)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4thblk-c16-.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core)
|
||||
prelim mycore-echo)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4th-c16-.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double report-noblk)
|
||||
prelim mycore-echo coreext double report-noblk)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4th-x16.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double report-noblk)
|
||||
prelim mycore-noecho coreext double report-noblk)
|
||||
cat $^ > $@
|
||||
|
||||
test-v4th-x16e.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim core coreext double report-noblk)
|
||||
prelim mycore-noecho coreext double report-noblk)
|
||||
cat $^ > $@
|
||||
|
||||
tests/golden/mycore-echo.golden: tests/golden/core-template.golden
|
||||
sed -e 's/TMPL_KEYS_ECHO_TMPL/$(test_keyboard_input)/' \
|
||||
-e 's/TMPL_KEYS_RECEIVED_TMPL/$(test_keyboard_input)/' $< >$@
|
||||
|
||||
tests/golden/mycore-noecho.golden: tests/golden/core-template.golden
|
||||
sed -e 's/TMPL_KEYS_ECHO_TMPL//' \
|
||||
-e 's/TMPL_KEYS_RECEIVED_TMPL/$(test_keyboard_input)/' $< >$@
|
||||
|
||||
# Sample test with a changed input that would run the tasker
|
||||
# even while waiting for keyboard input:
|
||||
test-v4th-x16-tsk.log: cbmfiles/v4th-x16 \
|
||||
$(test_files_petscii) $(wildcard emulator/run-in-*.sh) \
|
||||
cbmfiles/6502asm.fth cbmfiles/trns6502asm.fth \
|
||||
cbmfiles/vf-lbls-cbm.fth cbmfiles/x16input-tsk.fth \
|
||||
| emulator/sdcard.img
|
||||
rm -f cbmfiles/test.log
|
||||
emulator/run-in-x16emu.sh v4th-x16 \
|
||||
"include x16input-tsk.fth\ninclude run-min-tests.fth\n$(test_keyboard_input)"
|
||||
mcopy -i emulator/sdcard.img ::TEST.LOG cbmfiles/test.log
|
||||
petscii2ascii cbmfiles/test.log $@
|
||||
|
||||
test-v4th-x16-tsk.golden: $(patsubst %, tests/golden/%.golden, \
|
||||
prelim mycore-echo)
|
||||
cat $^ > $@
|
||||
|
||||
# Rules for building Forth binaries on top of the plain vanilla
|
||||
|
@ -1,6 +1,8 @@
|
||||
# VolksForth 6502 C64 Releases
|
||||
# VolksForth 6502-C64 Releases
|
||||
|
||||
Release notes of VolksForth for 6502 on CBM-like machines (C64/C16/X16)
|
||||
Release notes of VolksForth 6502-C64 which is the flavour of VolksForth
|
||||
running on CBM-like 6502 machines - currently the C64, the C16/Plus4 and the
|
||||
Commander X16.
|
||||
|
||||
## Release content
|
||||
|
||||
@ -18,11 +20,44 @@ The latest release zip file `volksforth-6502-c64-release.zip` contains
|
||||
* `v4th-x16e` - Commander X16 kernel with added X16Edit and
|
||||
DOS commands
|
||||
|
||||
* `doc/` - documentation, the beginning of an English translation
|
||||
of the original German VolksForth/UltraForth manual for C64 and C16,
|
||||
with some X16 specifics added.
|
||||
* [`tasker.md`](doc/tasker.md) - the chapter about the multitasker
|
||||
|
||||
* `src/` - sources
|
||||
* `v4th*.fth` - the binaries' main files
|
||||
* `vf-*.fth` - sources from which VolksForth
|
||||
kernels are compiled
|
||||
* further Forth sources
|
||||
* `6502asm.fth` - the 6502 assembler, needed to compile `Code` words
|
||||
* `trns6502asm.fth` - the transient 6502 assembler. It lives on the
|
||||
heap and is removed by `clear`. This allows building applications that
|
||||
have code words but don't carry the assembler itself after saving.
|
||||
* `tmp6502asm.fth` - like the transient 6502 assembler, but living on the
|
||||
tmpheap instead of the heap. See below for tmpheap.
|
||||
* `rom-ram-c16.fth` - macros for C16 bank switching
|
||||
* `rom-ram-c64.fth` - macros for C64 bank switching
|
||||
* `tracer.fth` - the debugger
|
||||
* `tasker.fth` - the multitasker
|
||||
* `multitask.fth` - the small bit of assembly code needed by tasker.fth
|
||||
* `taskdemo.fth` - a C64/C16 demo of the tasker
|
||||
* `taskdemo-x16.fth` - a X16 demo of the tasker
|
||||
* `x16input-tsk.fth`- The usual v4th X16 keyboard input uses the regular
|
||||
screen editor for line input, so no task switches happen during line input.
|
||||
This input implementation allows task switches during input but uses Kernal
|
||||
variables and has a cursor bug after backspace.
|
||||
* `cbmopen.fth` - Forth words for Kernal channel I/O
|
||||
* `lists.fth` - two list utility words
|
||||
* `profiler.fth` - *** [4d2023-04](https://forth-ev.de/wiki/res/lib/exe/fetch.php/vd-archiv:4d2023-04.pdf) (English)
|
||||
* `tmpheap.fth` - the reference implementation of the tmpheap design
|
||||
as described at
|
||||
[SVFIG 04-2021](https://www.forth.org/svfig/kk/04-2021.html), in the
|
||||
[4d2021-03](https://forth-ev.de/wiki/res/lib/exe/fetch.php/vd-archiv:4d2021-03.pdf) (German) and used
|
||||
in [cc64](https://github.com/pzembrod/cc64/blob/master/src/cc64/cc64.fth#L11)
|
||||
* `x16tmpheap.fth` - a X16 tmpheap implementation that uses banked ram
|
||||
* `notmpheap.fth` - a null implementation that redirects the tmpheap
|
||||
to the regular VolksForth heap
|
||||
* `tc-base.fth` - loadfile for the resident part of the target compiler
|
||||
|
||||
* `src_petscii/` - the files from `src/` converted to PETSCII
|
||||
|
||||
@ -31,14 +66,82 @@ The latest release zip file `volksforth-6502-c64-release.zip` contains
|
||||
* `tests_petscii/` - the files from `tests/` converted to PETSCII
|
||||
|
||||
## Versions
|
||||
The following version descriptions are only valid for VolksForth 6502
|
||||
C64 Releases. As of now (Dec 2023), the different VolksForth platforms
|
||||
|
||||
The following version descriptions are only valid for VolksForth 6502-C64
|
||||
releases. As of now (June 2024), the different VolksForth platforms
|
||||
(6502, 68k, 8080, 8086) don't have shared code or shared versioning.
|
||||
|
||||
### 6502-C64 3.9.6
|
||||
|
||||
Main topic of this release is the removal of all usages of Kernal variable
|
||||
uses esp. in the X16 VolksForth kernel. Because the addresses of Kernal
|
||||
variables can change between different X16 Kernal releases, their use was in
|
||||
the past the main reason why VolksForth broke after new X16 ROM releases.
|
||||
|
||||
With Kernal variable access replaced by Kernal API calls or by emitting
|
||||
control characters, the VolksForth kernel should now be much more robust
|
||||
when the X16 Kernal changes.
|
||||
|
||||
A secondary topic if this release is more bundled Forth sources, which are
|
||||
now also better described (see Release content above).
|
||||
|
||||
And a third topic is the beginning of an English translation of the
|
||||
original German VolksForth/UltraForth manual for C64 and C16.
|
||||
Since this release affects some multitasking behaviour, the translation
|
||||
was started with the [chapter about the multitasker](doc/tasker.md).
|
||||
|
||||
Changes affecting only the X16 VolksForth kernel:
|
||||
|
||||
* Clearing the IOStatus is now possible through the ExtApi call ($FEAB, thanks
|
||||
to mooinglemur for implementing this), so the dependency on the address of
|
||||
IOStatus could be removed.
|
||||
* The implementation of line input in EXPECT was changed from switching cursor
|
||||
on and off and using GETIN to using BASIN - which automatically handles the
|
||||
cursor and also makes use of the CBM screen editor. The Kernal var dependency
|
||||
that came with switching the cursor on and off is now removed.
|
||||
The downside is that the
|
||||
cooperative multitasker now can't run tasks during line input. The old
|
||||
tasker-compatible EXPECT is now available as separtate source
|
||||
x16input-tsk.fth. For details on this see [tasker.md](doc/tasker.md).
|
||||
* The clearing of the Kernal variables QtSw and Insrt after each
|
||||
char written to the console via CHROUT most likely has no real purpose.
|
||||
It was therefore removed from the X16 variant.
|
||||
* Up to version 3.9.5, the VolksForth kernel used BkgPenCol (X16: $0376)
|
||||
to set both background and pen color during initialization. It would be
|
||||
great ot have e.g. an ExtApi function to set BkgPenCol, similar to the
|
||||
X16 BASIC command `COLOR`. I'm planning to suggest this,
|
||||
but for the time being setting the background and pen color is
|
||||
instead done via PETSCII control codes instead. To reflect this change,
|
||||
the CBM VolksForth word `INK-POT` has been renamed to `X16-INK-POT`,
|
||||
and it contains only 3 values (border color code, background color PETSCII
|
||||
control charcter, pen color PETSCII control character. This removes the
|
||||
dependency on BkgPenCol and thereby on the last remaining Kernal variable
|
||||
that was used by VolksForth.
|
||||
|
||||
Changes affecting all VolksForth kernels (C64, C16, X16):
|
||||
|
||||
* The direct clearing of MsgFlg (X16: $028d) at the beginning of
|
||||
(busin and (busout was removed; it shouldn't have had any real purpose.
|
||||
|
||||
The cooperative multitasker was extracted from the original disk 3 (see
|
||||
[`disks/vforth4_3.fth`](https://github.com/forth-ev/VolksForth/blob/master/6502/C64/disks/vforth4_3.fth))
|
||||
into the files `tasker.fth, multitask.fth` and `taskdemo.fth`. The latter was
|
||||
ported to the X16 as `taskdemo-x16.fth`.
|
||||
|
||||
`rom-ram-sys.fth` was split up into a C64 and a C16 flavour. There is no X16
|
||||
equivalent; X16 bank switching poses challenges and opportunities completely
|
||||
different from those on C16 and C64.
|
||||
|
||||
New sources added: `lists,fth, tasker.fth, multitask.fth,
|
||||
taskdemo.fth, taskdemo-x16.fth, x16input-tsk.fth, tmp6502asm.fth,
|
||||
x16tmpheap.fth, rom-ram-c16.fth, rom-ram-c64.fth`
|
||||
|
||||
### 6502-C64 3.9.5
|
||||
|
||||
This release adapts the X16 VolksForth to the R46 ROM.
|
||||
It also adds an X16 binary with added words to invoke the
|
||||
This release adapts the X16 VolksForth kernel to the R46 X16 ROM.
|
||||
July 2024 note: version 3.9.5 also runs with the R47 ROM.
|
||||
|
||||
The release also adds an X16 binary with added words to invoke the
|
||||
ROM-based X16Edit (XED), to list directories and files (DIR and CAT)
|
||||
and to issue DOS commands and read the error channel (DOS).
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
589
6502/C64/doc/tasker.md
Normal file
589
6502/C64/doc/tasker.md
Normal file
@ -0,0 +1,589 @@
|
||||
|
||||
# The Multitasker
|
||||
|
||||
VolksForth comes with a simple but powerful multitasker which allows the
|
||||
creation of printer spoolers, clocks, counters and other simple background
|
||||
tasks.
|
||||
|
||||
The main characteristic of this multitasker is that it uses cooperative
|
||||
multitasking instad of preemtive multitasking.
|
||||
This means that each task has to explicitly yield
|
||||
execution control and access to I/O devices to make them available for other
|
||||
tasks. However, each task can choose when this happens, esp. when to yield
|
||||
execution control. Of course this must happen often enough for all tasks
|
||||
to work well. Execution control is yielded via the word PAUSE.
|
||||
|
||||
## Motivating Use Case
|
||||
|
||||
Block 74 of [Disk 3](../disks/vforth4_3.fth) of the original
|
||||
VolksForth/UltraForth distribution contains a print spooler that creates a task
|
||||
`Printspool` to print a range of source blocks via `pthru` in the background
|
||||
while the user can still interact with the system in the foreground.
|
||||
|
||||
Caveat: The printer code hasn't yet been extracted into `.fth` files and may
|
||||
need some adaption to current VolksForth versions and esp. to the X16.
|
||||
In particular, source block printing doesn't make much sense with the X16 as of
|
||||
now because block source compiling is currently only supported on the C64 and
|
||||
C16/Plus4.
|
||||
|
||||
## Task Demo
|
||||
|
||||
A simpler task demo has been extracted from Disk 3's block 62 into
|
||||
[src/taskdemo.fth](../src/taskdemo.fth).
|
||||
|
||||
### On C64 or C16/Plus4
|
||||
```
|
||||
include tasker.fth
|
||||
include taskdemo.fth
|
||||
```
|
||||
will create a counter in the top left corner, counting down in the background
|
||||
from 256 to 0. A fun way to see the time spent in the background task is to
|
||||
type
|
||||
```
|
||||
words
|
||||
```
|
||||
while the counter is running: The speed of words listing will increase
|
||||
noticably once the counter has run out.
|
||||
|
||||
### On the X16
|
||||
|
||||
On the X16 things are slightly different:
|
||||
```
|
||||
include tasker.fth
|
||||
include taskdemo-x16.fth
|
||||
```
|
||||
will create a counter in the top left corner, counting down in the background
|
||||
from 4096 to 0. However, unlike on C64/C16/Plus4 this counter doesn't run while
|
||||
the cursor is prompting for user input. Pressing repeated RETURNs or typing
|
||||
`words`
|
||||
will cause the counter to proceed, but it'll stop again on the input prompt.
|
||||
|
||||
This is because since version 3.9.6 the line input in EXPECT uses BASIN, i.e.
|
||||
delegates the input wait to the CBM screen editor which only returns to
|
||||
Forth code after RETURN is pressed, which means that until then PAUSE isn't
|
||||
called and execution control isn't yielded to other tasks.
|
||||
|
||||
An alternative EXPECT is available in `x16input-tsk.fth` with the EXPECT
|
||||
implementation of versions 3.9.5 and prior, similar to the C64/C16/Plus4
|
||||
EXPECT, which implements the input loop in Forth, with a PAUSE call. On the
|
||||
X16 this has the disadvantages that it uses a Kernal variable that could change
|
||||
between Kernal versions, and has a bug that often leaves inverted spaces after
|
||||
backspace is pressed. This being said,
|
||||
```
|
||||
include x16input-tsk.fth
|
||||
```
|
||||
after starting `taskdemo-x16.fth` will cause the counter to start running even
|
||||
while waiting for input.
|
||||
|
||||
Typing `keyboard` will activate the original X16 EXPECT again and stop the
|
||||
counter; typing `tasker-keyboard` will reactivate the task-switching EXPECT
|
||||
and start the counter again.
|
||||
|
||||
## Implementation
|
||||
|
||||
As mentioned, the multitasker uses cooperative multitasking where
|
||||
execution control is yielded via the word PAUSE. PAUSE saves the current state
|
||||
of the currently active task and calls the task switcher. The state of a task
|
||||
consists of the values of the Instruction Pointer (IP),
|
||||
Return stack Pointer (RP) and Stack Pointer (SP).
|
||||
|
||||
The task switcher consists of a closed round-robin loop made up of the
|
||||
first 6 bytes of the user area of each task.
|
||||
See the picture [Tasks' user areas](#tasks-user-areas) in the
|
||||
[Memory map](#memory-map) section.
|
||||
Each task's user area starts with a machine code jump to
|
||||
the next task's user area (`JMP XXXX` in the picture), followed by
|
||||
`JSR wake`. `wake` is the task wake-up routine which sets UP to the task's
|
||||
user area address calculated from return address left by the `jsr`,
|
||||
restores SP from `user area + 6`and then restores RP and IP from the task's
|
||||
data stack. The task's state is thereby restored, and the next iteration of
|
||||
`NEXT` will call the task's next word, the one following the `PAUSE` that was
|
||||
last invoked by the task.
|
||||
|
||||
A trick is employed to switch a task between active and inactive.
|
||||
The JMP XXXX instruction at the user area's start, as described above, marks
|
||||
an inactive task. When the round-robin loop reaches the task, the JMP
|
||||
immediately forwards execution to the next task; the `JSR wake` is never
|
||||
reached. For an active task, the JMP opcode is replaced by a BIT opcode (0x2c),
|
||||
so that, when the task is jumped to, execution does reach the `JMP wake`
|
||||
instruction, and the task runs until its reaaches the next `PAUSE`, which takes
|
||||
the address of the BIT instruction for an indirect jump to the next task.
|
||||
|
||||
`SINGLETASK` changes `PAUSE` into a `NOOP` so that no task change at all
|
||||
takes place when `PAUSE` is called. This is the default of a VolksForth
|
||||
system without loaded multitasker. `MULTITASK` enables the task-switching
|
||||
behaviour of `PAUSE`.
|
||||
|
||||
The system supports the multitasker by invoking `PAUSE` during many I/O
|
||||
operations such as `KEY`, `TYPE` and `BLOCK`. In many situations this is
|
||||
already sufficient for a task (e.g. the printer pooler) to run smoothly.
|
||||
In other situations a suitable placement of `PAUSE` calls within foreground
|
||||
or background task code may be useful.
|
||||
|
||||
Tasks are created in the dictionary of the foreground or console task. Each
|
||||
task has its own user area with a copy of the user variables.
|
||||
The implementation of the system is, however, simplified through the
|
||||
restriction that only the console task can interpret or compile input text.
|
||||
There is e.g. only one vocabulary search order across the system; if one task
|
||||
changes the search order, this affects all other tasks, too. But this is not
|
||||
really disturbing, since only the console task should use the search order
|
||||
anyway.
|
||||
|
||||
Incidentally, it is possible to forget active tasks: `FORGET` removes all
|
||||
tasks from the round-robin loop that are located in the dictionary range to
|
||||
forget. This can still go wrong, though, if the forgotten task holds a
|
||||
"Semaphor" (see below). Semaphores are not released during forgetting,
|
||||
and the associated device will remain blocked.
|
||||
|
||||
Finally, it should be mentioned that when invoking a task name, the address
|
||||
of the task's user area will be placed on the stack.
|
||||
|
||||
## Memory map
|
||||
|
||||
The memory used by VolksForth ranges from
|
||||
`ORIGIN` to `LIMIT` . Below `ORIGIN` are the
|
||||
Kernal variables, the screen memory and a single line of
|
||||
BASIC with a `SYS` command that starts VolksForth.
|
||||
Beyond `LIMIT` are I/O ports and the Kernal ROM.
|
||||
|
||||
Just below `LIMIT` the block buffers are stored; each with a size
|
||||
of 1 Kbyte tall. When the system starts, as many buffers are
|
||||
allocated as fit between `R0` and `LIMIT`.
|
||||
|
||||
The rest of the system, located between `ORIGIN` and `RO`, consists of
|
||||
two areas. The upper area contains the return stack (growing downwards,
|
||||
starting at `RO @`) and the user area (growing upwards, starting at `UP@`).
|
||||
|
||||
The dictionary and the data stack plus the heap occupy the other area.
|
||||
Heap and data stack grow downwards, the heap from `UP@` and the data stack
|
||||
from `S0 @`.
|
||||
When the heap grows, the data stack is automatically moved downwards.
|
||||
New words are stored in the dictionary, which is the fastest-growing
|
||||
part of the system during compilation. Therefore the system automatically
|
||||
checks that dictionary and data stack don't collide.
|
||||
|
||||
The Bootarea finally contains the initial values of the user
|
||||
variables, which is copied during the cold start from there into the
|
||||
console task's user area.
|
||||
|
||||
#### Overall memory map
|
||||
|
||||
```
|
||||
0xFFFF -> ╔════════════════════╗
|
||||
║ I/O and ROM ║
|
||||
║ (starts at 0x8000, ║
|
||||
║ 0x9F00, 0xD000 or ║
|
||||
║ 0xFD00 depending ║
|
||||
║ on platform) ║
|
||||
limit -> ╠════════════════════╣
|
||||
║ buffers ║
|
||||
first @ -> ╠════════════════════╣
|
||||
║ (unused) ║
|
||||
r0 @ -> ╠════════════════════╣ ─────
|
||||
║ return stack ║ ⋀
|
||||
rp@ -> ╠═════════════════|══╣ |
|
||||
║ ⋁ ║
|
||||
║ free ║ rlen
|
||||
║ ⋀ ║
|
||||
╠═════════════════|══╣ |
|
||||
║ user area ║ ⋁
|
||||
up@ -> ╠════════════════════╣ ─────
|
||||
║ heap ║ ⋀
|
||||
heap -> ╠════════════════════╣ |
|
||||
║ (stack underflow) ║
|
||||
s0 @ -> ╠════════════════════╣
|
||||
║ stack ║
|
||||
sp@ -> ╠═════════════════|══╣ slen
|
||||
║ ⋁ ║
|
||||
║ free ║
|
||||
║ ⋀ ║
|
||||
here -> ╠═════════════════|══╣
|
||||
║ ║
|
||||
║ dictionary ║
|
||||
║ ║
|
||||
╠════════════════════╣ |
|
||||
║ boot area ║ ⋁
|
||||
origin -> ╠════════════════════╣ ─────
|
||||
║ 10 SYS (2064) ║ SYS (4112) on the C16
|
||||
╠════════════════════╣
|
||||
║ video memory ║
|
||||
╠════════════════════╣
|
||||
║ Kernal vars ║
|
||||
║ 6502 ZP, stack ║
|
||||
╚════════════════════╝
|
||||
```
|
||||
|
||||
#### 6502 zero page
|
||||
|
||||
The system also uses zero page memory, with the inner interpreter `NEXT`
|
||||
and the stack pointers `RP` and `SP`, among others.
|
||||
|
||||
|
||||
|Label | C64 | C16 | X16 |
|
||||
|-------|-------|-------|-------|
|
||||
|N |0x0029 |0x0029 |0x0067 |
|
||||
|W |0x0021 |0x0021 |0x006F |
|
||||
|IP |0x000E |0x000E |0x005C |
|
||||
|NEXT |0x0009 |0x0009 |0x0057 |
|
||||
|SP |0x0007 |0x0007 |0x0055 |
|
||||
|Put A |0x0006 |0x0006 |0x0054 |
|
||||
|UP |0x0004 |0x0004 |0x0052 |
|
||||
|RP |0x0002 |0x0002 |0x0050 |
|
||||
|
||||
|
||||
|
||||
#### Memory map of a task
|
||||
```
|
||||
r0 @ -> ╔════════════════════╗ ─────
|
||||
║ return stack ║ ⋀
|
||||
rp@ -> ╠═════════════════|══╣ |
|
||||
║ ⋁ ║
|
||||
║ free ║ rlen
|
||||
║ ⋀ ║
|
||||
╠═════════════════|══╣ |
|
||||
║ user area ║ ⋁
|
||||
up@ -> ╠════════════════════╣ ─────
|
||||
║ heap ║ ⋀
|
||||
heap -> ╠════════════════════╣ |
|
||||
║ (stack underflow) ║
|
||||
s0 @ -> ╠════════════════════╣
|
||||
║ stack ║
|
||||
sp@ -> ╠═════════════════|══╣ slen
|
||||
║ ⋁ ║
|
||||
║ free ║
|
||||
║ ⋀ ║
|
||||
here -> ╠═════════════════|══╣ |
|
||||
║ dictionary ║ ⋁
|
||||
╚════════════════════╝ ─────
|
||||
```
|
||||
There's a small unused area of 6 bytes between stack and heap to prevent heap
|
||||
corruption in case of a small stack underrun.
|
||||
|
||||
And typically, the dictionary of any task but the console task will be empty,
|
||||
as that is where the outer interpreter is running which usally populates the
|
||||
dictionary through definitions. However, `DP` is a user variable, so each task
|
||||
has its own `HERE`, and if a task calls `ALLOT`, the memory will be allocated
|
||||
in its own dictionary.
|
||||
|
||||
#### Tasks' user areas
|
||||
|
||||
A task is characterized by the address of its user area. The tasker's round
|
||||
robin loop consists of
|
||||
|
||||
|
||||
```
|
||||
task 3: jmp XXXX => task is sleeping
|
||||
|
||||
│ ... │ task3 + 6
|
||||
├───────────┤
|
||||
│ jsr wake │ task3 + 3
|
||||
├───────────┤
|
||||
┌> -> -> │ jmp XXXX │-> ┐ task3 + 0
|
||||
⋀ └───────────┘ ⋁
|
||||
| ┌ <- <- <-- <- <- <┘
|
||||
⋀ ⋁
|
||||
| | task 2: bit XXXX => task is active
|
||||
⋀ ⋁
|
||||
| | │ ... │ task2 + 6
|
||||
⋀ ⋁ ├───────────┤
|
||||
| | │ jsr wake │ task2 + 3
|
||||
⋀ ⋁ ├───────────┤
|
||||
| └> │ bit XXXX │-> ┐ task2 + 0
|
||||
⋀ └───────────┘ ⋁
|
||||
| ┌ <- <- <-- <- <- <┘
|
||||
⋀ ⋁
|
||||
| | task 1: bit XXXX => task is active
|
||||
⋀ ⋁
|
||||
| | │ ... │ task1 + 6
|
||||
⋀ ⋁ ├───────────┤
|
||||
| | │ jsr wake │ task1 + 3
|
||||
⋀ ⋁ ├───────────┤
|
||||
| └> │ bit XXXX │-> ┐ task1 + 0
|
||||
⋀ └───────────┘ ⋁
|
||||
└ <- <- <- <- <-- <- <- <┘
|
||||
```
|
||||
|
||||
## Semaphores and LOCK
|
||||
|
||||
A problem that has not yet been mentioned: what happens when two tasks want to
|
||||
print or access the disk drive simultaneously? Obviously, I/O devices may
|
||||
at any time be used by only one task. This is achieved using Semaphores:
|
||||
|
||||
```
|
||||
Create disp 0,
|
||||
: newtype disp lock type disp unlock;
|
||||
```
|
||||
|
||||
This has the following effect:
|
||||
|
||||
If two tasks call `NEWTYPE` at the same time, still only task at a time will
|
||||
get to run `TYPE`, regardless of how many `PAUSE` are included in `TYPE`.
|
||||
The phrase `DISP LOCK` will set up a barrier after the first task that performs
|
||||
it, like switching a traffic light to red, and lets no other task pass.
|
||||
The other task is held until the first task switches the traffic light to
|
||||
green again via `DISP UNLOCK`. Then one (!) other task can pass the traffic
|
||||
light, switching it red again, and so on.
|
||||
|
||||
By the way, the task that switched the traffic lights to red will not be
|
||||
stopped by another `DISP LOCK` but will be let through. This is
|
||||
necessary since `TYPE` could also contain a `DISP LOCK`.
|
||||
(It doesn't in the above example, but it is conceivable.)
|
||||
|
||||
The implementation looks like this:
|
||||
(Remember that every task is uniquely identifiable by the its user area
|
||||
address.)
|
||||
|
||||
`DISP` is the so-called Semaphore; it must have the initial value 0.
|
||||
|
||||
`LOCK` looks at the Semaphore:
|
||||
If it is zero, then the currently asctive task (i.e. its user area address)
|
||||
is written to the semaphore, and the task may continue on its way.
|
||||
If the value of the semaphore is the active task, then it may continue, too.
|
||||
But if the value of the semaphore deviates from the active task's user area
|
||||
address, then another task is active behind the traffic light, and the task
|
||||
must `PAUSE` until the light turns green again, i.e. until the semaphore is
|
||||
zero.
|
||||
|
||||
`UNLOCK` has nothing more to do than to set the value of the semaphore back to
|
||||
zero.
|
||||
|
||||
`BLOCK` and `BUFFER` are, by the way, secured in this way for use by several
|
||||
tasks:
|
||||
only one task can request the loading of a block from the diskette at any given
|
||||
time.
|
||||
Whether `TYPE`, `EMIT`, etc. are also secured depends on their implementation -
|
||||
`TYPE`, `EMIT`, etc are essentially deferred words with different possible
|
||||
implementations.
|
||||
|
||||
## Remarks regarding BLOCK and a few other things
|
||||
|
||||
As can be seen from the glossary, only the address of the block buffer last
|
||||
requested with `BLOCK` or `BUFFER` is valid, i.e. older blocks, depending on
|
||||
the number of block buffers, may already be stored on the disk again. To be
|
||||
on the safe side, it is useful to imagine that only one block buffer exists
|
||||
in the entire system.
|
||||
|
||||
Now any task can run `BLOCK` and thus remove blocks from "under the feet"
|
||||
of other tasks.
|
||||
Therefore, one should not continue to use the address of a block after calling
|
||||
a word that performs `PAUSE` performs. One should rather request the block
|
||||
using `BLOCK` again. An example:
|
||||
|
||||
```
|
||||
: .line ( block -- )
|
||||
block c/l bounds DO I c@ emit LOOP ;
|
||||
```
|
||||
|
||||
is WRONG because after `EMIT` the address range the address range that the
|
||||
loop index steps through may no longer be correct.
|
||||
|
||||
```
|
||||
: .line ( block -- )
|
||||
c/1 0 DO dup block I + c@ emit LOOP drop ;
|
||||
```
|
||||
|
||||
is CORRECT because it only keeps the number of the block, not the address of
|
||||
its buffer.
|
||||
|
||||
```
|
||||
: .line ( block -- ) block c/l type ;
|
||||
```
|
||||
is WRONG since `TYPE` may call `EMIT` repeatedly, and thus the address
|
||||
delivered by `BLOCK` may become invalid during `TYPE`.
|
||||
|
||||
```
|
||||
: >type ( adr len -- ) >r pad r@ cmove pad r> type ;
|
||||
: .line -( block -—) block c/l >type ;
|
||||
```
|
||||
is CORRECT because `PAD` is different for each task.
|
||||
|
||||
In version 3.8 the word LIST was changed in such a way that it can be stopped
|
||||
and terminated by pressing buttons, similar to `INDEX`. This entails certain
|
||||
problems when this word is used in a task (e.g. a printer pooler). In this
|
||||
case, both the console task and the tasks containing the word LIST attempt
|
||||
to read inputs from the keyboard. If you type a text, the individual
|
||||
characters are randomly distributed to the two tasks. Therefore, each task
|
||||
(of course with the exception of the console task) should define its input
|
||||
vector so that you cannot receive inputs.
|
||||
|
||||
The following code snippet contains an input vector that does not allow inputs.
|
||||
See section Vectors in chapter Vectors and Deferred Words about defining
|
||||
input or output vectors using `Input:` or `Output:`.
|
||||
TODO: Add link once chapter Vectors and Deferred Words is translated.
|
||||
|
||||
```
|
||||
: halt ." Task gestoppt!” stop ; \ completely stops the task
|
||||
|
||||
Input: nul-Input halt false drop halt ;
|
||||
\ instead of: key key? decode expect
|
||||
```
|
||||
|
||||
Another implementation of `KEY` for background tasks could be one that always
|
||||
return a constant harmless character. Whether that works and with which
|
||||
character must of course be decided for each application.
|
||||
With `EXPECT` it is hard to envision a better solution, since `EXPECT` is
|
||||
intended to change the `SPAN` variable which is a global variable, not a
|
||||
per-task user variable.
|
||||
|
||||
One more note: A background task should not perform `ABORT"` or a similar word.
|
||||
If it did, the task would become like the console task, resulting in a system
|
||||
crash. Even if this possibility of error is intercepted and the task is
|
||||
stopped, the problem remains that semaphores can still be "locked" on this task
|
||||
and thus the use of certain parts of the forth remains blocked!
|
||||
|
||||
## Glossary
|
||||
|
||||
Multitasker words
|
||||
|
||||
#### `'s ( Tadr -- usradr )` "tick-s"
|
||||
|
||||
is used in the form:
|
||||
|
||||
```
|
||||
<taskname> ’s <uname> ...
|
||||
```
|
||||
|
||||
reads the name of a user variable `<uname>` and leaves the address `usradr` of
|
||||
this user variable in the task marked by `Tadr`.
|
||||
|
||||
Tadr is usually generated by calling `<taskname>`. An error condition exists
|
||||
if `<uname>` is not the name of a user variable.
|
||||
See also `USER` and `TASK`. `’S` is intended for changing the content of user
|
||||
variables of a task by another task.
|
||||
|
||||
#### `activate ( Tadr -- )`
|
||||
|
||||
activates the task marked by `Tadr` and wakes it up. `Tadr` is usually
|
||||
generated by calling a task name.
|
||||
See also `SLEEP` , `STOP` , `PASS` , `PAUSE` , `UP@` , `UP` and `WAKE`.
|
||||
|
||||
#### `lock ( semadr -- )`
|
||||
|
||||
The semaphore with address `semadr` is blocked by the task that calls `LOCK`.
|
||||
To do this, `LOCK` checks the contents of `semadr`. If the content indicates
|
||||
that another task has blocked the semaphore, `PAUSE` will be executed until
|
||||
the semaphore is released. When the semaphore is released, `LOCK` writes the
|
||||
identifier of the task performing `LOCK` into the semaphore, thus blocking it
|
||||
for all other tasks. So the code between `semadr LOCK` and `semadr UNLOCK`
|
||||
can always be executed byonly one task at a time. See also `UNLOCK` and the
|
||||
description of the [tasker](tasker.md#semaphores-and-lock).
|
||||
|
||||
#### `multitask ( -- )`
|
||||
|
||||
switches multitasking on. After `MULTITASK` has been executed, the word `PAUSE`
|
||||
is no longer a `NOOP`. Instead, it yields control of the CPU to another task.
|
||||
|
||||
#### `pass (n0 ... nr-1 Tadr r -- )`
|
||||
|
||||
activates the task marked by `Tadr` and wakes it up. `Tadr` is usually
|
||||
generated by calling a task name. `r` indicates the number of parameters
|
||||
`nO` to `nr-1?` which are transferred from the stack of the task calling `PASS`
|
||||
to the stack of the task identified by `Tadr`. The parameters `nO` to `nr-1`
|
||||
are available to the task identified by `Tadr` for further use.
|
||||
See also `STOP`, `ACTIVATE`, `PAUSE`, `UP@` and `UP!`.
|
||||
|
||||
#### `pause ( -- )`
|
||||
|
||||
a `NOOP`-word when single task mode is active. However, when multitasking is
|
||||
activated, the task that performs `PAUSE` will yield control of the CPU to
|
||||
another task. If there is only one task, or if all other tasks are asleep,
|
||||
control will be returned to the task performin `PAUSE`. If at least one other
|
||||
task is active, it will take overcontrol of the CPU, and will only yield it
|
||||
again to another task when it calls `PAUSE` or `STOP`. Since the tasks are
|
||||
linked to each other in a closed loop, the task that first performed `PAUSE`
|
||||
will eventually gain control agian. An error condition exists if a task
|
||||
never calls `PAUSE` or `STOP`. See also `STOP`, `MULTITASK` and `SINGLETASK`.
|
||||
|
||||
#### `rendezvous ( semadr -- )`
|
||||
|
||||
releases the semaphore with the address `semadr` and calls `PAUSE` in order to
|
||||
allow other tasks to access the device which has been protected by this
|
||||
semaphore. Then, `LOCK` is called in order to regain control of the device.
|
||||
See als `LOCK` and `UNLOCK`.
|
||||
|
||||
#### `singletask ( -- )`
|
||||
|
||||
turns off multitasking. The word `PAUSE` is a `NOOP` word after `SINGLETASK`
|
||||
has been run. An error condition exists if a background task calls `SINGLETASK`
|
||||
without a subsequent `MULTITASK`, since in such a case the foreground or
|
||||
console task would never regain control of the CPU.
|
||||
See also `UP@` and `UP!`
|
||||
|
||||
#### `sleep ( Tadr -- )`
|
||||
|
||||
puts the task characterized by `Tadr` to sleep. `Tadr` is usually generated by
|
||||
calling a task name. `SLEEP` has the same effect as the execution of `STOP`
|
||||
by the task itself. The difference is that `STOP` is usually an end point in
|
||||
processing. SLEEP will hit the task at an unforeseeable time so that the
|
||||
ongoing work of the task is interrupted. See also `WAKE`.
|
||||
|
||||
#### `stop ( -- )`
|
||||
|
||||
causes the task calling `STOP` to sleep. The content of `IP` (instruction
|
||||
pointer), `RP` (return stack pointer) and `SP` (stack pointer) are saved,
|
||||
then control of the CPU is yielded to the next task. These actions are also
|
||||
carried out by `PAUSE` (see there). The difference to `PAUSE` is that `STOP`
|
||||
leaves the task inactive, while `PAUSE` leaves it active.
|
||||
See also `ACTIVATE`, `PASS`, `WAKE`, `SLEEP`, `UP@` and `UP!`.
|
||||
|
||||
#### `Task ( rlen slen -- )`
|
||||
|
||||
is used in the form:
|
||||
|
||||
```
|
||||
rlen slen Task <cccc>
|
||||
```
|
||||
|
||||
`Task` is a defining word that sets up a task. A task is the work area for
|
||||
another program that is to run simultaneously with the already running
|
||||
programs. The task is named `cccc`, has a stack of size `slen` bytes and a
|
||||
return stack of `rlen` bytes. The task's own dictionary (including `PAD`)
|
||||
is located in the stack area, growing upwards while the stack grows downwards.
|
||||
In the return stack area contains the task's user area (growing upwards)
|
||||
and the return stack (growing downwards).
|
||||
A task is thus a reduced image of the entire VolksForth system.
|
||||
See the [task](tasker.md#memory-map-of-a-task) and
|
||||
[system memory map](tasker.md#overall-memory-map).
|
||||
|
||||
Calling `cccc`, the task's name, as a word in any task leaves the same address
|
||||
on the stack that the task `cccc` itself generates when calling `UP@`.
|
||||
This address functions as the ID of the task and used by `’S`, `ACTIVATE`,
|
||||
`LOCK`, `PASS`, `SLEEP`, `TASK` and `WAKE`.
|
||||
|
||||
#### `tasks ( -- )`
|
||||
|
||||
lists the names of all existing tasks and shows whether they are
|
||||
asleep or active.
|
||||
|
||||
#### `unlock ( semadr -- )`
|
||||
|
||||
releases the semaphore at address `semadr` for all tasks. If the semaphore is
|
||||
owned by another task, then `UNLOCK` will wait, doing `PAUSE`, for the
|
||||
until the semaphore is released. See also `LOCK` and the
|
||||
description of the [tasker](tasker.md#semaphores-and-lock).
|
||||
|
||||
#### `up@ ( -- Tadr )` "u-p-fetch"
|
||||
|
||||
provides the address `Tadr` of the first byte of the user rarea of the
|
||||
task calling `UP@`. `Tadr` is the address that characterizes each task,
|
||||
the ID of the task.
|
||||
See also `’S` , `ACTIVATE`, `LOCK`, `PASS`, `SLEEP`, `TASK` and `WAKE`.
|
||||
|
||||
In the user area, variables and other data structures are stored of which
|
||||
each task must have its own instance. See also `UP!`
|
||||
|
||||
#### `up! ( adr -- )` "u-p-store"
|
||||
|
||||
sets the `UP` (user pointer) to point to `adr`. See also `UP@`.
|
||||
|
||||
Note: This is potentially dangerous. Better know what you're doing when
|
||||
using this.
|
||||
|
||||
#### `wake ( Tadr -- )`
|
||||
|
||||
wakes up the task identified by `Tadr`. `Tadr` is usually generated by
|
||||
calling a task name. The specified task will continue to execute its code
|
||||
where it was stopped by `SLEEP` - or where it ended itself by `STOP`,
|
||||
thus be careful!.
|
||||
|
||||
See also `SLEEP`, `STOP`, `ACTIVATE` and `PASS`.
|
14
6502/C64/src/lists.fth
Normal file
14
6502/C64/src/lists.fth
Normal file
@ -0,0 +1,14 @@
|
||||
\ utility words for handling linked lists.
|
||||
\ The first word of each list node contains the link to the next node.
|
||||
|
||||
: end-of-list ( list-node -- last-node )
|
||||
BEGIN dup @ WHILE @ REPEAT ;
|
||||
|
||||
: reverse-list ( list-root-var -- )
|
||||
dup >r @ 0 ( node[0] 0 )
|
||||
BEGIN over WHILE ( node[i] node[i-1] )
|
||||
over @ ( node[i] node[i-1] node[i+1] )
|
||||
>r over ! r> ( node[i] node[i+1] )
|
||||
swap REPEAT ( 0 node[n] )
|
||||
r> ! drop ;
|
||||
|
25
6502/C64/src/multitask.fth
Normal file
25
6502/C64/src/multitask.fth
Normal file
@ -0,0 +1,25 @@
|
||||
\ *** Block No. 58, Hexblock 3a
|
||||
|
||||
\ Multitasker BP 13.9.84 )
|
||||
|
||||
\needs Code include trns6502asm.fth
|
||||
|
||||
Code stop
|
||||
SP 2dec IP lda SP X) sta
|
||||
IP 1+ lda SP )Y sta
|
||||
SP 2dec RP lda SP X) sta
|
||||
RP 1+ lda SP )Y sta
|
||||
6 # ldy SP lda UP )Y sta
|
||||
iny SP 1+ lda UP )Y sta
|
||||
1 # ldy tya clc UP adc W sta
|
||||
txa UP 1+ adc W 1+ sta
|
||||
W 1- jmp end-code
|
||||
|
||||
| Create taskpause Assembler
|
||||
$2C # lda UP X) sta ' stop @ jmp
|
||||
end-code
|
||||
|
||||
: singletask
|
||||
[ ' pause @ ] Literal ['] pause ! ;
|
||||
|
||||
: multitask taskpause ['] pause ! ;
|
@ -1,4 +1,3 @@
|
||||
\ *** Block No. 2, Hexblock 2
|
||||
|
||||
\ rom ram sys cas16aug06
|
||||
\ Shadow with Ctrl+W--->
|
||||
@ -7,36 +6,23 @@
|
||||
\ in the ROM Area
|
||||
|
||||
Assembler also definitions
|
||||
(16 \ Switch Bank 8000-FFFF
|
||||
\ Switch Bank 8000-FFFF
|
||||
: rom here 9 + $8000 u> abort" not here"
|
||||
$ff3e sta ;
|
||||
: ram $ff3f sta ;
|
||||
: sys rom jsr ram ;
|
||||
\ if suffering from abort" not here"
|
||||
\ see next screen Screen --> C)
|
||||
\ see next screen Screen
|
||||
|
||||
|
||||
(64 \ Switch Bank A000-BFFF
|
||||
: rom here 9 + $A000 u> abort" not here"
|
||||
$37 # lda 1 sta ;
|
||||
: ram $36 # lda 1 sta ;
|
||||
C)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\ *** Block No. 3, Hexblock 3
|
||||
|
||||
\ sysMacro Long cas16aug06
|
||||
|
||||
(64 .( not for C64 !) \\ C)
|
||||
|
||||
\ for advanced users, use macros
|
||||
|
||||
\ the following macro must be compiled well
|
||||
\ below the address of $8000 to work.
|
||||
here $8000 $20 - u> ?exit \ not possible
|
||||
|
||||
|
||||
' 0 | Alias ???
|
||||
|
||||
Label long ROM
|
14
6502/C64/src/rom-ram-c64.fth
Normal file
14
6502/C64/src/rom-ram-c64.fth
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
\ rom ram cas16aug06
|
||||
|
||||
\ macros switching the C64 BASIC ROM ($A000-$Bfff)
|
||||
\ on and off. By default VolksForth runs with BASIC ROM
|
||||
\ switched off.
|
||||
|
||||
Assembler also definitions
|
||||
|
||||
\ Can't swich on BASIC ROM (A000-BFFF) if current code
|
||||
\ location is under the BASIC ROM.
|
||||
: rom here 9 + $A000 u> abort" not here"
|
||||
$37 # lda 1 sta ;
|
||||
: ram $36 # lda 1 sta ;
|
33
6502/C64/src/taskdemo-x16.fth
Normal file
33
6502/C64/src/taskdemo-x16.fth
Normal file
@ -0,0 +1,33 @@
|
||||
\ Taskdemo for X16
|
||||
|
||||
: taskmark ; \needs cbm>scr : cbm>scr ;
|
||||
|
||||
\ This method of writing directly into the X16's screen memory
|
||||
\ is a bit hacky and relies on the default settings that the
|
||||
\ Kernal uses for text mode.
|
||||
: scrstart ( -- adr) $b000 ;
|
||||
: ctrl@ ( -- b ) $9f25 c@ ;
|
||||
: addr-sel@ ( -- 0/1 ) ctrl@ 1 and ;
|
||||
: datax! ( c -- ) $9f23 addr-sel@ + c! ;
|
||||
: addrx-l/m! ( u -- ) $9f20 ! ;
|
||||
: scr! ( scrcode vram-addr -- )
|
||||
addrx-l/m! datax! ;
|
||||
|
||||
Variable counter counter off
|
||||
|
||||
$100 $100 Task Background
|
||||
|
||||
: >count ( n -)
|
||||
Background 1 pass
|
||||
counter !
|
||||
BEGIN counter @ -1 counter +! ?dup
|
||||
WHILE pause 0 <# #s #> dup >r
|
||||
0 DO pause dup I + c@ cbm>scr
|
||||
scrstart I 2* + scr! LOOP drop
|
||||
bl r> 2* scrstart + scr!
|
||||
REPEAT
|
||||
BEGIN stop REPEAT ; \ stop's forever
|
||||
: wait Background sleep ;
|
||||
: go Background wake ;
|
||||
|
||||
multitask $1000 >count page
|
28
6502/C64/src/taskdemo.fth
Normal file
28
6502/C64/src/taskdemo.fth
Normal file
@ -0,0 +1,28 @@
|
||||
\ Taskdemo clv12aug87
|
||||
|
||||
(CX cr .( this taskdemo works on c64 and c16 only) C)
|
||||
(CX abort C)
|
||||
|
||||
: taskmark ; \needs cbm>scr : cbm>scr ;
|
||||
|
||||
: scrstart ( -- adr)
|
||||
(64 $288 C) (16 $53e C) c@ $100 * ;
|
||||
|
||||
Variable counter counter off
|
||||
|
||||
$100 $100 Task Background
|
||||
|
||||
: >count ( n -)
|
||||
Background 1 pass
|
||||
counter !
|
||||
BEGIN counter @ -1 counter +! ?dup
|
||||
WHILE pause 0 <# #s #> dup >r
|
||||
0 DO pause dup I + c@ cbm>scr
|
||||
scrstart I + c! LOOP drop
|
||||
bl r> scrstart + c!
|
||||
REPEAT
|
||||
BEGIN stop REPEAT ; \ stop's forever
|
||||
: wait Background sleep ;
|
||||
: go Background wake ;
|
||||
|
||||
multitask $100 >count page
|
92
6502/C64/src/tasker.fth
Normal file
92
6502/C64/src/tasker.fth
Normal file
@ -0,0 +1,92 @@
|
||||
\ *** Block No. 57, Hexblock 39
|
||||
|
||||
\ Multitasker BP 13.9.84 )
|
||||
|
||||
Onlyforth
|
||||
|
||||
\needs multitask include multitask.fth save
|
||||
|
||||
\ *** Block No. 59, Hexblock 3b
|
||||
|
||||
\ pass activate ks 8 may 84 )
|
||||
|
||||
: pass ( n0 .. nr-1 Tadr r -- )
|
||||
BEGIN [ rot ( Trick ! ) ]
|
||||
swap $2C over c! \ awake Task
|
||||
r> -rot \ IP r addr
|
||||
8 + >r \ s0 of Task
|
||||
r@ 2+ @ swap \ IP r0 r
|
||||
2+ 2* \ bytes on Taskstack
|
||||
\ incl. r0 & IP
|
||||
r@ @ over - \ new SP
|
||||
dup r> 2- ! \ into ssave
|
||||
swap bounds ?DO I ! 2 +LOOP ;
|
||||
restrict
|
||||
|
||||
: activate ( Tadr --)
|
||||
0 [ -rot ( Trick ! ) ] REPEAT ;
|
||||
-2 allot restrict
|
||||
|
||||
: sleep ( Tadr --)
|
||||
$4C swap c! ; \ JMP-Opcode
|
||||
|
||||
: wake ( Tadr --)
|
||||
$2C swap c! ; \ BIT-Opcode
|
||||
|
||||
|
||||
\ *** Block No. 60, Hexblock 3c
|
||||
|
||||
\ building a Task BP 13.9.84 )
|
||||
|
||||
| : taskerror ( string -)
|
||||
standardi/o singletask
|
||||
." Task error : " count type
|
||||
multitask stop ;
|
||||
|
||||
: Task ( rlen slen -- )
|
||||
allot \ Stack
|
||||
here $FF and $FE =
|
||||
IF 1 allot THEN \ 6502-align
|
||||
up@ here $100 cmove \ init user area
|
||||
here $4C c, \ JMP opcode
|
||||
\ to sleep Task
|
||||
up@ 1+ @ ,
|
||||
dup up@ 1+ ! \ link Task
|
||||
3 allot \ allot JSR wake
|
||||
dup 6 - dup , , \ ssave and s0
|
||||
2dup + , \ here + rlen = r0
|
||||
under + here - 2+ allot
|
||||
['] taskerror over
|
||||
[ ' errorhandler >body c@ ] Literal + !
|
||||
Constant ;
|
||||
|
||||
|
||||
|
||||
\ *** Block No. 61, Hexblock 3d
|
||||
|
||||
\ more Tasks ks/bp 26apr85re)
|
||||
|
||||
: rendezvous ( semaphoradr -)
|
||||
dup unlock pause lock ;
|
||||
|
||||
| : statesmart
|
||||
state @ IF [compile] Literal THEN ;
|
||||
|
||||
: 's ( Tadr - adr.of.taskuservar)
|
||||
' >body c@ + statesmart ; immediate
|
||||
|
||||
\ Syntax: 2 Demotask 's base !
|
||||
\ makes Demotask working binary
|
||||
|
||||
: tasks ( -)
|
||||
." MAIN " cr up@ dup 1+ @
|
||||
BEGIN 2dup - WHILE
|
||||
dup [ ' r0 >body c@ ] Literal + @
|
||||
6 + name> >name .name
|
||||
dup c@ $4C = IF ." sleeping" THEN cr
|
||||
1+ @ REPEAT 2drop ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
8
6502/C64/src/tmp6502asm.fth
Normal file
8
6502/C64/src/tmp6502asm.fth
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
cr .( tmpheap transient forth assembler) cr
|
||||
|
||||
here $800 tmp-hallot dp !
|
||||
|
||||
include 6502asm.fth
|
||||
|
||||
dp !
|
@ -28,5 +28,5 @@ here dup origin!
|
||||
$100 allot
|
||||
|
||||
Create logo
|
||||
(C16+ ," volksFORTH-83 3.9.5-C16+ " )
|
||||
(C16- ," volksFORTH-83 3.9.5-C16- " )
|
||||
(C16+ ," volksFORTH-83 3.9.6-C16+ " )
|
||||
(C16- ," volksFORTH-83 3.9.6-C16- " )
|
||||
|
@ -28,4 +28,4 @@ here dup origin!
|
||||
$100 allot
|
||||
|
||||
Create logo
|
||||
," volksFORTH-83 3.9.5-C64 "
|
||||
," volksFORTH-83 3.9.6-C64 "
|
||||
|
@ -27,4 +27,4 @@ here dup origin!
|
||||
$100 allot
|
||||
|
||||
Create logo
|
||||
," volksFORTH-83 3.9.5-X16 "
|
||||
," volksFORTH-83 3.9.6-X16 "
|
||||
|
@ -1,7 +1,4 @@
|
||||
|
||||
\ *** Block No. 126, Hexblock 7e
|
||||
7e fthpage
|
||||
|
||||
\ CBM-Labels 05nov87re
|
||||
|
||||
$FFA5 >label ACPTR
|
||||
|
@ -8,13 +8,12 @@ include vf-lbls-cbm.fth
|
||||
|
||||
0ff4c >label ConOut
|
||||
090 >label IOStatus
|
||||
09a >label MsgFlg
|
||||
0ae >label CurDev
|
||||
0ff19 >label BrdCol
|
||||
0ff15 >label BkgCol
|
||||
053b >label PenCol
|
||||
0cb >label CurFlg
|
||||
0cf >label InsCnt
|
||||
0cb >label QtSw
|
||||
0cf >label Insrt
|
||||
0540 >label KeyRep
|
||||
|
||||
055d >label PKeys
|
||||
@ -51,6 +50,34 @@ Code curoff \ --
|
||||
end-code
|
||||
|
||||
|
||||
\ *** Block No. 131, Hexblock 83
|
||||
83 fthpage
|
||||
|
||||
( #bs #cr ..keyboard clv12.4.87)
|
||||
|
||||
: c64key ( -- 8b)
|
||||
curon BEGIN pause c64key? UNTIL
|
||||
curoff getkey ;
|
||||
|
||||
14 Constant #bs 0D Constant #cr
|
||||
|
||||
: c64decode
|
||||
( addr cnt1 key -- addr cnt2)
|
||||
#bs case? IF dup IF del 1- THEN
|
||||
exit THEN
|
||||
#cr case? IF dup span ! exit THEN
|
||||
>r 2dup + r@ swap c! r> emit 1+ ;
|
||||
|
||||
: c64expect ( addr len1 -- )
|
||||
span ! 0
|
||||
BEGIN dup span @ u<
|
||||
WHILE key decode
|
||||
REPEAT 2drop space ;
|
||||
|
||||
Input: keyboard [ here input ! ]
|
||||
c64key c64key? c64decode c64expect ;
|
||||
|
||||
|
||||
include vf-sys-cbm.fth
|
||||
|
||||
|
||||
|
@ -8,12 +8,11 @@ include vf-lbls-cbm.fth
|
||||
|
||||
0E716 >label ConOut
|
||||
090 >label IOStatus
|
||||
09d >label MsgFlg
|
||||
0d020 >label BrdCol
|
||||
0d021 >label BkgCol
|
||||
0286 >label PenCol
|
||||
0d4 >label CurFlg
|
||||
0d8 >label InsCnt
|
||||
0d4 >label QtSw
|
||||
0d8 >label Insrt
|
||||
028a >label KeyRep
|
||||
|
||||
0cc >label blnsw
|
||||
@ -59,6 +58,34 @@ Code curoff ( --)
|
||||
1 # ldy Next jmp end-code
|
||||
|
||||
|
||||
\ *** Block No. 131, Hexblock 83
|
||||
83 fthpage
|
||||
|
||||
( #bs #cr ..keyboard clv12.4.87)
|
||||
|
||||
: c64key ( -- 8b)
|
||||
curon BEGIN pause c64key? UNTIL
|
||||
curoff getkey ;
|
||||
|
||||
14 Constant #bs 0D Constant #cr
|
||||
|
||||
: c64decode
|
||||
( addr cnt1 key -- addr cnt2)
|
||||
#bs case? IF dup IF del 1- THEN
|
||||
exit THEN
|
||||
#cr case? IF dup span ! exit THEN
|
||||
>r 2dup + r@ swap c! r> emit 1+ ;
|
||||
|
||||
: c64expect ( addr len1 -- )
|
||||
span ! 0
|
||||
BEGIN dup span @ u<
|
||||
WHILE key decode
|
||||
REPEAT 2drop space ;
|
||||
|
||||
Input: keyboard [ here input ! ]
|
||||
c64key c64key? c64decode c64expect ;
|
||||
|
||||
|
||||
include vf-sys-cbm.fth
|
||||
|
||||
|
||||
|
@ -1,32 +1,4 @@
|
||||
|
||||
\ *** Block No. 131, Hexblock 83
|
||||
83 fthpage
|
||||
|
||||
( #bs #cr ..keyboard clv12.4.87)
|
||||
|
||||
: c64key ( -- 8b)
|
||||
curon BEGIN pause c64key? UNTIL
|
||||
curoff getkey ;
|
||||
|
||||
14 Constant #bs 0D Constant #cr
|
||||
|
||||
: c64decode
|
||||
( addr cnt1 key -- addr cnt2)
|
||||
#bs case? IF dup IF del 1- THEN
|
||||
exit THEN
|
||||
#cr case? IF dup span ! exit THEN
|
||||
>r 2dup + r@ swap c! r> emit 1+ ;
|
||||
|
||||
: c64expect ( addr len1 -- )
|
||||
span ! 0
|
||||
BEGIN dup span @ u<
|
||||
WHILE key decode
|
||||
REPEAT 2drop space ;
|
||||
|
||||
Input: keyboard [ here input ! ]
|
||||
c64key c64key? c64decode c64expect ;
|
||||
|
||||
|
||||
\ *** Block No. 132, Hexblock 84
|
||||
84 fthpage
|
||||
|
||||
@ -34,7 +6,15 @@ Input: keyboard [ here input ! ]
|
||||
|
||||
Code con! ( 8b --) SP X) lda
|
||||
Label (con! ConOut jsr SP 2inc
|
||||
Label (con!end CurFlg stx InsCnt stx
|
||||
Label (con!end
|
||||
\ So far VolksForth switches off quote switch and insert count
|
||||
\ after every printed character. This introduces a dependency
|
||||
\ on Kernal variables QtSw and Insrt that are undesirable on the
|
||||
\ X16 where their addresses may change between Kernal versions.
|
||||
\ Therefore we'll try how the system behaves without them on the
|
||||
\ X16. Possibly this isn't needed at all, in the end.
|
||||
(C64 QtSw stx Insrt stx )
|
||||
(C16 QtSw stx Insrt stx )
|
||||
1 # ldy ;c: pause ;
|
||||
|
||||
Label (printable? \ for CBM-Code !
|
||||
@ -150,8 +130,10 @@ Label nodevice 0 # ldx 1 # ldy
|
||||
|
||||
\ ?device clv12jul87
|
||||
|
||||
Label (?dev
|
||||
IOStatus stx \ because IOStatus isn't cleared by LISTEN or TALK
|
||||
Label (?dev ( a: dev )
|
||||
\ Clear IOStatus because it isn't cleared by LISTEN or TALK
|
||||
(C64 IOStatus stx ( ) (C16 IOStatus stx ( )
|
||||
(X16 pha 1 # lda ExtApi jsr pla ( )
|
||||
\ It's unclear in which situation or use case the following
|
||||
\ workaround for a C16 OS error is needed. The v4th tests pass
|
||||
\ even with the following line removed.
|
||||
@ -169,7 +151,7 @@ Label (?dev
|
||||
i/o lock (?device ;
|
||||
|
||||
Code (busout ( dev 2nd -- )
|
||||
MsgFlg stx 2 # lda Setup jsr
|
||||
2 # lda Setup jsr
|
||||
N 2+ lda (?dev jsr
|
||||
N 2+ lda LISTEN jsr
|
||||
N lda 60 # ora SECOND jsr
|
||||
@ -192,7 +174,7 @@ Label (?dev
|
||||
0E0 or busout busoff ;
|
||||
|
||||
Code (busin ( dev 2nd -- )
|
||||
MsgFlg stx 2 # lda Setup jsr
|
||||
2 # lda Setup jsr
|
||||
N 2+ lda (?dev jsr
|
||||
N 2+ lda TALK jsr
|
||||
N lda 60 # ora (C16 $ad sta ( )
|
||||
|
@ -7,35 +7,22 @@ include vf-lbls-cbm.fth
|
||||
|
||||
0ffd2 >label ConOut
|
||||
0febd >label KbdbufPeek
|
||||
0287 >label IOStatus \ aka status
|
||||
028d >label MsgFlg
|
||||
0feab >label ExtApi
|
||||
09f2c >label BrdCol
|
||||
0376 >label BkgPenCol \ aka color
|
||||
0381 >label CurFlg \ aka qtsw
|
||||
0385 >label InsCnt \ aka insrt
|
||||
\ I'm tentatively removing QtSw & Insrt from the X16 variant;
|
||||
\ see comment at the top of vf-sys-cbm.fth
|
||||
\ 0381 >label QtSw
|
||||
\ 0385 >label Insrt
|
||||
|
||||
1 >label RomBank
|
||||
0 >label RamBank
|
||||
|
||||
037B >label blnsw \ C64: $cc
|
||||
\ 037C >label blnct \ C64: $cd
|
||||
\ 037D >label gdbln \ C64: $ce
|
||||
\ 037E >label blnon \ C64: $cf
|
||||
\ 0262 >label pnt \ C64: $d1
|
||||
\ 0380 >label pntr \ C64: $d3
|
||||
\ 0373 >label gdcol
|
||||
|
||||
\ C64 labels that X16 doesn't have:
|
||||
|
||||
\ 028a >label KeyRep \ aka rptflg
|
||||
|
||||
|
||||
\ *** Block No. 129, Hexblock 81
|
||||
81 fthpage
|
||||
|
||||
\ X16 c64key? getkey
|
||||
\ X16 x16key? getkey
|
||||
|
||||
Code c64key? ( -- flag)
|
||||
Code x16key? ( -- flag)
|
||||
KbdbufPeek jsr
|
||||
txa pha
|
||||
Push jmp end-code
|
||||
@ -45,16 +32,33 @@ Code getkey ( -- 8b)
|
||||
Push0A jmp end-code
|
||||
|
||||
|
||||
\ *** Block No. 130, Hexblock 82
|
||||
82 fthpage
|
||||
\ *** Block No. 131, Hexblock 83
|
||||
83 fthpage
|
||||
|
||||
\ X16 curon curoff
|
||||
( #bs #cr ..keyboard clv12.4.87)
|
||||
|
||||
Code curon ( --)
|
||||
blnsw stx Next jmp end-code
|
||||
: x16key ( -- 8b)
|
||||
BEGIN pause x16key? UNTIL getkey ;
|
||||
|
||||
Code curoff ( --)
|
||||
blnsw sty Next jmp end-code
|
||||
14 Constant #bs 0D Constant #cr
|
||||
|
||||
: x16decode
|
||||
( addr cnt1 key -- addr cnt2)
|
||||
#cr case? IF dup span ! exit THEN
|
||||
>r 2dup + r> swap c! 1+ ;
|
||||
|
||||
Code basin ( -- 8b)
|
||||
CHRIN jsr
|
||||
Push0A jmp end-code
|
||||
|
||||
: x16expect ( addr len1 -- )
|
||||
span ! 0
|
||||
BEGIN dup span @ u<
|
||||
WHILE basin x16decode
|
||||
REPEAT 2drop space ;
|
||||
|
||||
Input: keyboard [ here input ! ]
|
||||
x16key x16key? x16decode x16expect ;
|
||||
|
||||
|
||||
include vf-sys-cbm.fth
|
||||
@ -64,11 +68,9 @@ include vf-sys-cbm.fth
|
||||
\ ... continued
|
||||
8f fthpage
|
||||
|
||||
Create ink-pot
|
||||
\ border bkgnd pen 0
|
||||
6 c, 6 c, 3 c, 0 c, \ Forth
|
||||
0E c, 6 c, 3 c, 0 c, \ Edi
|
||||
6 c, 6 c, 3 c, 0 c, \ User
|
||||
Create x16-ink-pot
|
||||
\ border bkgnd-color-petscii pen-color-petscii
|
||||
6 c, $1f c, $9f c, \ Forth
|
||||
|
||||
|
||||
\ *** Block No. 144, Hexblock 90
|
||||
@ -94,10 +96,10 @@ Label first-init
|
||||
sei cld
|
||||
RomBank lda $f8 # and RomBank sta \ map in KERNAL ROM
|
||||
IOINIT jsr CINT jsr RESTOR jsr \ init. and set I/O-Vectors
|
||||
ink-pot lda BrdCol sta \ border
|
||||
ink-pot 1+ lda
|
||||
.a asl .a asl .a asl .a asl \ backgrnd
|
||||
ink-pot 2+ ora BkgPenCol sta \ pen
|
||||
x16-ink-pot lda BrdCol sta \ border
|
||||
x16-ink-pot 1+ lda ConOut jsr \ backgrnd
|
||||
1 # lda ConOut jsr \ swap backgrnd <-> pen
|
||||
x16-ink-pot 2+ lda ConOut jsr \ pen
|
||||
$0e # lda ConOut jsr \ lower/uppercase
|
||||
cli rts end-code
|
||||
first-init dup bootsystem 1+ !
|
||||
|
35
6502/C64/src/x16input-tsk.fth
Normal file
35
6502/C64/src/x16input-tsk.fth
Normal file
@ -0,0 +1,35 @@
|
||||
\ Sample: a changed input that would run the tasker
|
||||
\ even while waiting for keyboard input, similar to
|
||||
\ the keyboard input on C16 and C64:
|
||||
|
||||
\needs Code include trns6502asm.fth
|
||||
|
||||
\ X16 labels
|
||||
|
||||
$037B >label blnsw \ C64: $cc
|
||||
|
||||
\ X16 curon curoff
|
||||
|
||||
Code curon ( --)
|
||||
blnsw stx Next jmp end-code
|
||||
|
||||
Code curoff ( --)
|
||||
blnsw sty Next jmp end-code
|
||||
|
||||
: c64decode
|
||||
( addr cnt1 key -- addr cnt2)
|
||||
#bs case? IF dup IF del 1- THEN
|
||||
exit THEN
|
||||
#cr case? IF dup span ! exit THEN
|
||||
>r 2dup + r@ swap c! r> emit 1+ ;
|
||||
|
||||
: c64expect ( addr len1 -- )
|
||||
span ! 0
|
||||
BEGIN dup span @ u<
|
||||
WHILE curon key curoff decode
|
||||
REPEAT 2drop space ;
|
||||
|
||||
Input: tasker-keyboard [ here input ! ]
|
||||
x16key x16key? c64decode c64expect ;
|
||||
|
||||
tasker-keyboard
|
@ -5,7 +5,7 @@
|
||||
\ tmpclear will remove all words on the tmpheap, wheras regular clear
|
||||
\ will remove all words on tmpheap and heap together.
|
||||
|
||||
\ Other than the reference tmpheap living on the regular heap, this
|
||||
\ In contrast to the reference tmpheap living on the regular heap, this
|
||||
\ custom tmpheap needs no initialization as its position and
|
||||
\ size (8k) is fixed.
|
||||
|
||||
|
@ -21,8 +21,8 @@ YOU SHOULD SEE THE NUMBER RANGES OF SIGNED AND UNSIGNED NUMBERS:
|
||||
UNSIGNED: 0 FFFF
|
||||
*
|
||||
PLEASE TYPE UP TO 80 CHARACTERS:
|
||||
1234567890
|
||||
RECEIVED: "1234567890"
|
||||
TMPL_KEYS_ECHO_TMPL
|
||||
RECEIVED: "TMPL_KEYS_RECEIVED_TMPL"
|
||||
* GDX exists
|
||||
End of Core word set tests
|
||||
|
19
VERSIONS.ORG
19
VERSIONS.ORG
@ -2,6 +2,25 @@
|
||||
|
||||
* C64/C16/Plus4/CommanderX16
|
||||
|
||||
See also [[6502/C64/RELEASE_NOTES.md]]
|
||||
|
||||
*3.9.6*
|
||||
|
||||
* Removes all known dependencies of the X16 VolksForth kernel on
|
||||
undocumented X16 Kernal variables and thus (hopefully) on specific
|
||||
X16 ROM versions. This has some implications on multitasking behaviour
|
||||
while waiting for console input.
|
||||
* Adds more bundled Forth sources from the original disks.
|
||||
* Starts an English translation of the original German manual with a
|
||||
translation of the chapter on the multitasker.
|
||||
|
||||
*3.9.5*
|
||||
|
||||
* X16 version adapted to the X16 ROM version R46. It also runs with
|
||||
the R47 ROM.
|
||||
* Adds a second X16 binary with a word (XED) use the ROM-based editor
|
||||
X16Edit, and with some DOS and file support (DIR, CAT, DOS).
|
||||
|
||||
*3.9.4*
|
||||
|
||||
* X16 version adapted to Kernal/Emulator version R41
|
||||
|
Loading…
x
Reference in New Issue
Block a user