added sorting module and sortingbench example

This commit is contained in:
Irmen de Jong 2024-12-21 06:18:35 +01:00
parent 5482ac0302
commit d70cfbb661
5 changed files with 718 additions and 365 deletions

View File

@ -0,0 +1,180 @@
; **experimental** data sorting routines, API subject to change!!
sorting {
; GNOME SORT is tiny and extremely fast if the initial values are already almost sorted.
; SHELL SORT is quite a bit faster if the initial values are more randomly distributed.
; NOTE: all word arrays are assumed to be @nosplit!!
; NOTE: sorting is done in ascending order!!!
asmsub gnomesort_ub(uword bytearray @AY, ubyte num_elements @X) {
%asm {{
stx _loop+1 ; modifying
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
sta P8ZP_SCRATCH_W2
cmp #0
bne +
dey
+ dec P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldy #0 ; pos
_loop
cpy #0 ; modified
beq _done
cpy #0
beq +
lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
; swap elements
tax
lda (P8ZP_SCRATCH_W2),y
sta (P8ZP_SCRATCH_W1),y
txa
sta (P8ZP_SCRATCH_W2),y
dey
jmp _loop
+ iny
bne _loop
_done
rts
}}
}
/*
prog8 source code for the above routine:
sub gnomesort_ub(uword @requirezp values, ubyte num_elements) {
ubyte @zp pos
while pos != num_elements {
if pos==0
pos++
else if values[pos]>=values[pos-1]
pos++
else {
; swap elements
cx16.r0L = values[pos-1]
values[pos-1] = values[pos]
values[pos] = cx16.r0L
pos--
}
}
}
*/
sub gnomesort_uw(uword values, ubyte num_elements) {
; TODO optimize this more, rewrite in asm?
uword @zp pos
cx16.r2 = num_elements*$0002
while pos != cx16.r2 {
uword @requirezp ptr = values+pos
if pos==0
pos += 2
else {
cx16.r0 = peekw(ptr-2)
cx16.r1 = peekw(ptr)
if cx16.r0<=cx16.r1
pos += 2
else {
; swap elements
pokew(ptr-2, cx16.r1)
pokew(ptr, cx16.r0)
pos -= 2
}
}
}
}
; gnomesort_pointers is not worth it over shellshort_pointers.
sub shellsort_ub(uword @requirezp values, ubyte num_elements) {
num_elements--
ubyte @zp gap
for gap in [132, 57, 23, 10, 4, 1] {
ubyte i
for i in gap to num_elements {
ubyte @zp temp = values[i]
ubyte @zp j = i
ubyte @zp k = j-gap
repeat {
ubyte @zp v = values[k]
if v <= temp break
if j < gap break
values[j] = v
j = k
k -= gap
}
values[j] = temp
}
}
}
sub shellsort_uw(uword @requirezp values, ubyte num_elements) {
num_elements--
ubyte gap
for gap in [132, 57, 23, 10, 4, 1] {
ubyte i
for i in gap to num_elements {
uword @zp temp = peekw(values+i*$0002)
ubyte @zp j = i
ubyte @zp k = j-gap
repeat {
uword @zp v = peekw(values+k*2)
if v <= temp break
if j < gap break
pokew(values+j*2, v)
j = k
k -= gap
}
pokew(values+j*2, temp)
}
}
}
sub shellsort_pointers(uword @requirezp pointers, ubyte num_elements, uword comparefunc) {
; Comparefunc must be a routine that accepts 2 pointers in R0 and R1, and must return with Carry=1 if R0<=R1, otherwise Carry=0.
; One such function, to compare strings, is provided as 'string_comparator' below.
num_elements--
ubyte gap
for gap in [132, 57, 23, 10, 4, 1] {
ubyte i
for i in gap to num_elements {
cx16.r1 = peekw(pointers+i*$0002)
ubyte @zp j = i
ubyte @zp k = j-gap
repeat {
cx16.r0 = peekw(pointers+k*2)
void call(comparefunc)
if_cs break
if j < gap break
pokew(pointers+j*2, cx16.r0)
j = k
k -= gap
}
pokew(pointers+j*2, cx16.r1)
}
}
}
asmsub string_comparator(uword string1 @R0, uword string2 @R1) -> bool @Pc {
; R0 and R1 are the two strings, must return Carry=1 when R0<=R1, else Carry=0
%asm {{
lda cx16.r1L
ldy cx16.r1H
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda cx16.r0L
ldy cx16.r0H
jsr prog8_lib.strcmp_mem
cmp #1
bne +
clc
rts
+ sec
rts
}}
}
}

View File

@ -144,6 +144,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
"rasterbars",
"showbmx",
"snow",
"sortingbench",
"spotlight",
"starszoom",
"tehtriz",

View File

@ -254,150 +254,24 @@ Grouped per compilation target.
* `virtual <_static/symboldumps/skeletons-virtual.txt>`_
syslib
------
The "system library" for your target machine. It contains many system-specific definitions such
as ROM/Kernal subroutine definitions, memory location constants, and utility subroutines.
bmx (cx16 only)
----------------
Routines to load and save "BMX" files, the CommanderX16 bitmap file format:
`BMX file format specification <https://cx16forum.com/forum/viewtopic.php?t=6945>`_
Only the *uncompressed* bitmaps variant is supported in this library for now.
The routines are designed to be fast and bulk load/save the data directly into or from vram,
without the need to buffer something in main memory.
Many of these definitions overlap for the C64 and Commander X16 targets so it is still possible
to write programs that work on both targets without modifications.
This module is usually imported automatically and can provide definitions in the ``sys``, ``cbm``, ``c64``, ``cx16``, ``c128``, ``atari`` blocks
depending on the chosen compilation target. Read the `sys lib source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib>`_ for the correct compilation target to see exactly what is there.
sys (part of syslib)
--------------------
``target``
A constant ubyte value designating the target machine that the program is compiled for.
Notice that this is a compile-time constant value and is not determined on the
system when the program is running.
The following return values are currently defined:
- 8 = Atari 8 bits
- 16 = Commander X16
- 64 = Commodore 64
- 128 = Commodore 128
- 255 = Virtual machine
``exit (returncode)``
Immediately stops the program and exits it, with the returncode in the A register.
Note: custom interrupt handlers remain active unless manually cleared first!
``exit2 (resultA, resultX, resultY)``
Immediately stops the program and exits it, with the result values in the A, X and Y registers.
Note: custom interrupt handlers remain active unless manually cleared first!
``exit3 (resultA, resultX, resultY, carry)``
Immediately stops the program and exits it, with the result values in the A, X and Y registers, and the carry flag in the status register.
Note: custom interrupt handlers remain active unless manually cleared first!
``memcopy (from, to, numbytes)``
Efficiently copy a number of bytes from a memory location to another.
*Warning:* can only copy *non-overlapping* memory areas correctly!
Because this function imposes some overhead to handle the parameters,
it is only faster if the number of bytes is larger than a certain threshold.
Compare the generated code to see if it was beneficial or not.
The most efficient will often be to write a specialized copy routine in assembly yourself!
``memset (address, numbytes, bytevalue)``
Efficiently set a part of memory to the given (u)byte value.
But the most efficient will always be to write a specialized fill routine in assembly yourself!
Note that for clearing the screen, very fast specialized subroutines are
available in the ``textio`` and ``graphics`` library modules.
``memsetw (address, numwords, wordvalue)``
Efficiently set a part of memory to the given (u)word value.
But the most efficient will always be to write a specialized fill routine in assembly yourself!
``memcmp (address1, address2, size)``
Compares two blocks of memory of up to 65535 bytes in size.
Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
``read_flags () -> ubyte``
Returns the current value of the CPU status register.
``set_carry ()``
Sets the CPU status register Carry flag.
``clear_carry ()``
Clears the CPU status register Carry flag.
``set_irqd ()``
Sets the CPU status register Interrupt Disable flag.
``clear_irqd ()``
Clears the CPU status register Interrupt Disable flag.
``irqsafe_set_irqd ()``
Sets the CPU status register Interrupt Disable flag, in a way that is safe to be used inside a IRQ handler.
Pair with ``irqsafe_clear_irqd()``.
``irqsafe_clear_irqd ()``
Clears the CPU status register Interrupt Disable flag, in a way that is safe to be used inside a IRQ handler.
Pair with ``irqsafe_set_irqd()``. Inside an IRQ handler this makes sure it doesn't inadvertently
clear the irqd status bit, and it can still be used inside normal code as well (where it *does* clear
the irqd status bit if it was cleared before entering).
``progend ()``
Returns the last address of the program in memory + 1. This means: the memory address directly after all the program code and variables,
including the uninitialized ones ("BSS" variables) and the uninitialized memory blocks reserved by the `memory()` function.
Can be used to load dynamic data after the program, instead of hardcoding something.
On the assembly level: it returns the address of the symbol "``prog8_program_end``".
``progstart ()``
Returns the first address of the program in memory. This usually is $0801 on the C64 and the X16, for example.
On the assembly level: it returns the address of the symbol "``prog8_program_start``".
``wait (uword jiffies)``
wait approximately the given number of jiffies (1/60th seconds)
Note: the regular system irq handler has run for this to work as it depends on the system jiffy clock.
If this is is not possible (for instance because your program is running its own irq handler logic *and* no longer calls
the kernal's handler routine), you'll have to write your own wait routine instead.
``waitvsync ()``
busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
can be used to avoid screen flicker/tearing when updating screen contents.
note: a more accurate way to wait for vsync is to set up a vsync irq handler instead.
note for cx16: the regular system irq handler has to run for this to work (this is not required on C64 and C128)
``waitrastborder ()`` (c64/c128 targets only)
busy wait till the raster position has reached the bottom screen border (approximately)
can be used to avoid screen flicker/tearing when updating screen contents.
note: a more accurate way to do this is by using a raster irq handler instead.
``reset_system ()``
Soft-reset the system back to initial power-on BASIC prompt.
(called automatically by Prog8 when the main subroutine returns and the program is not using basicsafe zeropage option)
``disable_caseswitch()`` and ``enable_caseswitch()``
Disable or enable the ability to switch character set case using a keyboard combination.
``save_prog8_internals()`` and ``restore_prog8_internals()``
Normally not used in user code, the compiler utilizes these for the internal interrupt logic.
It stores and restores the values of the internal prog8 variables.
This allows other code to run that might clobber these values temporarily.
``push (value)``
pushes a byte value on the CPU hardware stack. Low-level function that should normally not be used.
``pushw (value)``
pushes a 16-bit word value on the CPU hardware stack. Low-level function that should normally not be used.
``pop ()``
pops a byte value off the CPU hardware stack and returns it.
Low-level function that should normally not be used.
``popw ()``
pops a 16-bit word value off the CPU hardware stack and returns it.
Low-level function that should normally not be used.
For details about what routines are available, have a look at
the `bmx source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/bmx.p8>`_ .
There's also the "showbmx" example to look at.
buffers (experimental)
----------------------
A small library providing a 8 KB stack, an 8 KB ringbuffer, and a fast 256 bytes ringbuffer.
API is experimental and may change or disappear in a future version.
Stack is a LIFO container, ringbuffers are FIFO containers.
On the Commander X16 the stack and ringbuffer will use a HiRAM bank instead of system ram,
you have to initialize that via the init(bank) routine.
@ -406,10 +280,11 @@ Read the `buffers source code <https://github.com/irmen/prog8/tree/master/compil
to see what's in there. Note that the init() routines have that extra bank parameter on the cx16.
compression
-----------
compression (slightly experimental)
-----------------------------------
Routines for data compression and decompression. Currently only the 'ByteRun1' aka 'PackBits' RLE encoding
is available. This is the compression that was also used in Amiga IFF images and in old MacPaint images.
API is slightly experimental and may change in a future version.
``encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword``
Compress the given data block using ByteRun1 aka PackBits RLE encoding.
@ -470,23 +345,46 @@ Read the `conv source code <https://github.com/irmen/prog8/tree/master/compiler/
to see what's in there.
textio (txt.*)
--------------
This will probably be the most used library module. It contains a whole lot of routines
dealing with text-based input and output (to the screen). Such as
cx16
----
This is available on *all targets*, it is always imported as part of syslib.
On the Commander X16 this module contains a *whole bunch* of things specific to that machine.
It's way too much to include here, you have to study the
`syslib source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/syslib.p8>`_
to see what is there.
- printing strings, numbers and booleans
- reading text input from the user via the keyboard
- filling or clearing the screen and colors
- scrolling the text on the screen
- placing individual characters on the screen
- convert petscii to screencode characters
On the other targets, it only contains the definition of the 16 memory-mapped virtual registers
(cx16.r0 - cx16.r15) and the following utility routines:
All routines work with Screencode character encoding, except `print`, `chrout` and `input_chars`,
these work with PETSCII encoding instead.
``save_virtual_registers()``
save the values of all 16 virtual registers r0 - r15 in a buffer. Might be useful in an IRQ handler to avoid clobbering them.
Read the `textio source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/textio.p8>`_
to see what's in there. (Note: slight variations for different compiler targets)
``restore_virtual_registers()``
restore the values of all 16 virtual registers r0 - r15 from the buffer. Might be useful in an IRQ handler to avoid clobbering them.
``cpu_is_65816()``
Returns true if the CPU in the computer is a 65816, false otherwise (6502 cpu).
Note that Prog8 itself has no support yet for this CPU other than detecting its presence.
``reset_system ()``
Soft-reset the system back to initial power-on BASIC prompt. (same as the routine in sys)
``poweroff_system ()``
Powers down the computer.
``set_led_brightness (ubyte brightness)``
Sets the brightness of the activity led on the computer.
cx16logo
--------
Just a fun module that contains the Commander X16 logo in PETSCII graphics
and allows you to print it anywhere on the screen.
``logo ()``
prints the logo at the current cursor position
``logo_at (column, row)``
printss the logo at the given position
diskio
@ -538,126 +436,16 @@ to see what's in there. (Note: slight variations for different compiler targets)
descriptions for the various methods in this library for details and tips.
strings
-------
Provides string manipulation routines.
emudbg (cx16 only)
-------------------
X16Emu Emulator debug routines, for Cx16 only.
Allows you to interface with the emulator's debug routines/registers.
There's stuff like ``is_emulator`` to detect if running in the emulator,
and ``console_write`` to write a (iso) string to the emulator's console (stdout) etc.
``length (str) -> ubyte length``
Number of bytes in the string. This value is determined during runtime and counts upto
the first terminating 0 byte in the string, regardless of the size of the string during compilation time.
Don't confuse this with ``len`` and ``sizeof``!
``left (source, length, target)``
Copies the left side of the source string of the given length to target string.
It is assumed the target string buffer is large enough to contain the result.
Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
Modifies in-place, doesn't return a value (so can't be used in an expression).
``right (source, length, target)``
Copies the right side of the source string of the given length to target string.
It is assumed the target string buffer is large enough to contain the result.
Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
Modifies in-place, doesn't return a value (so can't be used in an expression).
``slice (source, start, length, target)``
Copies a segment from the source string, starting at the given index,
and of the given length to target string.
It is assumed the target string buffer is large enough to contain the result.
Also, you have to make sure yourself that start and length are within bounds of the strings.
Modifies in-place, doesn't return a value (so can't be used in an expression).
``find (string, char) -> ubyte index, bool found``
Locates the first index of the given character in the string, and a boolean (in Carry flag)
to say if it was found at all. If the character is not found, index 255 (and false) is returned.
You can consider this a safer way of checking if a character occurs
in a string than using an `in` containment check - because this find routine
properly stops at the first 0-byte string terminator it encounters in case the string was modified.
``rfind (string, char) -> ubyte index, bool found``
Like ``find``, but now looking from the *right* of the string instead.
``contains (string, char) -> bool``
Just returns true if the character is in the given string, or false if it's not.
For string literals, you can use a containment check expression instead: ``char in "hello world"``.
``compare (string1, string2) -> ubyte result``
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.
Note that you can also directly compare strings and string values with each other
using ``==``, ``<`` etcetera (it will use strings.compare for you under water automatically).
This even works when dealing with uword (pointer) variables when comparing them to a string type.
``copy (from, to) -> ubyte length``
Copy a string to another, overwriting that one. Returns the length of the string that was copied.
Often you don't have to call this explicitly and can just write ``string1 = string2``
but this function is useful if you're dealing with addresses for instance.
``append (string, suffix) -> ubyte length``
Appends the suffix string to the other string (make sure the memory buffer is large enough!)
Returns the length of the combined string.
``lower (string)``
Lowercases the PETSCII-string in place.
``upper (string)``
Uppercases the PETSCII-string in place.
``lowerchar (char)``
Returns lowercased PETSCII character.
``upperchar (char)``
Returns uppercased PETSCII character.
``strip (string)``
Gets rid of whitespace and other non-visible characters at the edges of the string. (destructive)
``rstrip (string)``
Gets rid of whitespace and other non-visible characters at the end of the string. (destructive)
``lstrip (string)``
Gets rid of whitespace and other non-visible characters at the start of the string. (destructive)
``lstripped (string) -> str``
Returns pointer to first non-whitespace and non-visible character at the start of the string (non-destructive lstrip)
``trim (string)``
Gets rid of whitespace characters at the edges of the string. (destructive)
``rtrim (string)``
Gets rid of whitespace characters at the end of the string. (destructive)
``ltrim (string)``
Gets rid of whitespace characters at the start of the string. (destructive)
``ltrimmed (string) -> str``
Returns pointer to first non-whitespace character at the start of the string (non-destructive ltrim)
``isdigit (char)``
Returns boolean if the character is a numerical digit 0-9
``islower (char)``, ``isupper (char)``, ``isletter (char)``
Returns true if the character is a shifted-PETSCII lowercase letter, uppercase letter, or any letter, respectively.
``isspace (char)``
Returns true if the PETSCII character is a whitespace (tab, space, return, and shifted versions)
``isprint (char)``
Returns true if the PETSCII character is a "printable" character (space or any visible symbol)
``startswith (string, prefix) -> bool``
Returns true if string starts with prefix, otherwise false
``endswith (string, suffix) -> bool``
Returns true if string ends with suffix, otherwise false
``pattern_match (string, pattern) -> bool`` (not on Virtual target)
Returns true if the string matches the pattern, false if not.
'?' in the pattern matches any one character. '*' in the pattern matches any substring.
``hash (string) -> ubyte``
Returns a simple 8 bit hash value for the given string.
The formula is: hash(-1)=179; clear carry; hash(i) = ROL hash(i-1) XOR string[i]
(where ROL is the cpu ROL instruction)
On the English word list in /usr/share/dict/words it seems to have a pretty even distribution.
Read the `emudbg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/emudbg.p8>`_
to see what's in there.
Information about the exposed debug registers is in the `emulator's documentation <https://github.com/X16Community/x16-emulator#debug-io-registers>`_.
floats
@ -760,6 +548,25 @@ Provides definitions for the ROM/Kernal subroutines and utility routines dealing
Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
gfx_lores and gfx_hires (cx16 only)
-----------------------------------
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
- gfx_lores: optimized routines for 320x240 256 color bitmap graphics mode. Compatible with X16 screen mode 128.
- gfx_hires: optimized routines for 640x480 4 color bitmap graphics mode
- enable bitmap graphics mode, also back to text mode
- drawing and reading individual pixels
- drawing lines, rectangles, filled rectangles, circles, discs
- flood fill
- drawing text inside the bitmap
Read the `gfx_lores source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_lores.p8>`_
or `gfx_hires source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_hires.p8>`_
to see what's in there.
They share the same routines.
graphics
--------
Bitmap graphics routines:
@ -921,80 +728,6 @@ but perhaps the provided ones can be of service too.
(there is no version for word values because of lack of precision in the fixed point calculation there).
cx16logo
--------
Just a fun module that contains the Commander X16 logo in PETSCII graphics
and allows you to print it anywhere on the screen.
``logo ()``
prints the logo at the current cursor position
``logo_at (column, row)``
printss the logo at the given position
prog8_lib
---------
Low-level language support. You should not normally have to bother with this directly.
The compiler needs it for various built-in system routines.
cx16
----
This is available on *all targets*, it is always imported as part of syslib.
On the Commander X16 this module contains a *whole bunch* of things specific to that machine.
It's way too much to include here, you have to study the
`syslib source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/syslib.p8>`_
to see what is there.
On the other targets, it only contains the definition of the 16 memory-mapped virtual registers
(cx16.r0 - cx16.r15) and the following utility routines:
``save_virtual_registers()``
save the values of all 16 virtual registers r0 - r15 in a buffer. Might be useful in an IRQ handler to avoid clobbering them.
``restore_virtual_registers()``
restore the values of all 16 virtual registers r0 - r15 from the buffer. Might be useful in an IRQ handler to avoid clobbering them.
``cpu_is_65816()``
Returns true if the CPU in the computer is a 65816, false otherwise (6502 cpu).
Note that Prog8 itself has no support yet for this CPU other than detecting its presence.
``reset_system ()``
Soft-reset the system back to initial power-on BASIC prompt. (same as the routine in sys)
``poweroff_system ()``
Powers down the computer.
``set_led_brightness (ubyte brightness)``
Sets the brightness of the activity led on the computer.
bmx (cx16 only)
----------------
Routines to load and save "BMX" files, the CommanderX16 bitmap file format:
`BMX file format specification <https://cx16forum.com/forum/viewtopic.php?t=6945>`_
Only the *uncompressed* bitmaps variant is supported in this library for now.
The routines are designed to be fast and bulk load/save the data directly into or from vram,
without the need to buffer something in main memory.
For details about what routines are available, have a look at
the `bmx source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/bmx.p8>`_ .
There's also the "showbmx" example to look at.
emudbg (cx16 only)
-------------------
X16Emu Emulator debug routines, for Cx16 only.
Allows you to interface with the emulator's debug routines/registers.
There's stuff like ``is_emulator`` to detect if running in the emulator,
and ``console_write`` to write a (iso) string to the emulator's console (stdout) etc.
Read the `emudbg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/emudbg.p8>`_
to see what's in there.
Information about the exposed debug registers is in the `emulator's documentation <https://github.com/X16Community/x16-emulator#debug-io-registers>`_.
monogfx (cx16 and virtual)
---------------------------
Full-screen lores or hires monochrome bitmap graphics routines, available on the Cx16 machine only.
@ -1012,25 +745,6 @@ Read the `monogfx source code <https://github.com/irmen/prog8/tree/master/compil
to see what's in there.
gfx_lores and gfx_hires (cx16 only)
-----------------------------------
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
- gfx_lores: optimized routines for 320x240 256 color bitmap graphics mode. Compatible with X16 screen mode 128.
- gfx_hires: optimized routines for 640x480 4 color bitmap graphics mode
- enable bitmap graphics mode, also back to text mode
- drawing and reading individual pixels
- drawing lines, rectangles, filled rectangles, circles, discs
- flood fill
- drawing text inside the bitmap
Read the `gfx_lores source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_lores.p8>`_
or `gfx_hires source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_hires.p8>`_
to see what's in there.
They share the same routines.
palette (cx16 only)
--------------------
Available for the Cx16 target. Various routines to set the display color palette.
@ -1045,6 +759,12 @@ Read the `palette source code <https://github.com/irmen/prog8/tree/master/compil
to see what's in there.
prog8_lib
---------
Low-level language support. You should not normally have to bother with this directly.
The compiler needs it for various built-in system routines.
psg (cx16 only)
----------------
Available for the Cx16 target.
@ -1056,6 +776,16 @@ Read the `psg source code <https://github.com/irmen/prog8/tree/master/compiler/r
to see what's in there.
sorting (experimental)
----------------------
Various sorting routines (gnome sort and shell sort variants) for byte, word and string arrays.
API is experimental and may change or disappear in a future version.
**NOTE:** all word arrays are assumed to be @nosplit, words and pointers need to be consecutive in memory.
**NOTE:** sorting is done in ascending order.
Read the `sorting source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/sorting.p8>`_
to see what's in there.
sprites (cx16 only)
--------------------
Available for the Cx16 target. Simple routines to manipulate sprites.
@ -1068,6 +798,288 @@ Read the `sprites source code <https://github.com/irmen/prog8/tree/master/compil
to see what's in there.
strings
-------
Provides string manipulation routines.
``length (str) -> ubyte length``
Number of bytes in the string. This value is determined during runtime and counts upto
the first terminating 0 byte in the string, regardless of the size of the string during compilation time.
Don't confuse this with ``len`` and ``sizeof``!
``left (source, length, target)``
Copies the left side of the source string of the given length to target string.
It is assumed the target string buffer is large enough to contain the result.
Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
Modifies in-place, doesn't return a value (so can't be used in an expression).
``right (source, length, target)``
Copies the right side of the source string of the given length to target string.
It is assumed the target string buffer is large enough to contain the result.
Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
Modifies in-place, doesn't return a value (so can't be used in an expression).
``slice (source, start, length, target)``
Copies a segment from the source string, starting at the given index,
and of the given length to target string.
It is assumed the target string buffer is large enough to contain the result.
Also, you have to make sure yourself that start and length are within bounds of the strings.
Modifies in-place, doesn't return a value (so can't be used in an expression).
``find (string, char) -> ubyte index, bool found``
Locates the first index of the given character in the string, and a boolean (in Carry flag)
to say if it was found at all. If the character is not found, index 255 (and false) is returned.
You can consider this a safer way of checking if a character occurs
in a string than using an `in` containment check - because this find routine
properly stops at the first 0-byte string terminator it encounters in case the string was modified.
``rfind (string, char) -> ubyte index, bool found``
Like ``find``, but now looking from the *right* of the string instead.
``contains (string, char) -> bool``
Just returns true if the character is in the given string, or false if it's not.
For string literals, you can use a containment check expression instead: ``char in "hello world"``.
``compare (string1, string2) -> ubyte result``
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.
Note that you can also directly compare strings and string values with each other
using ``==``, ``<`` etcetera (it will use strings.compare for you under water automatically).
This even works when dealing with uword (pointer) variables when comparing them to a string type.
``copy (from, to) -> ubyte length``
Copy a string to another, overwriting that one. Returns the length of the string that was copied.
Often you don't have to call this explicitly and can just write ``string1 = string2``
but this function is useful if you're dealing with addresses for instance.
``append (string, suffix) -> ubyte length``
Appends the suffix string to the other string (make sure the memory buffer is large enough!)
Returns the length of the combined string.
``lower (string)``
Lowercases the PETSCII-string in place.
``upper (string)``
Uppercases the PETSCII-string in place.
``lowerchar (char)``
Returns lowercased PETSCII character.
``upperchar (char)``
Returns uppercased PETSCII character.
``strip (string)``
Gets rid of whitespace and other non-visible characters at the edges of the string. (destructive)
``rstrip (string)``
Gets rid of whitespace and other non-visible characters at the end of the string. (destructive)
``lstrip (string)``
Gets rid of whitespace and other non-visible characters at the start of the string. (destructive)
``lstripped (string) -> str``
Returns pointer to first non-whitespace and non-visible character at the start of the string (non-destructive lstrip)
``trim (string)``
Gets rid of whitespace characters at the edges of the string. (destructive)
``rtrim (string)``
Gets rid of whitespace characters at the end of the string. (destructive)
``ltrim (string)``
Gets rid of whitespace characters at the start of the string. (destructive)
``ltrimmed (string) -> str``
Returns pointer to first non-whitespace character at the start of the string (non-destructive ltrim)
``isdigit (char)``
Returns boolean if the character is a numerical digit 0-9
``islower (char)``, ``isupper (char)``, ``isletter (char)``
Returns true if the character is a shifted-PETSCII lowercase letter, uppercase letter, or any letter, respectively.
``isspace (char)``
Returns true if the PETSCII character is a whitespace (tab, space, return, and shifted versions)
``isprint (char)``
Returns true if the PETSCII character is a "printable" character (space or any visible symbol)
``startswith (string, prefix) -> bool``
Returns true if string starts with prefix, otherwise false
``endswith (string, suffix) -> bool``
Returns true if string ends with suffix, otherwise false
``pattern_match (string, pattern) -> bool`` (not on Virtual target)
Returns true if the string matches the pattern, false if not.
'?' in the pattern matches any one character. '*' in the pattern matches any substring.
``hash (string) -> ubyte``
Returns a simple 8 bit hash value for the given string.
The formula is: hash(-1)=179; clear carry; hash(i) = ROL hash(i-1) XOR string[i]
(where ROL is the cpu ROL instruction)
On the English word list in /usr/share/dict/words it seems to have a pretty even distribution.
syslib
------
The "system library" for your target machine. It contains many system-specific definitions such
as ROM/Kernal subroutine definitions, memory location constants, and utility subroutines.
Many of these definitions overlap for the C64 and Commander X16 targets so it is still possible
to write programs that work on both targets without modifications.
This module is usually imported automatically and can provide definitions in the ``sys``, ``cbm``, ``c64``, ``cx16``, ``c128``, ``atari`` blocks
depending on the chosen compilation target. Read the `sys lib source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib>`_ for the correct compilation target to see exactly what is there.
sys (part of syslib)
--------------------
``target``
A constant ubyte value designating the target machine that the program is compiled for.
Notice that this is a compile-time constant value and is not determined on the
system when the program is running.
The following return values are currently defined:
- 8 = Atari 8 bits
- 16 = Commander X16
- 64 = Commodore 64
- 128 = Commodore 128
- 255 = Virtual machine
``exit (returncode)``
Immediately stops the program and exits it, with the returncode in the A register.
Note: custom interrupt handlers remain active unless manually cleared first!
``exit2 (resultA, resultX, resultY)``
Immediately stops the program and exits it, with the result values in the A, X and Y registers.
Note: custom interrupt handlers remain active unless manually cleared first!
``exit3 (resultA, resultX, resultY, carry)``
Immediately stops the program and exits it, with the result values in the A, X and Y registers, and the carry flag in the status register.
Note: custom interrupt handlers remain active unless manually cleared first!
``memcopy (from, to, numbytes)``
Efficiently copy a number of bytes from a memory location to another.
*Warning:* can only copy *non-overlapping* memory areas correctly!
Because this function imposes some overhead to handle the parameters,
it is only faster if the number of bytes is larger than a certain threshold.
Compare the generated code to see if it was beneficial or not.
The most efficient will often be to write a specialized copy routine in assembly yourself!
``memset (address, numbytes, bytevalue)``
Efficiently set a part of memory to the given (u)byte value.
But the most efficient will always be to write a specialized fill routine in assembly yourself!
Note that for clearing the screen, very fast specialized subroutines are
available in the ``textio`` and ``graphics`` library modules.
``memsetw (address, numwords, wordvalue)``
Efficiently set a part of memory to the given (u)word value.
But the most efficient will always be to write a specialized fill routine in assembly yourself!
``memcmp (address1, address2, size)``
Compares two blocks of memory of up to 65535 bytes in size.
Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
``read_flags () -> ubyte``
Returns the current value of the CPU status register.
``set_carry ()``
Sets the CPU status register Carry flag.
``clear_carry ()``
Clears the CPU status register Carry flag.
``set_irqd ()``
Sets the CPU status register Interrupt Disable flag.
``clear_irqd ()``
Clears the CPU status register Interrupt Disable flag.
``irqsafe_set_irqd ()``
Sets the CPU status register Interrupt Disable flag, in a way that is safe to be used inside a IRQ handler.
Pair with ``irqsafe_clear_irqd()``.
``irqsafe_clear_irqd ()``
Clears the CPU status register Interrupt Disable flag, in a way that is safe to be used inside a IRQ handler.
Pair with ``irqsafe_set_irqd()``. Inside an IRQ handler this makes sure it doesn't inadvertently
clear the irqd status bit, and it can still be used inside normal code as well (where it *does* clear
the irqd status bit if it was cleared before entering).
``progend ()``
Returns the last address of the program in memory + 1. This means: the memory address directly after all the program code and variables,
including the uninitialized ones ("BSS" variables) and the uninitialized memory blocks reserved by the `memory()` function.
Can be used to load dynamic data after the program, instead of hardcoding something.
On the assembly level: it returns the address of the symbol "``prog8_program_end``".
``progstart ()``
Returns the first address of the program in memory. This usually is $0801 on the C64 and the X16, for example.
On the assembly level: it returns the address of the symbol "``prog8_program_start``".
``wait (uword jiffies)``
wait approximately the given number of jiffies (1/60th seconds)
Note: the regular system irq handler has run for this to work as it depends on the system jiffy clock.
If this is is not possible (for instance because your program is running its own irq handler logic *and* no longer calls
the kernal's handler routine), you'll have to write your own wait routine instead.
``waitvsync ()``
busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
can be used to avoid screen flicker/tearing when updating screen contents.
note: a more accurate way to wait for vsync is to set up a vsync irq handler instead.
note for cx16: the regular system irq handler has to run for this to work (this is not required on C64 and C128)
``waitrastborder ()`` (c64/c128 targets only)
busy wait till the raster position has reached the bottom screen border (approximately)
can be used to avoid screen flicker/tearing when updating screen contents.
note: a more accurate way to do this is by using a raster irq handler instead.
``reset_system ()``
Soft-reset the system back to initial power-on BASIC prompt.
(called automatically by Prog8 when the main subroutine returns and the program is not using basicsafe zeropage option)
``disable_caseswitch()`` and ``enable_caseswitch()``
Disable or enable the ability to switch character set case using a keyboard combination.
``save_prog8_internals()`` and ``restore_prog8_internals()``
Normally not used in user code, the compiler utilizes these for the internal interrupt logic.
It stores and restores the values of the internal prog8 variables.
This allows other code to run that might clobber these values temporarily.
``push (value)``
pushes a byte value on the CPU hardware stack. Low-level function that should normally not be used.
``pushw (value)``
pushes a 16-bit word value on the CPU hardware stack. Low-level function that should normally not be used.
``pop ()``
pops a byte value off the CPU hardware stack and returns it.
Low-level function that should normally not be used.
``popw ()``
pops a 16-bit word value off the CPU hardware stack and returns it.
Low-level function that should normally not be used.
textio (txt.*)
--------------
This will probably be the most used library module. It contains a whole lot of routines
dealing with text-based input and output (to the screen). Such as
- printing strings, numbers and booleans
- reading text input from the user via the keyboard
- filling or clearing the screen and colors
- scrolling the text on the screen
- placing individual characters on the screen
- convert petscii to screencode characters
All routines work with Screencode character encoding, except `print`, `chrout` and `input_chars`,
these work with PETSCII encoding instead.
Read the `textio source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/textio.p8>`_
to see what's in there. (Note: slight variations for different compiler targets)
verafx (cx16 only)
-------------------
Available for the Cx16 target.

View File

@ -1,6 +1,9 @@
TODO
====
diskio: in 1 routine also save Y not only A? it's when it calls CLRCHN
various library modules: remove %option no_symbol_prefixing?
- DONE: make word arrays split by default and add new @nosplit tag to make an array use the old linear storage format
- DONE: &splitarray will give you the start address of the lsb-array (which is immediately followed by the msb-array)
- DONE: add &< and &> operators to get the address of the lsb-array and msb-array, respectively. (&< is just syntactic sugar for &)
@ -75,6 +78,8 @@ Libraries
---------
- monogfx: flood fill should be able to fill stippled
- Add in-place TSCrunch decoder routine as well to compression lib? May come in handy where you load a block of compressed data, decompress it in place in the same buffer/memory bank
- Sorting module gnomesort_uw could be optimized more, rewrite in asm? Shellshort seems consistently faster even if most of the words are already sorted.
- Add split-word array sorting routines to sorting module?
- pet32 target: make syslib more complete (missing kernal routines)?
- need help with: PET disk routines (OPEN, SETLFS etc are not exposed as kernal calls)
- fix the problems in atari target, and flesh out its libraries.

View File

@ -0,0 +1,155 @@
%import math
%import textio
%import strings
%import sorting
%import emudbg
; show the use and times the performance of the routines in the sorting module.
main {
ubyte[50] array1
ubyte[50] array2
uword[50] warray1
uword[50] warray2
str[22] @nosplit fruits
str[] @nosplit original_fruits = ["mango", "banana", "cranberry", "zucchini", "blackberry", "orange", "dragonfruit", "cherry",
"kiwifruit", "lychee", "peach", "apricot", "tomato", "avocado", "nectarine", "pear",
"mulberry", "pineapple", "apple", "starfruit", "pumpkin", "coconut"]
sub fill_arrays() {
math.rndseed(999,1234)
for cx16.r0L in 0 to len(array1)-1 {
array1[cx16.r0L] = math.rnd()
array2[cx16.r0L] = cx16.r0L & 127
warray1[cx16.r0L] = math.rndw()
warray2[cx16.r0L] = cx16.r0L * (100 as uword)
}
array2[40] = 200
array2[44] = 201
array2[48] = 202
warray2[40] = 9900
warray2[44] = 9910
warray2[48] = 9920
sys.memcopy(original_fruits, fruits, sizeof(original_fruits))
}
sub perf_reset() {
emudbg.reset_cpu_cycles()
}
sub perf_print() {
cx16.r4, cx16.r5 = emudbg.cpu_cycles()
txt.print_uwhex(cx16.r5, true)
txt.print_uwhex(cx16.r4, false)
txt.nl()
}
sub start() {
fill_arrays()
txt.print("\ngnomesort random:\n")
perf_reset()
sorting.gnomesort_ub(array1, len(array1))
perf_print()
for cx16.r0L in 0 to len(array1)-1 {
txt.print_ub(array1[cx16.r0L])
txt.chrout(',')
}
txt.nl()
txt.print("\ngnomesort almost sorted:\n")
perf_reset()
sorting.gnomesort_ub(array2, len(array2))
perf_print()
for cx16.r0L in 0 to len(array2)-1 {
txt.print_ub(array2[cx16.r0L])
txt.chrout(',')
}
txt.nl()
fill_arrays()
txt.print("\nshellsort:\n")
perf_reset()
sorting.shellsort_ub(array1, len(array1))
perf_print()
for cx16.r0L in 0 to len(array1)-1 {
txt.print_ub(array1[cx16.r0L])
txt.chrout(',')
}
txt.nl()
txt.print("\nshellsort almost sorted:\n")
perf_reset()
sorting.shellsort_ub(array2, len(array2))
perf_print()
for cx16.r0L in 0 to len(array2)-1 {
txt.print_ub(array2[cx16.r0L])
txt.chrout(',')
}
txt.nl()
; txt.print("\n\npress enter for next page ")
; void cbm.CHRIN()
; txt.cls()
txt.print("\ngnomesort (words):\n")
perf_reset()
sorting.gnomesort_uw(warray1, len(warray1))
perf_print()
for cx16.r0L in 0 to len(warray1)-1 {
txt.print_uw(warray1[cx16.r0L])
txt.chrout(',')
}
txt.nl()
txt.print("\ngnomesort (words) almost sorted:\n")
perf_reset()
sorting.gnomesort_uw(warray2, len(warray2))
perf_print()
for cx16.r0L in 0 to len(warray2)-1 {
txt.print_uw(warray2[cx16.r0L])
txt.chrout(',')
}
txt.nl()
fill_arrays()
txt.print("\nshellsort (words):\n")
perf_reset()
sorting.shellsort_uw(warray1, len(warray1))
perf_print()
for cx16.r0L in 0 to len(warray1)-1 {
txt.print_uw(warray1[cx16.r0L])
txt.chrout(',')
}
txt.nl()
txt.print("\nshellsort (words) almost sorted:\n")
perf_reset()
sorting.shellsort_uw(warray2, len(warray2))
perf_print()
for cx16.r0L in 0 to len(warray2)-1 {
txt.print_uw(warray2[cx16.r0L])
txt.chrout(',')
}
txt.nl()
txt.print("\nshellsort (strings):\n")
perf_reset()
sorting.shellsort_pointers(fruits, len(fruits), sorting.string_comparator)
perf_print()
for cx16.r0L in 0 to len(fruits)-1 {
txt.print(fruits[cx16.r0L])
txt.chrout(',')
}
txt.nl()
txt.print("\n\nend.")
repeat {
}
}
}