Compare commits

..
52 Commits
Author SHA1 Message Date
Irmen de Jong 0dd1c17ff4 avoid possible crash 2024-10-13 17:51:14 +02:00
Irmen de Jong fa5479ee5f fix ast printing of arrays with duplicate elements 2024-10-13 04:30:46 +02:00
Irmen de Jong 03412cacba added examples/cx16/balloonflight.p8 2024-10-13 00:51:07 +02:00
Irmen de Jong 01a38a0b11 Merge branch 'monogfx_fill_optimization' 2024-10-12 17:29:38 +02:00
Irmen de Jong f43c14bd78 doc 2024-10-12 17:29:28 +02:00
Irmen de Jong fb23452383 optimize monogfx.fill() 2024-10-12 17:18:00 +02:00
Irmen de Jong ab7dde1450 todo 2024-10-12 13:04:19 +02:00
Irmen de Jong 8d9bc2f5ff fixing all sorts of things about assigning arrays to arrays 2024-10-12 12:33:46 +02:00
Irmen de Jong 7651ccc84e fix a type error 2024-10-11 00:50:05 +02:00
Irmen de Jong 1a6b95b388 house cleaning 2024-10-10 20:46:18 +02:00
Irmen de Jong 78ec1e7512 version 2024-10-09 22:21:04 +02:00
Irmen de Jong 7e38d26c33 added several color fade functions to the palette module (cx16) 2024-10-09 21:48:04 +02:00
Irmen de Jong ed09dd4e9e improve automatic type conversions for return values, fixes #155 2024-10-09 20:04:05 +02:00
Irmen de Jong 5731b79554 don't allow problematic string and array assignments anymore, improve error messages.
In certain cases you will need to use string.copy() explicitly to overwrite strings with new strings.
2024-10-09 00:51:05 +02:00
Irmen de Jong eaa22a9d13 added callfar2() builtin function that allows to set A,X,Y and Carry arguments. 2024-10-08 21:36:04 +02:00
Irmen de Jong b2bdfe8482 fix ir rndseed() 2024-10-08 20:40:00 +02:00
Irmen de Jong fea531be9a add sys.sizeof_bool, _ubyte, _uword constants 2024-10-07 20:45:13 +02:00
Irmen de Jong 7c69d38588 scan all asmsubs to see if another subroutine is referenced. Fixes #153 2024-10-07 20:39:49 +02:00
Irmen de Jong a088ee56b0 function inlining can no longer get into an infinite loop. Fixes #154 2024-10-07 19:58:04 +02:00
Irmen de Jong ae669af904 add sys.sizeof_byte, _word, _float constants
because Antlr doesn't allow the grammar to contain a sizeof(typename) rule to override the sizeof(identifier) rule
2024-10-07 19:17:37 +02:00
Irmen de Jong d1ddf05e38 check that block address leaves room for program startup logic 2024-10-03 22:30:06 +02:00
Irmen de Jong 51279a98b3 attempt to fix forloop range datatype issues 2024-10-03 21:12:31 +02:00
Irmen de Jong bf33a4f82d small refactor to prepare for better range dt adjustment 2024-10-02 23:28:33 +02:00
Irmen de Jong fff0d741c3 improved parsing of "not in" operator, and [] array signature (allow space) 2024-10-02 19:06:20 +02:00
Irmen de Jong e83d0ee820 fix crash in msb() when assigning to word again. Fix wrong register in lsb() and msb() in certain situations. 2024-10-02 02:40:16 +02:00
Irmen de Jong 09f3eecf56 changed cx16/rotating-stars example to starszoom instead. 2024-10-02 01:36:54 +02:00
Irmen de Jong 2bd4326ff6 added cx16/rotating-stars example 2024-10-01 23:43:50 +02:00
Irmen de Jong c13168b60c various improvements:
fix verafx.available().
added gfx_lores.plot().
faster gfx_lores.clear_screen().
added a new Sublime Text 4 syntax highlighting file.
2024-10-01 22:18:03 +02:00
Irmen de Jong ea3871d0c4 comment about builtin function call ast node type 2024-10-01 02:14:31 +02:00
markjreed 70a2b11271 New example program: draw a fractal tree (#152)
* demo of prog8 recursion to draw a fractal tree

* feat: comments

* fix: comment formatting

* feat: make minimum branch size a tunable parameter
2024-10-01 02:00:04 +02:00
Irmen de Jong 3cf39e072e fix C64 floating point sign issue 2024-09-30 21:56:34 +02:00
Irmen de Jong 413b86cc4a more helpful error messages 2024-09-30 00:27:29 +02:00
Irmen de Jong a6107fcfdf taking the address of a romsub is now the constant value of said romsub's declared address 2024-09-29 23:53:39 +02:00
Irmen de Jong a064ade1e0 better codegen for call() function 2024-09-29 23:18:51 +02:00
Irmen de Jong df35aa7942 added (experimental) compression library 2024-09-29 18:59:53 +02:00
Irmen de Jong cd49c5f88d cx16: set rom bank to 0 at startup (for faster kernal API calls)
cx16: callfar() with constant address generates shorter asm
2024-09-28 20:58:29 +02:00
Irmen de Jong 1541ad2160 fix variable init order mistake in program startup
reset multiply bit at end of verafx.muls
2024-09-28 19:17:45 +02:00
Irmen de Jong c78b7b1a24 added verafx.mult16() 2024-09-28 01:00:28 +02:00
Irmen de Jong 9c7a645e18 remove non-functional verafx.mult(). note: muls() is still there and just fine!
added documentation/source code comments to the cpu word*word multiplication routine not producing the correct upper 16 bits.
2024-09-28 00:43:05 +02:00
Irmen de Jong 4acf38031a feedback 2024-09-27 20:59:31 +02:00
Irmen de Jong 4cd7271e30 added prog8 vs other languages chapter to the manual 2024-09-27 20:19:28 +02:00
Irmen de Jong 3f630ab1b0 RAW output now also properly initializes variables 2024-09-27 18:46:03 +02:00
Irmen de Jong 04cb684fd4 tweak program start initialization and fix cleanup at exit for atari and pet compiler targets 2024-09-27 02:14:54 +02:00
Irmen de Jong 4c843571ea fix syntax error check for missing return statement 2024-09-26 01:52:33 +02:00
Irmen de Jong 1326498802 update skeleton scripts 2024-09-26 00:12:29 +02:00
Irmen de Jong b7ebd8c4a6 update cx16/audioroutines example to use the new audio module 2024-09-26 00:08:25 +02:00
markjreed 24e0a69480 feat: module with front-ends that jsrfar into audio ROM routines (#151) 2024-09-26 00:00:42 +02:00
Irmen de Jong 4bcb2bdede added benchmark program 2024-09-25 23:32:45 +02:00
Irmen de Jong d27f3eb8a4 remove wrong print_f mention 2024-09-24 23:58:39 +02:00
Irmen de Jong d3e4481112 fix asm optimizer bug where it erroneously discarded rts with a label 2024-09-22 21:41:41 +02:00
Irmen de Jong 1d1d6b3d98 tweak c64 balloonflight example etc. 2024-09-22 13:20:12 +02:00
Irmen de Jong 90b8a22a71 correct amount 2024-09-20 22:35:17 +02:00
124 changed files with 7606 additions and 2459 deletions

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
.idea/workspace.xml
.idea/discord.xml
.idea/developer-tools.xml
build/
dist/
output/
+10 -2
View File
@@ -6,7 +6,15 @@
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
</SOURCES>
</library>
</component>
+2 -1
View File
@@ -12,9 +12,10 @@
<module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
<module fileurl="file://$PROJECT_DIR$/benchmark-program/benchmark-program.iml" filepath="$PROJECT_DIR$/benchmark-program/benchmark-program.iml" />
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
<module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
</modules>
</component>
</project>
</project>
+6 -10
View File
@@ -54,27 +54,23 @@ What does Prog8 provide?
------------------------
- all advantages of a higher level language over having to write assembly code manually
- programs run very fast because compilation to native machine code
- programs run very fast because it's compiled to native machine code
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
- modularity, symbol scoping, subroutines
- modularity, symbol scoping, subroutines. No need for forward declarations.
- various data types other than just bytes (16-bit words, floats, strings)
- floating point math is supported if the target system provides floating point library routines (C64 and Cx16 both do)
- floating point math is supported on certain targets
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
- automatic static variable allocations, automatic string and array variables and string sharing
- subroutines with input parameters and result values
- high-level program optimizations
- no need for forward declarations
- small program boilerplate/compilersupport overhead
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
- conditional branches
- conditional branches that map 1:1 to cpu status flags
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
- ``in`` expression for concise and efficient multi-value/containment check
- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
- various powerful built-in libraries to do I/O, number conversions, graphics and more
- convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses
- inline assembly allows you to have full control when every cycle or byte matters
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16, and provides them also on the C64.
- encode strings and characters into petscii or screencodes or even other encodings, as desired (C64/Cx16)
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
- encode strings and characters into petscii or screencodes or even other encodings
*Rapid edit-compile-run-debug cycle:*
+12
View File
@@ -0,0 +1,12 @@
.PHONY: all clean emu
all: benchmark.prg
clean:
rm -f *.prg *.PRG *.asm *.vice-* *.BIN *.PAL *.zip *.7z
emu: benchmark.prg
x16emu -run -prg $< -warp
benchmark.prg: benchmark.p8 b_3d.p8 b_adpcm.p8 b_circles.p8 b_life.p8 b_mandelbrot.p8 b_maze.p8 b_queens.p8 b_textelite.p8
p8compile $< -target cx16
+109
View File
@@ -0,0 +1,109 @@
%import textio
%import math
rotate3d {
const ubyte WIDTH = 40
const ubyte HEIGHT = 30
sub benchmark(uword max_time) -> uword {
uword anglex
uword angley
uword anglez
uword frames
txt.nl()
cbm.SETTIM(0,0,0)
while cbm.RDTIM16()<max_time {
matrix_math.rotate_vertices(msb(anglex), msb(angley), msb(anglez))
draw_edges() ; doesn't really draw anything in the benchmark, but does do the screen calculations
anglex+=500
angley+=215
anglez+=453
frames++
}
return frames
}
sub draw_edges() {
; plot the points of the 3d cube
; first the points on the back, then the points on the front (painter algorithm)
ubyte @zp i
word @zp rz
word @zp persp
byte @shared sx
byte @shared sy
for i in 0 to len(matrix_math.xcoor)-1 {
rz = matrix_math.rotatedz[i]
if rz >= 10 {
persp = 600 + rz/64
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
;; txt.setcc(sx as ubyte, sy as ubyte, 46, 7)
}
}
for i in 0 to len(matrix_math.xcoor)-1 {
rz = matrix_math.rotatedz[i]
if rz < 10 {
persp = 600 + rz/64
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
;; txt.setcc(sx as ubyte, sy as ubyte, 81, 7)
}
}
txt.chrout('.')
}
}
matrix_math {
; vertices
word[] @split xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
word[] @split ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
word[] @split zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
; storage for rotated coordinates
word[len(xcoor)] @split rotatedx
word[len(ycoor)] @split rotatedy
word[len(zcoor)] @split rotatedz
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
; rotate around origin (0,0,0)
; set up the 3d rotation matrix values
word wcosa = math.cos8(ax)
word wsina = math.sin8(ax)
word wcosb = math.cos8(ay)
word wsinb = math.sin8(ay)
word wcosc = math.cos8(az)
word wsinc = math.sin8(az)
word wcosa_sinb = wcosa*wsinb / 128
word wsina_sinb = wsina*wsinb / 128
word Axx = wcosa*wcosb / 128
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) / 128
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) / 128
word Ayx = wsina*wcosb / 128
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) / 128
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) / 128
word Azx = -wsinb
word Azy = wcosb*wsinc / 128
word Azz = wcosb*wcosc / 128
ubyte @zp i
for i in 0 to len(xcoor)-1 {
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i]
rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i]
}
}
}
+89
View File
@@ -0,0 +1,89 @@
adpcm {
sub decode_benchmark(uword max_time) -> uword {
uword num_blocks
txt.nl()
cbm.SETTIM(0,0,0)
while cbm.RDTIM16()<max_time {
adpcm.init(0,0)
uword @requirezp nibbles_ptr = $a000 ; for benchmark purposes, the exact nibbles don't really matter, so we just take the basic ROM as input
repeat 252/2 {
unroll 2 {
ubyte @zp nibble = @(nibbles_ptr)
adpcm.decode_nibble(nibble & 15) ; first word (note: upper nibble needs to be zero!)
adpcm.decode_nibble(nibble>>4) ; second word (note: upper nibble is zero, after the shifts.)
nibbles_ptr++
}
}
num_blocks++
txt.chrout('.')
}
return num_blocks
}
; IMA ADPCM decoder. Supports mono and stereo streams.
ubyte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
uword[] @split t_step = [
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767]
uword @requirezp predict ; decoded 16 bit pcm sample for first channel.
ubyte @requirezp index
uword @requirezp pstep
sub init(uword startPredict, ubyte startIndex) {
; initialize first decoding channel.
predict = startPredict
index = startIndex
pstep = t_step[index]
}
sub decode_nibble(ubyte @zp nibble) {
; Decoder for a single nibble for the first channel. (value of 'nibble' needs to be strictly 0-15 !)
; This is the hotspot of the decoder algorithm!
; Note that the generated assembly from this is pretty efficient,
; rewriting it by hand in asm seems to improve it only ~10%.
cx16.r0s = 0 ; difference
if nibble & %0100 !=0
cx16.r0s += pstep
pstep >>= 1
if nibble & %0010 !=0
cx16.r0s += pstep
pstep >>= 1
if nibble & %0001 !=0
cx16.r0s += pstep
pstep >>= 1
cx16.r0s += pstep
if nibble & %1000 !=0
predict -= cx16.r0
else
predict += cx16.r0
; NOTE: the original C/Python code uses a 32 bits prediction value and clips it to a 16 bit word
; but for speed reasons we only work with 16 bit words here all the time (with possible clipping error)
; if predicted > 32767:
; predicted = 32767
; elif predicted < -32767:
; predicted = - 32767
index += t_index[nibble]
if_neg
index = 0
else if index >= len(t_step)-1
index = len(t_step)-1
pstep = t_step[index]
}
}
+111
View File
@@ -0,0 +1,111 @@
%import gfx2
%import math
circles {
const ubyte MAX_NUM_CIRCLES = 80
const ubyte GROWTH_RATE = 4
uword[MAX_NUM_CIRCLES] @split circle_x
uword[MAX_NUM_CIRCLES] @split circle_y
ubyte[MAX_NUM_CIRCLES] circle_radius
ubyte color
uword total_num_circles
sub draw(bool use_kernal, uword max_time) -> uword {
if use_kernal
void cx16.set_screen_mode(128)
else
gfx2.screen_mode(1)
math.rndseed(12345,6789)
cbm.SETTIM(0,0,0)
total_num_circles = 0
color = 16
while cbm.RDTIM16()<max_time {
if use_kernal {
cx16.GRAPH_set_colors(0,0,0)
cx16.GRAPH_clear()
}
else
gfx2.clear_screen(0)
total_num_circles += draw_circles(use_kernal, max_time)
}
if use_kernal
void cx16.set_screen_mode(3)
else {
gfx2.screen_mode(0)
}
return total_num_circles
}
sub draw_circles(bool use_kernal, uword max_time) -> uword {
uword @zp x
uword @zp y
ubyte @zp radius
ubyte num_circles
while num_circles<MAX_NUM_CIRCLES and cbm.RDTIM16()<max_time {
x = math.rndw() % 320
y = math.rndw() % 240
radius = GROWTH_RATE
if not_colliding() {
while not_edge() and not_colliding() {
radius += GROWTH_RATE
}
radius -= GROWTH_RATE
if radius>0 {
color++
if color==0
color=16
if use_kernal {
cx16.GRAPH_set_colors(color, 255-color, 0)
cx16.GRAPH_draw_oval(x-radius, y-radius, radius*2, radius*2, true)
}
else
gfx2.disc(x, y as ubyte, radius, color)
circle_x[num_circles] = x
circle_y[num_circles] = y
circle_radius[num_circles] = radius
num_circles++
}
}
}
return num_circles
sub not_colliding() -> bool {
if num_circles==0
return true
ubyte @zp c
for c in 0 to num_circles-1 {
if distance(c) < (radius as uword) + circle_radius[c]
return false
}
return true
}
sub distance(ubyte cix) -> uword {
word dx = x as word - circle_x[cix]
word dy = y as word - circle_y[cix]
uword sqx = dx*dx as uword
uword sqy = dy*dy as uword
return sqrt(sqx + sqy)
}
sub not_edge() -> bool {
if x as word - radius < 0
return false
if x + radius >= 320
return false
if y as word - radius < 0
return false
if y + radius >= 240
return false
return true
}
}
}
+123
View File
@@ -0,0 +1,123 @@
; conway's game of life.
%import math
%import textio
life {
const ubyte WIDTH = 40
const ubyte HEIGHT = 30
const uword STRIDE = $0002+WIDTH
uword world1 = memory("world1", (WIDTH+2)*(HEIGHT+2), 0)
uword world2 = memory("world2", (WIDTH+2)*(HEIGHT+2), 0)
uword @requirezp active_world = world1
sub benchmark(uword max_time) -> uword {
txt.clear_screen()
sys.memset(world1, (WIDTH+2)*(HEIGHT+2), 0)
sys.memset(world2, (WIDTH+2)*(HEIGHT+2), 0)
set_start_gen()
uword gen
cbm.SETTIM(0,0,0)
while cbm.RDTIM16()<max_time {
next_gen()
gen++
}
return gen
}
sub set_start_gen() {
; some way to set a custom start generation:
; str start_gen = " " +
; " " +
; " " +
; " ** " +
; " * * " +
; " * " +
; " * * " +
; " ****** " +
; " " +
; " " +
; " " +
; " " +
; " " +
; " " +
; " " +
; " "
;
; for y in 0 to 15 {
; for x in 0 to 15 {
; if start_gen[y*16 + x]=='*'
; active_world[offset + x] = 1
; }
; offset += STRIDE
; }
; randomize whole world
math.rndseed(12345,9999)
uword offset = STRIDE+1
ubyte x
ubyte y
for y in 0 to HEIGHT-1 {
for x in 0 to WIDTH-1 {
active_world[offset+x] = math.rnd() & 1
}
offset += STRIDE
}
}
sub next_gen() {
const ubyte DXOFFSET = 0
const ubyte DYOFFSET = 0
ubyte[2] cell_chars = [sc:' ', sc:'●']
uword @requirezp new_world = world1
if active_world == world1
new_world = world2
; To avoid re-calculating word index lookups into the new- and active world arrays,
; we calculate the required pointer values upfront.
; Inside the loop we can use ptr+x just fine (results in efficient LDA (ptr),Y instruction because x is a byte type),
; and for each row we simply add the stride to the pointer.
; It's more readable to use active_world[offset] etc, but offset is a word value, and this produces
; inefficient assembly code because we can't use a register indexed mode in this case. Costly inside a loop.
uword @requirezp new_world_ptr = new_world + STRIDE+1-DXOFFSET
uword @requirezp active_world_ptr = active_world + STRIDE+1-DXOFFSET
ubyte x
ubyte y
for y in DYOFFSET to HEIGHT+DYOFFSET-1 {
cx16.vaddr_autoincr(1, $b000 + 256*y, 0, 2) ; allows us to use simple Vera data byte assigns later instead of setchr() calls
for x in DXOFFSET to WIDTH+DXOFFSET-1 {
; count the living neighbors
ubyte cell = @(active_world_ptr + x)
uword @requirezp ptr = active_world_ptr + x - STRIDE - 1
ubyte neighbors = @(ptr) + @(ptr+1) + @(ptr+2) +
@(ptr+STRIDE) + cell + @(ptr+STRIDE+2) +
@(ptr+STRIDE*2) + @(ptr+STRIDE*2+1) + @(ptr+STRIDE*2+2)
; apply game of life rules
if neighbors==3
cell=1
else if neighbors!=4
cell=0
@(new_world_ptr + x) = cell
; draw new cell
; txt.setchr(x,y,cell_chars[cell])
cx16.VERA_DATA0 = cell_chars[cell]
}
active_world_ptr += STRIDE
new_world_ptr += STRIDE
}
active_world = new_world
}
}
+54
View File
@@ -0,0 +1,54 @@
%import textio
%import floats
mandelbrot {
const ubyte width = 39
const ubyte height = 29
const ubyte max_iter = 15
sub calc(uword max_time) -> uword {
uword num_pixels
ubyte pixelx
ubyte pixely
txt.home()
cbm.SETTIM(0,0,0)
while cbm.RDTIM16() < max_time {
for pixely in 0 to height-1 {
float yy = (pixely as float)/0.40/height - 1.3
for pixelx in 0 to width-1 {
float xx = (pixelx as float)/0.32/width - 2.2
float xsquared = 0.0
float ysquared = 0.0
float x = 0.0
float y = 0.0
ubyte iter = 0
while iter<max_iter and xsquared+ysquared<4.0 {
y = x*y*2.0 + yy
x = xsquared - ysquared + xx
xsquared = x*x
ysquared = y*y
iter++
}
txt.color2(1, max_iter-iter)
txt.spc()
num_pixels++
if cbm.RDTIM16()>=max_time
goto finished
}
txt.nl()
}
txt.clear_screen()
}
finished:
txt.color2(1, 6)
return num_pixels
}
}
+343
View File
@@ -0,0 +1,343 @@
%import textio
%import math
; Even though prog8 only has support for extremely limited recursion,
; you can write recursive algorithms with a bit of extra work by building your own explicit stack structure.
; This program shows a depth-first maze generation algorithm (1 possible path from start to finish),
; and a depth-first maze solver algorithm, both using a stack to store the path taken.
; Note: this program can be compiled for multiple target systems.
maze {
uword score
sub bench(uword max_time) -> uword {
txt.nl()
score=0
math.rndseed(2345,44332)
cbm.SETTIM(0,0,0)
while cbm.RDTIM16()<max_time {
maze.initialize()
maze.drawStartFinish()
if maze.generate(max_time) {
maze.openpassages()
maze.drawStartFinish()
if maze.solve(max_time) {
maze.drawStartFinish()
} else break
} else break
}
return score
}
const uword screenwidth = 40
const uword screenheight = 30
const ubyte numCellsHoriz = (screenwidth-1) / 2
const ubyte numCellsVert = (screenheight-1) / 2
; maze start and finish cells
const ubyte startCx = 0
const ubyte startCy = 0
const ubyte finishCx = numCellsHoriz-1
const ubyte finishCy = numCellsVert-1
; cell properties
const ubyte STONE = 128
const ubyte WALKED = 64
const ubyte BACKTRACKED = 32
const ubyte UP = 1
const ubyte RIGHT = 2
const ubyte DOWN = 4
const ubyte LEFT = 8
const ubyte WALLCOLOR = 12
const ubyte EMPTYCOLOR = 0
; unfortunately on larger screens (cx16), the number of cells exceeds 256 and doesn't fit in a regular array anymore.
uword cells = memory("cells", numCellsHoriz*numCellsVert, 0)
ubyte[256] cx_stack
ubyte[256] cy_stack
ubyte stackptr
ubyte[4] directionflags = [LEFT,RIGHT,UP,DOWN]
sub generate(uword max_time) -> bool {
ubyte cx = startCx
ubyte cy = startCy
stackptr = 0
@(celladdr(cx,cy)) &= ~STONE
drawCell(cx, cy)
uword cells_to_carve = numCellsHoriz * numCellsVert - 1
while cbm.RDTIM16()<max_time {
carve_restart_after_repath:
ubyte direction = choose_uncarved_direction()
if direction==0 {
;backtrack
stackptr--
if stackptr==255 {
; stack empty.
; repath if we are not done yet. (this is a workaround for the prog8 256 array lenght limit)
if cells_to_carve!=0 {
if repath()
goto carve_restart_after_repath
}
return true
}
cx = cx_stack[stackptr]
cy = cy_stack[stackptr]
} else {
cx_stack[stackptr] = cx
cy_stack[stackptr] = cy
stackptr++
if stackptr==0 {
; stack overflow, we can't track our path any longer.
; repath if we are not done yet. (this is a workaround for the prog8 256 array lenght limit)
if cells_to_carve!=0 {
if repath()
goto carve_restart_after_repath
}
return true
}
@(celladdr(cx,cy)) |= direction
when direction {
UP -> {
cy--
@(celladdr(cx,cy)) |= DOWN
}
RIGHT -> {
cx++
@(celladdr(cx,cy)) |= LEFT
score++
}
DOWN -> {
cy++
@(celladdr(cx,cy)) |= UP
}
LEFT -> {
cx--
@(celladdr(cx,cy)) |= RIGHT
}
}
@(celladdr(cx,cy)) &= ~STONE
cells_to_carve--
drawCell(cx, cy)
}
}
return false
sub repath() -> bool {
; repath: try to find a new start cell with possible directions.
; we limit our number of searches so that the algorith doesn't get stuck
; for too long on bad rng... just accept a few unused cells in that case.
repeat 255 {
do {
cx = math.rnd() % numCellsHoriz
cy = math.rnd() % numCellsVert
} until @(celladdr(cx, cy)) & STONE ==0
if available_uncarved()!=0
return true
}
return false
}
sub available_uncarved() -> ubyte {
ubyte candidates = 0
if cx>0 and @(celladdr(cx-1, cy)) & STONE !=0
candidates |= LEFT
if cx<numCellsHoriz-1 and @(celladdr(cx+1, cy)) & STONE !=0
candidates |= RIGHT
if cy>0 and @(celladdr(cx, cy-1)) & STONE !=0
candidates |= UP
if cy<numCellsVert-1 and @(celladdr(cx, cy+1)) & STONE !=0
candidates |= DOWN
return candidates
}
sub choose_uncarved_direction() -> ubyte {
ubyte candidates = available_uncarved()
if candidates==0
return 0
repeat {
ubyte choice = candidates & directionflags[math.rnd() & 3]
if choice!=0
return choice
}
}
}
sub openpassages() {
; open just a few extra passages, so that multiple routes are possible in theory.
ubyte numpassages
ubyte cx
ubyte cy
do {
do {
cx = math.rnd() % (numCellsHoriz-2) + 1
cy = math.rnd() % (numCellsVert-2) + 1
} until @(celladdr(cx, cy)) & STONE ==0
ubyte direction = directionflags[math.rnd() & 3]
if @(celladdr(cx, cy)) & direction == 0 {
when direction {
LEFT -> {
if @(celladdr(cx-1,cy)) & STONE == 0 {
@(celladdr(cx,cy)) |= LEFT
drawCell(cx,cy)
numpassages++
}
}
RIGHT -> {
if @(celladdr(cx+1,cy)) & STONE == 0 {
@(celladdr(cx,cy)) |= RIGHT
drawCell(cx,cy)
numpassages++
}
}
UP -> {
if @(celladdr(cx,cy-1)) & STONE == 0 {
@(celladdr(cx,cy)) |= UP
drawCell(cx,cy)
numpassages++
}
}
DOWN -> {
if @(celladdr(cx,cy+1)) & STONE == 0 {
@(celladdr(cx,cy)) |= DOWN
drawCell(cx,cy)
numpassages++
}
}
}
}
} until numpassages==10
}
sub solve(uword max_time) -> bool {
ubyte cx = startCx
ubyte cy = startCy
const uword max_path_length = 1024
; the path through the maze can be longer than 256 so doesn't fit in a regular array.... :(
uword pathstack = memory("pathstack", max_path_length, 0)
uword pathstackptr = 0
@(celladdr(cx,cy)) |= WALKED
; txt.setcc(cx*2+1, cy*2+1, 81, 1)
while cbm.RDTIM16()<max_time {
solve_loop:
if cx==finishCx and cy==finishCy {
;txt.home()
txt.print("found! path length: ")
txt.print_uw(pathstackptr)
txt.nl()
return true
}
ubyte cell = @(celladdr(cx,cy))
if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0 {
@(pathstack + pathstackptr) = UP
;txt.setcc(cx*2+1, cy*2, 81, 3)
cy--
}
else if cell & DOWN !=0 and @(celladdr(cx,cy+1)) & (WALKED|BACKTRACKED) ==0 {
@(pathstack + pathstackptr) = DOWN
;txt.setcc(cx*2+1, cy*2+2, 81, 3)
cy++
}
else if cell & LEFT !=0 and @(celladdr(cx-1,cy)) & (WALKED|BACKTRACKED) ==0 {
@(pathstack + pathstackptr) = LEFT
;txt.setcc(cx*2, cy*2+1, 81, 3)
cx--
}
else if cell & RIGHT !=0 and @(celladdr(cx+1,cy)) & (WALKED|BACKTRACKED) ==0 {
@(pathstack + pathstackptr) = RIGHT
;txt.setcc(cx*2+2, cy*2+1, 81, 3)
cx++
}
else {
; dead end, pop stack
pathstackptr--
if pathstackptr==65535 {
txt.print("no solution?!\n")
return true
}
@(celladdr(cx,cy)) |= BACKTRACKED
;txt.setcc(cx*2+1, cy*2+1, 81, 2)
when @(pathstack + pathstackptr) {
UP -> {
;txt.setcc(cx*2+1, cy*2+2, 81, 9)
cy++
}
DOWN -> {
;txt.setcc(cx*2+1, cy*2, 81, 9)
cy--
}
LEFT -> {
;txt.setcc(cx*2+2, cy*2+1, 81, 9)
cx++
}
RIGHT -> {
;txt.setcc(cx*2, cy*2+1, 81, 9)
cx--
score++
}
}
goto solve_loop
}
pathstackptr++
if pathstackptr==max_path_length {
txt.print("stack overflow, path too long\n")
return true
}
@(celladdr(cx,cy)) |= WALKED
;txt.setcc(cx*2+1, cy*2+1, 81, 1)
}
return false
}
sub celladdr(ubyte cx, ubyte cy) -> uword {
return cells+(numCellsHoriz as uword)*cy+cx
}
sub drawCell(ubyte cx, ubyte cy) {
return
; ubyte x = cx * 2 + 1
; ubyte y = cy * 2 + 1
; ubyte doors = @(celladdr(cx,cy))
; if doors & UP !=0
; txt.setcc(x, y-1, ' ', EMPTYCOLOR)
; if doors & RIGHT !=0
; txt.setcc(x+1, y, ' ', EMPTYCOLOR)
; if doors & DOWN !=0
; txt.setcc(x, y+1, ' ', EMPTYCOLOR)
; if doors & LEFT !=0
; txt.setcc(x-1, y, ' ', EMPTYCOLOR)
; if doors & STONE !=0
; txt.setcc(x, y, 160, WALLCOLOR)
; else
; txt.setcc(x, y, 32, EMPTYCOLOR)
;
; if doors & WALKED !=0
; txt.setcc(x, y, 81, 1)
; if doors & BACKTRACKED !=0
; txt.setcc(x, y, 81, 2)
}
sub initialize() {
sys.memset(cells, numCellsHoriz*numCellsVert, STONE)
; txt.fill_screen(160, WALLCOLOR)
drawStartFinish()
}
sub drawStartFinish() {
; txt.setcc(startCx*2+1,startCy*2+1,sc:'s',5)
; txt.setcc(finishCx*2+1, finishCy*2+1, sc:'f', 13)
}
}
+63
View File
@@ -0,0 +1,63 @@
%import textio
; Recursive N-Queens solver.
; The problem is: find all possible ways to place 8 Queen chess pieces on a chess board, so that none of them attacks any other.
; (this program prints all solutions without taking mirroring and flipping the chess board into account)
; Note: this program can be compiled for multiple target systems.
queens {
const ubyte NUMQUEENS=8
ubyte[NUMQUEENS] board
sub could_place(ubyte row, ubyte col) -> bool {
if row==0
return true
ubyte i
for i in 0 to row-1 {
if board[i]==col or board[i]-i==col-row or board[i]+i==col+row
return false
}
return true
}
uword solution_count
uword maximum_duration
sub place_queen(ubyte row) -> bool {
if row == NUMQUEENS {
solution_count++
txt.chrout('.')
return cbm.RDTIM16()<maximum_duration
}
bool continue_running=true
ubyte col
for col in 0 to NUMQUEENS-1 {
if could_place(row, col) {
board[row] = col
; we need to save the local variables row and col.
sys.push(row)
sys.push(col)
continue_running = place_queen(row + 1)
; restore the local variables after the recursive call.
col = sys.pop()
row = sys.pop()
board[row] = 0
if not continue_running
break
}
}
return continue_running
}
sub bench(uword max_time) -> uword {
solution_count = 0
maximum_duration = max_time
txt.nl()
cbm.SETTIM(0,0,0)
while cbm.RDTIM16() < maximum_duration {
void place_queen(0)
}
return solution_count
}
}
+990
View File
@@ -0,0 +1,990 @@
%import textio
%import conv
%import string
%import string
textelite {
const ubyte numforLave = 7 ; Lave is 7th generated planet in galaxy one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
uword num_commands
sub bench(uword max_time) -> uword {
num_commands = 0
txt.lowercase()
cbm.SETTIM(0,0,0)
while cbm.RDTIM16()<max_time {
reinit()
run_commands(max_time)
}
return num_commands
}
sub reinit() {
;txt.clear_screen()
;txt.print("\n --- TextElite v1.3 ---\n")
txt.print("\nnew game\n")
elite_planet.set_seed(0, 0)
elite_galaxy.travel_to(1, numforLave)
elite_market.init(0) ; Lave's market is seeded with 0
elite_ship.init()
elite_planet.display(false, 0)
input_index = 0
}
sub run_commands(uword max_time) {
while cbm.RDTIM16() < max_time {
str input = "????????"
;txt.print("\nCash: ")
;elite_util.print_10s(elite_ship.cash)
;txt.print("\nCommand (?=help): ")
ubyte num_chars = next_input(input)
;txt.nl()
if num_chars!=0 {
when input[0] {
'q' -> {
bool has_error = false
if elite_galaxy.number != 2 {
txt.print("\nERROR: galaxy is not 2: ")
txt.print_ub(elite_galaxy.number)
txt.nl()
has_error=true
}
if elite_planet.number != 164 {
txt.print("\nERROR: planet is not 164: ")
txt.print_ub(elite_planet.number)
txt.nl()
has_error=true
}
if elite_planet.x != 116 {
txt.print("\nERROR: planet.x is not 116: ")
txt.print_ub(elite_planet.x)
txt.nl()
has_error=true
}
if elite_planet.y != 201 {
txt.print("\nERROR: planet.y is not 201: ")
txt.print_ub(elite_planet.y)
txt.nl()
has_error=true
}
if "ribeen" != elite_planet.name {
txt.print("\nERROR: planet.name is not 'ribeen': ")
txt.print(elite_planet.name)
txt.nl()
has_error=true
}
if elite_ship.cash != 1212 {
txt.print("\nERROR: cash is not 1212: ")
txt.print_uw(elite_ship.cash)
txt.nl()
has_error=true
}
if elite_ship.fuel != 50 {
txt.print("\nERROR: fuel is not 50:")
txt.print_ub(elite_ship.fuel)
txt.nl()
has_error=true
}
if elite_ship.cargohold[0] != 3 {
txt.print("\nERROR: food is not 3:")
txt.print_ub(elite_ship.cargohold[0])
txt.nl()
has_error=true
}
if elite_ship.cargohold[1] != 0 {
txt.print("\nERROR: textiles is not 0:")
txt.print_ub(elite_ship.cargohold[1])
txt.nl()
has_error=true
}
if has_error
sys.exit(1)
return
}
'b' -> elite_trader.do_buy()
's' -> elite_trader.do_sell()
'f' -> elite_trader.do_fuel()
'j' -> elite_trader.do_jump()
't' -> elite_trader.do_teleport()
'g' -> elite_trader.do_next_galaxy()
'i' -> elite_trader.do_info()
'm' -> {
if input[1]=='a' and input[2]=='p'
elite_trader.do_map()
else
elite_trader.do_show_market()
}
'l' -> elite_trader.do_local()
'c' -> elite_trader.do_cash()
'h' -> elite_trader.do_hold()
}
num_commands++
}
}
}
str[] inputs = [
"i",
"diso",
"i",
"lave",
"m",
"b",
"food",
"15",
"map",
"g",
"map",
"l",
"j",
"zao",
"s",
"food",
"12",
"tele",
"quti",
"tele",
"aro",
"i",
"diso",
"i",
"lave",
"i",
"zao",
"galhyp",
"fuel",
"20",
"j",
"rib",
"i",
"rib",
"i",
"tiri",
"q",
0
]
ubyte input_index
sub next_input(str buffer) -> ubyte {
input_index++
return string.copy(inputs[input_index], buffer)
}
}
elite_trader {
str input = "??????????"
ubyte num_chars
sub do_jump() {
;txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
;txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = elite_ship.fuel
elite_ship.fuel = 255
jump_to_system()
elite_ship.fuel = fuel
}
sub jump_to_system() {
void textelite.next_input(input)
ubyte current_planet = elite_planet.number
ubyte x = elite_planet.x
ubyte y = elite_planet.y
if elite_galaxy.search_closest_planet(input) {
ubyte distance = elite_planet.distance(x, y)
if distance <= elite_ship.fuel {
elite_galaxy.init_market_for_planet()
elite_ship.fuel -= distance
;txt.print("\n\nHyperspace jump! Arrived at:\n")
elite_planet.display(true,0 )
return
}
;txt.print("\nInsufficient fuel\n")
} else {
;txt.print(" Not found!\n")
}
elite_galaxy.travel_to(elite_galaxy.number, current_planet)
}
sub do_buy() {
;txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void textelite.next_input(commodity)
ubyte ci = elite_market.match(commodity)
if ci & 128 !=0 {
txt.print("Unknown\n")
} else {
;txt.print("\nHow much? ")
void textelite.next_input(input)
ubyte amount = conv.str2ubyte(input)
if elite_market.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = elite_market.current_price[ci] * amount
;txt.print(" Total price: ")
;elite_util.print_10s(price)
if price > elite_ship.cash {
txt.print(" Not enough cash!\n")
} else {
elite_ship.cash -= price
elite_ship.cargohold[ci] += amount
elite_market.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
;txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void textelite.next_input(commodity)
ubyte ci = elite_market.match(commodity)
if ci & 128 !=0 {
txt.print("Unknown\n")
} else {
;txt.print("\nHow much? ")
void textelite.next_input(input)
ubyte amount = conv.str2ubyte(input)
if elite_ship.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = elite_market.current_price[ci] * amount
;txt.print(" Total price: ")
;elite_util.print_10s(price)
elite_ship.cash += price
elite_ship.cargohold[ci] -= amount
elite_market.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
;txt.print("\nBuy fuel. Amount? ")
void textelite.next_input(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = elite_ship.Max_fuel - elite_ship.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * elite_ship.Fuel_cost
if price > elite_ship.cash {
txt.print("Not enough cash!\n")
} else {
elite_ship.cash -= price
elite_ship.fuel += buy_fuel
}
}
sub do_cash() {
;txt.print("\nCheat! Set cash amount: ")
void textelite.next_input(input)
elite_ship.cash = conv.str2uword(input)
}
sub do_hold() {
;txt.print("\nCheat! Set cargohold size: ")
void textelite.next_input(input)
elite_ship.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy() {
txt.print("\n>>>>> Galaxy Hyperjump!\n")
elite_galaxy.travel_to(elite_galaxy.number+1, elite_planet.number)
elite_planet.display(false, 0)
}
sub do_info() {
;txt.print("\nSystem name (empty=current): ")
num_chars = textelite.next_input(input)
if num_chars!=0 {
ubyte current_planet = elite_planet.number
ubyte x = elite_planet.x
ubyte y = elite_planet.y
if elite_galaxy.search_closest_planet(input) {
ubyte distance = elite_planet.distance(x, y)
elite_planet.display(false, distance)
} else {
;txt.print(" Not found!")
}
elite_galaxy.travel_to(elite_galaxy.number, current_planet)
} else {
elite_planet.display(false, 0)
}
}
sub do_local() {
elite_galaxy.local_area()
}
sub do_map() {
;txt.print("\n(l)ocal or (g)alaxy starmap? ")
num_chars = textelite.next_input(input)
if num_chars!=0 {
elite_galaxy.starmap(input[0]=='l')
}
}
sub do_show_market() {
elite_market.display()
;txt.print("\nFuel: ")
;elite_util.print_10s(elite_ship.fuel)
;txt.print(" Cargohold space: ")
;txt.print_ub(elite_ship.cargo_free())
;txt.print("t\n")
}
}
elite_ship {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel
uword cash
ubyte[17] cargohold
sub init() {
sys.memset(cargohold, len(cargohold), 0)
fuel = Max_fuel
cash = 1000
}
}
elite_market {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity
uword[17] current_price
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all commands are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = elite_planet.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80 !=0
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
return
; ubyte ci
; txt.nl()
; elite_planet.print_name_uppercase()
; txt.print(" trade market:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
; for ci in 0 to len(names)-1 {
; elite_util.print_right(13, names[ci])
; txt.print(" ")
; elite_util.print_10s(current_price[ci])
; txt.column(24)
; txt.print_ub(current_quantity[ci])
; txt.chrout(' ')
; when units[ci] {
; 0 -> txt.chrout('t')
; 1 -> txt.print("kg")
; 2 -> txt.chrout('g')
; }
; txt.column(32)
; txt.print_ub(elite_ship.cargohold[ci])
; txt.nl()
; }
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if elite_util.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
elite_galaxy {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxynum) {
number = 1
elite_planet.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxynum-1 {
nextgalaxy()
}
}
sub nextgalaxy() {
textelite.num_commands++
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxynum, ubyte system) {
init(galaxynum)
generate_next_planet() ; always at least planet 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet()
textelite.num_commands++
}
elite_planet.name = make_current_planet_name()
init_market_for_planet()
}
sub init_market_for_planet() {
elite_market.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet(uword nameptr) -> bool {
textelite.num_commands++
ubyte x = elite_planet.x
ubyte y = elite_planet.y
ubyte current_planet_num = elite_planet.number
init(number)
bool found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet()
elite_planet.name = make_current_planet_name()
if elite_util.prefix_matches(nameptr, elite_planet.name) {
ubyte distance = elite_planet.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet_num)
return found
}
sub local_area() {
ubyte current_planet = elite_planet.number
ubyte px = elite_planet.x
ubyte py = elite_planet.y
ubyte pn = 0
init(number)
; txt.print("\nGalaxy #")
; txt.print_ub(number)
; txt.print(" - systems in vicinity:\n")
do {
generate_next_planet()
ubyte distance = elite_planet.distance(px, py)
if distance <= elite_ship.Max_fuel {
; if distance <= elite_ship.fuel
; txt.chrout('*')
; else
; txt.chrout('-')
; txt.spc()
elite_planet.name = make_current_planet_name()
elite_planet.display(true, distance)
}
pn++
} until pn==0
travel_to(number, current_planet)
}
sub starmap(bool local) {
ubyte current_planet = elite_planet.number
ubyte px = elite_planet.x
ubyte py = elite_planet.y
str current_name = " " ; 8 max
ubyte pn = 0
current_name = elite_planet.name
init(number)
; txt.clear_screen()
; txt.print("Galaxy #")
; txt.print_ub(number)
; if local
; txt.print(" - local systems")
; else
; txt.print(" - galaxy")
; txt.print(" starmap:\n")
ubyte max_distance = 255
if local
max_distance = elite_ship.Max_fuel
ubyte home_sx
ubyte home_sy
ubyte home_distance
do {
generate_next_planet()
ubyte distance = elite_planet.distance(px, py)
if distance <= max_distance {
elite_planet.name = make_current_planet_name()
elite_planet.name[0] = string.upperchar(elite_planet.name[0])
uword tx = elite_planet.x
uword ty = elite_planet.y
if local {
tx = tx + 24 - px
ty = ty + 24 - py
}
ubyte sx = display_scale_x(tx)
ubyte sy = display_scale_y(ty)
ubyte char = '*'
if elite_planet.number==current_planet
char = '%'
if local {
print_planet_details(elite_planet.name, sx, sy, distance)
} else if elite_planet.number==current_planet {
home_distance = distance
home_sx = sx
home_sy = sy
}
; txt.setchr(2+sx, 2+sy, char)
}
pn++
} until pn==0
if not local
print_planet_details(current_name, home_sx, home_sy, home_distance)
; if local
; txt.plot(0, display_scale_y(64) + 4)
; else
; txt.plot(0, display_scale_y(256) + 4 as ubyte)
travel_to(number, current_planet)
sub print_planet_details(str name, ubyte screenx, ubyte screeny, ubyte d) {
return
; txt.plot(2+screenx-2, 2+screeny+1)
; txt.print(name)
; if d!=0 {
; txt.plot(2+screenx-2, 2+screeny+2)
; elite_util.print_10s(d)
; txt.print(" LY")
; }
}
sub display_scale_x(uword x) -> ubyte {
if local
return x/2 as ubyte
return x/8 as ubyte
}
sub display_scale_y(uword y) -> ubyte {
if local
return y/4 as ubyte
return y/16 as ubyte
}
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
bool longname
sub generate_next_planet() {
determine_planet_properties()
longname = lsb(seed[0]) & 64 !=0
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet_properties() {
; create the planet's characteristics
elite_planet.number++
elite_planet.x = msb(seed[1])
elite_planet.y = msb(seed[0])
elite_planet.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
elite_planet.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if elite_planet.govtype <= 1
elite_planet.economy = (elite_planet.economy | 2)
elite_planet.techlevel = (msb(seed[1]) & 3) + (elite_planet.economy ^ 7)
elite_planet.techlevel += elite_planet.govtype >> 1
if elite_planet.govtype & 1 !=0
elite_planet.techlevel++
elite_planet.population = 4 * elite_planet.techlevel + elite_planet.economy
elite_planet.population += elite_planet.govtype + 1
elite_planet.productivity = ((elite_planet.economy ^ 7) + 3) * (elite_planet.govtype + 4)
elite_planet.productivity *= elite_planet.population * 8
ubyte seed2_msb = msb(seed[2])
elite_planet.radius = mkword((seed2_msb & 15) + 11, elite_planet.x)
elite_planet.species_is_alien = lsb(seed[2]) & 128 !=0 ; bit 7 of w2_lo
if elite_planet.species_is_alien {
elite_planet.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
elite_planet.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
elite_planet.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
elite_planet.species_kind = (elite_planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
elite_planet.goatsoup_seed[0] = lsb(seed[1])
elite_planet.goatsoup_seed[1] = msb(seed[1])
elite_planet.goatsoup_seed[2] = lsb(seed[2])
elite_planet.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
xh <<= 1 ; make sure carry flag is not used on first shift!
rol(xl)
return mkword(xh, xl)
}
}
elite_planet {
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet", "world", "place", "little planet", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] @shared wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy, then increases by 1 for each generated planet
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
bool species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str randname = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte xx = goatsoup_rnd_number() & $3e
if pairs0[xx] != '.' {
randname[nx] = pairs0[xx]
nx++
}
xx++
if pairs0[xx] != '.' {
randname[nx] = pairs0[xx]
nx++
}
}
randname[nx] = 0
randname[0] = string.upperchar(randname[0])
return randname
}
sub goatsoup_rnd_number() -> ubyte {
ubyte xx = goatsoup_rnd[0] * 2
uword a = xx as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = xx
xx = goatsoup_rnd[1]
ubyte ac = xx + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = xx
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet_result
reset_rnd()
recursive_soup()
return planet_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = ((rnr >= $33) as ubyte) + ((rnr >= $66) as ubyte) + ((rnr >= $99) as ubyte) + ((rnr >= $CC) as ubyte)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = string.upperchar(name[0])
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = string.upperchar(name[0])
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc in ['e', 'o', 0]
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(bool compressed, ubyte distance) {
txt.print(soup())
txt.nl()
}
sub getword(ubyte listnum, ubyte wordidx) -> uword {
uword list = wordlists[listnum-$81]
return peekw(list + wordidx*2)
}
}
elite_util {
sub prefix_matches(uword prefixptr, uword stringptr) -> bool {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
if string.lowerchar(pc)!=string.lowerchar(sc)
return false
prefixptr++
stringptr++
}
}
}
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/compiled" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+112
View File
@@ -0,0 +1,112 @@
; This benchmark program is meant to check for regressions in the
; Prog8 compiler's code-generator (performance wise).
;
; As the X16 computer is a more or less fixed system, it's not very useful
; to benchmark the computer itself with.
%import textio
%import b_adpcm
%import b_circles
%import b_3d
%import b_life
%import b_mandelbrot
%import b_queens
%import b_textelite
%import b_maze
%zeropage basicsafe
%option no_sysinit
main {
str[20] benchmark_names
uword[20] benchmark_score
sub start() {
ubyte benchmark_number
void cx16.set_screen_mode(3)
txt.color2(1, 6)
txt.clear_screen()
txt.print("\n\n\n prog8 compiler benchmark tests.\n")
sys.wait(60)
benchmark_number = 0
announce_benchmark("maze solver")
benchmark_score[benchmark_number] = maze.bench(300)
benchmark_number++
announce_benchmark("n-queens")
benchmark_score[benchmark_number] = queens.bench(300)
benchmark_number++
announce_benchmark("mandelbrot (floating point)")
benchmark_score[benchmark_number] = mandelbrot.calc(400)
benchmark_number++
announce_benchmark("game of life")
benchmark_score[benchmark_number] = life.benchmark(300)
benchmark_number++
announce_benchmark("3d model rotation")
benchmark_score[benchmark_number] = rotate3d.benchmark(300)
benchmark_number++
announce_benchmark("adpcm audio decoding")
benchmark_score[benchmark_number] = adpcm.decode_benchmark(300)
benchmark_number++
announce_benchmark("circles with gfx2")
benchmark_score[benchmark_number] = circles.draw(false, 300)
benchmark_number++
; announce_benchmark("circles with kernal")
; benchmark_score[benchmark_number] = circles.draw(true, 300)
; benchmark_number++
announce_benchmark("text-elite")
benchmark_score[benchmark_number] = textelite.bench(120)
benchmark_number++
benchmark_names[benchmark_number] = 0
benchmark_score[benchmark_number] = 0
void cx16.set_screen_mode(3)
txt.uppercase()
txt.color2(1, 6)
uword final_score
benchmark_number = 0
txt.print("\nscore benchmark\n\n")
do {
txt.spc()
txt.print_uw(benchmark_score[benchmark_number])
txt.column(6)
txt.print(benchmark_names[benchmark_number])
final_score += benchmark_score[benchmark_number]
txt.nl()
benchmark_number++
} until benchmark_names[benchmark_number]==0
txt.print("\n\nfinal score : ")
txt.print_uw(final_score)
txt.nl()
sub announce_benchmark(str name) {
benchmark_names[benchmark_number] = name
void cx16.set_screen_mode(3)
txt.uppercase()
txt.color2(1, 6)
txt.clear_screen()
txt.plot(4, 6)
txt.print(benchmark_names[benchmark_number])
txt.nl()
sys.wait(60)
}
}
}
+10 -1
View File
@@ -21,7 +21,16 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
else
"&"
}
is PtArray -> "array len=${node.children.size} ${type(node.type)}"
is PtArray -> {
val valuelist = node.children.map {
when (it) {
is PtNumber -> it.number.toString()
is PtIdentifier -> it.name
else -> "?"
}
}.joinToString(", ")
"array len=${node.children.size} ${type(node.type)} [ $valuelist ]"
}
is PtArrayIndexer -> "<arrayindexer> ${type(node.type)} ${if(node.splitWords) "[splitwords]" else ""}"
is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}"
is PtBuiltinFunctionCall -> {
@@ -128,6 +128,7 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"rrestore" to FSignature(false, emptyList(), null),
"memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
"callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD),
"callfar2" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("argA", arrayOf(DataType.UBYTE)), FParam("argX", arrayOf(DataType.UBYTE)), FParam("argY", arrayOf(DataType.UBYTE)), FParam("argC", arrayOf(DataType.BOOL))), DataType.UWORD),
"call" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
)
@@ -104,7 +104,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
is PtIdentifier -> parent.children[index] = node.prefix(parent, st)
is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last")
is PtJump -> parent.children[index] = node.prefix(parent, st)
is PtVariable -> parent.children[index] = node.prefix(st)
is PtVariable -> parent.children[index] = node.prefix(parent, st)
else -> throw AssemblyError("weird node to prefix $node")
}
}
@@ -135,7 +135,7 @@ private fun prefixScopedName(name: String, type: Char): String {
return prefixed.joinToString(".")
}
private fun PtVariable.prefix(st: SymbolTable): PtVariable {
private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
name = prefixScopedName(name, 'v')
if(value==null)
return this
@@ -163,7 +163,9 @@ private fun PtVariable.prefix(st: SymbolTable): PtVariable {
else -> throw AssemblyError("weird array value element $elt")
}
}
PtVariable(name, type, zeropage, newValue, arraySize, position)
val result = PtVariable(name, type, zeropage, newValue, arraySize, position)
result.parent = parent
result
}
else this
}
@@ -516,34 +516,35 @@ private fun optimizeJsrRtsAndOtherCombinations(linesByFour: Sequence<List<Indexe
val first = lines[0].value
val second = lines[1].value
val third = lines[2].value
if ((" jsr" in first || "\tjsr" in first ) && (" rts" in second || "\trts" in second)) {
mods += Modification(lines[0].index, false, lines[0].value.replace("jsr", "jmp"))
mods += Modification(lines[1].index, true, null)
}
else if (" rts" in first || "\trts" in first) {
if (" jmp" in second || "\tjmp" in second)
mods += Modification(lines[1].index, true, null)
else if (" bra" in second || "\tbra" in second)
mods += Modification(lines[1].index, true, null)
else if (" bcc" in second || "\tbcc" in second)
mods += Modification(lines[1].index, true, null)
else if (" bcs" in second || "\tbcs" in second)
mods += Modification(lines[1].index, true, null)
else if (" beq" in second || "\tbeq" in second)
mods += Modification(lines[1].index, true, null)
else if (" bne" in second || "\tbne" in second)
mods += Modification(lines[1].index, true, null)
else if (" bmi" in second || "\tbmi" in second)
mods += Modification(lines[1].index, true, null)
else if (" bpl" in second || "\tbpl" in second)
mods += Modification(lines[1].index, true, null)
else if (" bvs" in second || "\tbvs" in second)
mods += Modification(lines[1].index, true, null)
else if (" bvc" in second || "\tbvc" in second)
mods += Modification(lines[1].index, true, null)
}
if (!haslabel(second)) {
if(!haslabel(second)) {
if ((" jsr" in first || "\tjsr" in first ) && (" rts" in second || "\trts" in second)) {
mods += Modification(lines[0].index, false, lines[0].value.replace("jsr", "jmp"))
mods += Modification(lines[1].index, true, null)
}
else if (" rts" in first || "\trts" in first) {
if (" jmp" in second || "\tjmp" in second)
mods += Modification(lines[1].index, true, null)
else if (" bra" in second || "\tbra" in second)
mods += Modification(lines[1].index, true, null)
else if (" bcc" in second || "\tbcc" in second)
mods += Modification(lines[1].index, true, null)
else if (" bcs" in second || "\tbcs" in second)
mods += Modification(lines[1].index, true, null)
else if (" beq" in second || "\tbeq" in second)
mods += Modification(lines[1].index, true, null)
else if (" bne" in second || "\tbne" in second)
mods += Modification(lines[1].index, true, null)
else if (" bmi" in second || "\tbmi" in second)
mods += Modification(lines[1].index, true, null)
else if (" bpl" in second || "\tbpl" in second)
mods += Modification(lines[1].index, true, null)
else if (" bvs" in second || "\tbvs" in second)
mods += Modification(lines[1].index, true, null)
else if (" bvc" in second || "\tbvc" in second)
mods += Modification(lines[1].index, true, null)
}
if ((" lda" in first || "\tlda" in first) && (" cmp #0" in second || "\tcmp #0" in second) ||
(" ldx" in first || "\tldx" in first) && (" cpx #0" in second || "\tcpx #0" in second) ||
(" ldy" in first || "\tldy" in first) && (" cpy #0" in second || "\tcpy #0" in second)
@@ -64,6 +64,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"rrestore" -> funcRrestore()
"cmp" -> funcCmp(fcall)
"callfar" -> funcCallFar(fcall, resultRegister)
"callfar2" -> funcCallFar2(fcall, resultRegister)
"call" -> funcCall(fcall)
"prog8_ifelse_bittest_set" -> throw AssemblyError("prog8_ifelse_bittest_set() should have been translated as part of an ifElse statement")
"prog8_ifelse_bittest_notset" -> throw AssemblyError("prog8_ifelse_bittest_notset() should have been translated as part of an ifElse statement")
@@ -266,33 +267,110 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcCall(fcall: PtBuiltinFunctionCall) {
// note: the routine can return a word value (in AY)
val constAddr = fcall.args[0].asConstInteger()
if(constAddr!=null) {
asmgen.out(" jsr ${constAddr.toHex()}")
} else {
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) // jump address
asmgen.out("""
sta (+)+1
sty (+)+2
+ jsr 0 ; modified""")
return
}
// note: the routine can return a word value (in AY)
val identifier = fcall.args[0] as? PtIdentifier
if(identifier!=null) {
asmgen.out("""
; push a return address so the jmp becomes indirect jsr
lda #>((+)-1)
pha
lda #<((+)-1)
pha
jmp (${asmgen.asmSymbolName(identifier)})
+""")
return
}
asmgen.assignExpressionToVariable(fcall.args[0], asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD) // jump address
asmgen.out("""
; push a return address so the jmp becomes indirect jsr
lda #>((+)-1)
pha
lda #<((+)-1)
pha
jmp (P8ZP_SCRATCH_W2)
+""")
}
private fun funcCallFar(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
if(asmgen.options.compTarget.name != "cx16")
throw AssemblyError("callfar only works on cx16 target at this time")
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // bank
asmgen.out(" sta (++)+0")
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY) // jump address
asmgen.out(" sta (+)+0 | sty (+)+1")
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.AY) // uword argument
asmgen.out("""
jsr cx16.JSRFAR
+ .word 0
+ .byte 0""")
val constBank = fcall.args[0].asConstInteger()
val constAddress = fcall.args[1].asConstInteger()
if(constBank!=null && constAddress!=null) {
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.AY) // uword argument
asmgen.out("""
jsr cx16.JSRFAR
.word ${constAddress.toHex()}
.byte $constBank""")
} else {
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // bank
asmgen.out(" sta (++)+0")
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY) // jump address
asmgen.out(" sta (+)+0 | sty (+)+1")
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.AY) // uword argument
asmgen.out("""
jsr cx16.JSRFAR
+ .word 0
+ .byte 0""")
}
// note that by convention the values in A+Y registers are now the return value of the call.
if(resultRegister!=null) {
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister, false, fcall.position, null, asmgen), RegisterOrPair.AY)
}
}
private fun funcCallFar2(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
if(asmgen.options.compTarget.name != "cx16")
throw AssemblyError("callfar2 only works on cx16 target at this time")
fun assignArgs() {
fun assign(value: PtExpression, register: Char) {
when(value) {
is PtBool -> asmgen.out(" ld$register #${value.asInt()}")
is PtNumber -> asmgen.out(" ld$register #${value.number.toInt()}")
is PtIdentifier -> asmgen.out(" ld$register ${asmgen.asmVariableName(value)}")
else -> TODO("callfar2: support non-simple expressions for arguments")
}
}
assign(fcall.args[2], 'a')
assign(fcall.args[3], 'x')
assign(fcall.args[4], 'y')
val carry = fcall.args[5].asConstInteger()
if(carry!=null)
asmgen.out(if(carry==0) " clc" else " sec")
else
TODO("callfar2: support non-const argument values")
}
val constBank = fcall.args[0].asConstInteger()
val constAddress = fcall.args[1].asConstInteger()
if(constBank!=null && constAddress!=null) {
assignArgs()
asmgen.out("""
jsr cx16.JSRFAR
.word ${constAddress.toHex()}
.byte $constBank""")
} else {
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // bank
asmgen.out(" sta (++)+0")
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY) // jump address
asmgen.out(" sta (+)+0 | sty (+)+1")
assignArgs()
asmgen.out("""
jsr cx16.JSRFAR
+ .word 0
+ .byte 0""")
}
// note that by convention the values in A+Y registers are now the return value of the call.
if(resultRegister!=null) {
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister, false, fcall.position, null, asmgen), RegisterOrPair.AY)
@@ -1122,7 +1200,44 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
else -> throw AssemblyError("invalid reg")
}
} else {
when(resultRegister) {
if(arg is PtArrayIndexer && resultRegister in setOf(null, RegisterOrPair.A, RegisterOrPair.Y, RegisterOrPair.X)) {
// just read the msb byte out of the word array
if(arg.splitWords) {
val arrayVar = asmgen.asmVariableName(arg.variable)+"_msb"
when(resultRegister) {
null, RegisterOrPair.A -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.Y)
asmgen.out(" lda $arrayVar,y")
}
RegisterOrPair.Y -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.X)
asmgen.out(" ldy $arrayVar,x")
}
RegisterOrPair.X -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.Y)
asmgen.out(" ldx $arrayVar,y")
}
else -> throw AssemblyError("invalid reg")
}
} else {
val arrayVar = asmgen.asmVariableName(arg.variable)
when(resultRegister) {
null, RegisterOrPair.A -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.Y)
asmgen.out(" lda $arrayVar+1,y")
}
RegisterOrPair.Y -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.X)
asmgen.out(" ldy $arrayVar+1,x")
}
RegisterOrPair.X -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.Y)
asmgen.out(" ldx $arrayVar+1,y")
}
else -> throw AssemblyError("invalid reg")
}
}
} else when(resultRegister) {
null, RegisterOrPair.A -> {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" tya")
@@ -1137,6 +1252,23 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" pla")
}
RegisterOrPair.AY -> {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" tya | ldy #0 | cmp #0")
}
RegisterOrPair.AX -> {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AX)
asmgen.out(" txa | ldx #0 | cmp #0")
}
RegisterOrPair.XY -> {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.XY)
asmgen.out(" tya | tax | ldy #0 | cpx #0")
}
in Cx16VirtualRegisters -> {
val reg = "cx16.${resultRegister.toString().lowercase()}"
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" sty ${reg}L | lda #0 | sta ${reg}H | lda ${reg}L")
}
else -> throw AssemblyError("invalid reg")
}
}
@@ -1178,7 +1310,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
RegisterOrPair.Y -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.X)
asmgen.out(" lda $arrayVar,x")
asmgen.out(" ldy $arrayVar,x")
}
RegisterOrPair.X -> {
asmgen.loadScaledArrayIndexIntoRegister(arg, CpuRegister.Y)
@@ -1216,11 +1348,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.out(" ldy #0 | cpx #0")
}
in Cx16VirtualRegisters -> {
asmgen.assignExpressionToRegister(arg, resultRegister)
val zero = PtNumber(DataType.UBYTE, 0.0, Position.DUMMY)
zero.parent=fcall
assignAsmGen.assignExpressionToVariable(zero, "cx16.${resultRegister.toString().lowercase()}H", DataType.UBYTE)
asmgen.out(" lda cx16.r0L")
val reg = "cx16.${resultRegister.toString().lowercase()}"
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" sta ${reg}L | ldy #0 | sty ${reg}H | cmp #0")
}
else -> throw AssemblyError("invalid reg")
}
@@ -89,6 +89,12 @@ internal class ProgramAndVarsGen(
OutputType.RAW -> {
asmgen.out("; ---- raw assembler program ----")
asmgen.out("* = ${options.loadAddress.toHex()}")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit)
asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2")
}
OutputType.PRG -> {
when(options.launcher) {
@@ -103,13 +109,20 @@ internal class ProgramAndVarsGen(
asmgen.out(" .null $9e, format(' %d ', prog8_entrypoint), $3a, $8f, ' prog8'")
asmgen.out("+\t.word 0")
asmgen.out("prog8_entrypoint\t; assembly code starts here")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit)
asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2")
}
CbmPrgLauncherType.NONE -> {
// this is the same as RAW
asmgen.out("; ---- program without basic sys call ----")
asmgen.out("* = ${options.loadAddress.toHex()}")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit)
asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2")
@@ -119,6 +132,9 @@ internal class ProgramAndVarsGen(
OutputType.XEX -> {
asmgen.out("; ---- atari xex program ----")
asmgen.out("* = ${options.loadAddress.toHex()}")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit)
asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2")
@@ -149,7 +165,10 @@ internal class ProgramAndVarsGen(
asmgen.out(" jsr p8b_main.p8s_start | lda #0 | sta ${"$"}ff00")
asmgen.out(" jmp sys.cleanup_at_exit")
}
else -> asmgen.jmp("p8b_main.p8s_start")
else -> {
asmgen.out(" jsr p8b_main.p8s_start")
asmgen.out(" jmp sys.cleanup_at_exit")
}
}
}
@@ -451,22 +470,10 @@ internal class ProgramAndVarsGen(
}
private fun entrypointInitialization() {
asmgen.out("; program startup initialization")
asmgen.out(" cld | tsx | stx prog8_lib.orig_stackpointer ; required for sys.exit()")
// set full BSS area to zero
asmgen.out("""
.if prog8_bss_section_size>0
; reset all variables in BSS section to zero
lda #<prog8_bss_section_start
ldy #>prog8_bss_section_start
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldx #<prog8_bss_section_size
ldy #>prog8_bss_section_size
lda #0
jsr prog8_lib.memset
.endif""")
// zero out the BSS area first, before setting the variable init values
asmgen.out(" jsr prog8_lib.program_startup_clear_bss")
// initialize block-level (global) variables at program start
blockVariableInitializers.forEach {
if (it.value.isNotEmpty())
asmgen.out(" jsr ${it.key.name}.prog8_init_vars")
@@ -517,9 +524,7 @@ internal class ProgramAndVarsGen(
arrayVariable2asm(varname, it.alloc.dt, it.value, null)
}
asmgen.out("""+
clv
clc""")
asmgen.out("+")
}
private class ZpStringWithInitial(
@@ -579,7 +584,7 @@ internal class ProgramAndVarsGen(
asmgen.out("")
val (varsNoInit, varsWithInit) = variables.partition { it.uninitialized }
if(varsNoInit.isNotEmpty()) {
asmgen.out("; non-zeropage variables without initialization value")
asmgen.out("; non-zeropage variables")
asmgen.out(" .section BSS")
varsNoInit.sortedWith(compareBy<StStaticVariable> { it.name }.thenBy { it.dt }).forEach {
uninitializedVariable2asm(it)
@@ -588,7 +593,7 @@ internal class ProgramAndVarsGen(
}
if(varsWithInit.isNotEmpty()) {
asmgen.out("; non-zeropage variables")
asmgen.out("; non-zeropage variables with init value")
val (stringvars, othervars) = varsWithInit.sortedBy { it.name }.partition { it.dt == DataType.STR }
stringvars.forEach {
outputStringvar(
@@ -175,17 +175,14 @@ internal class AnyExprAsmGen(
private fun assignFloatOperandsToFACandARG(left: PtExpression, right: PtExpression) {
when(asmgen.options.compTarget.name) {
C64Target.NAME -> {
// c64 has a quirk: always make sure FAC2 is loaded last (done using CONUPK) otherwise the result will be corrupt on C64
// this requires some more forced copying around of float values in certain cases
if (right.isSimple()) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1, true)
asmgen.assignExpressionToRegister(right, RegisterOrPair.FAC2, true)
} else {
asmgen.assignExpressionToRegister(right, RegisterOrPair.FAC1, true)
asmgen.pushFAC1()
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1, true)
asmgen.popFAC2()
}
// C64 math library has a quirk: you have always make sure FAC2/ARG is loaded last (done using CONUPK)
// otherwise the result of certain floating point operations such as FDIVT will be wrong.
// see https://www.c64-wiki.com/wiki/CONUPK
// Unfortunately this means we have to push and pop an intermediary floating point value to and from memory.
asmgen.assignExpressionToRegister(right, RegisterOrPair.FAC1, true)
asmgen.pushFAC1()
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1, true)
asmgen.popFAC2()
}
Cx16Target.NAME -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1, true)
@@ -17,6 +17,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
"divmod__uword" -> funcDivmod(call, IRDataType.WORD)
"rsave", "rrestore" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore
"callfar" -> funcCallfar(call)
"callfar2" -> funcCallfar2(call)
"call" -> funcCall(call)
"msb" -> funcMsb(call)
"lsb" -> funcLsb(call)
@@ -149,6 +150,29 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
return ExpressionCodeResult(result, IRDataType.WORD, argumentwordTr.resultReg, -1)
}
private fun funcCallfar2(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
val bankTr = exprGen.translateExpression(call.args[0])
val addressTr = exprGen.translateExpression(call.args[1])
val argumentA = exprGen.translateExpression(call.args[2])
val argumentX = exprGen.translateExpression(call.args[3])
val argumentY = exprGen.translateExpression(call.args[4])
val argumentCarry = exprGen.translateExpression(call.args[5])
addToResult(result, bankTr, bankTr.resultReg, -1)
addToResult(result, addressTr, addressTr.resultReg, -1)
addToResult(result, argumentA, argumentA.resultReg, -1)
addToResult(result, argumentX, argumentX.resultReg, -1)
addToResult(result, argumentY, argumentY.resultReg, -1)
addToResult(result, argumentCarry, argumentCarry.resultReg, -1)
result += codeGen.makeSyscall(IMSyscall.CALLFAR2, listOf(IRDataType.BYTE to bankTr.resultReg, IRDataType.WORD to addressTr.resultReg,
IRDataType.BYTE to argumentA.resultReg,
IRDataType.BYTE to argumentX.resultReg,
IRDataType.BYTE to argumentY.resultReg,
IRDataType.BYTE to argumentCarry.resultReg), IRDataType.WORD to addressTr.resultReg)
return ExpressionCodeResult(result, IRDataType.WORD, addressTr.resultReg, -1)
}
private fun funcDivmod(call: PtBuiltinFunctionCall, type: IRDataType): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val number = call.args[0]
@@ -392,11 +392,35 @@ internal class ConstantIdentifierReplacer(
return noModifications
}
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
// convert a range expression that is assigned to an array, to an array literal instead.
val range = assignment.value as? RangeExpression
if(range!=null) {
val targetDatatype = assignment.target.inferType(program)
if(targetDatatype.isArray) {
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, targetDatatype.getOr(DataType.UNDEFINED),
ZeropageWish.DONTCARE, null, "dummy", emptyList(),
assignment.value, false, false, Position.DUMMY)
val replaceValue = createConstArrayInitializerValue(decl)
if(replaceValue!=null) {
return listOf(IAstModification.ReplaceNode(assignment.value, replaceValue, assignment))
}
}
}
return noModifications
}
private fun createConstArrayInitializerValue(decl: VarDecl): ArrayLiteral? {
if(decl.type==VarDeclType.MEMORY)
return null // memory mapped arrays can never have an initializer value other than the address where they're mapped.
val rangeSize=(decl.value as? RangeExpression)?.size()
if(rangeSize!=null && rangeSize>65535) {
errors.err("range size overflow", decl.value!!.position)
return null
}
// convert the initializer range expression from a range or int, to an actual array.
when(decl.datatype) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT -> {
@@ -224,8 +224,11 @@ class Inliner(private val program: Program, private val options: CompilationOpti
noModifications
}
else -> {
sub.hasBeenInlined=true
listOf(IAstModification.ReplaceNode(origNode, toInline.copy(), parent))
if(origNode !== toInline) {
sub.hasBeenInlined = true
listOf(IAstModification.ReplaceNode(origNode, toInline.copy(), parent))
} else
noModifications
}
}
}
@@ -255,7 +258,7 @@ class Inliner(private val program: Program, private val options: CompilationOpti
is Return -> {
// is an expression, so we have to have a Return here in the inlined sub
// note that we don't have to process any args, because we online inline parameterless subroutines.
if(toInline.value!=null) {
if(toInline.value!=null && functionCallExpr!==toInline.value) {
sub.hasBeenInlined=true
listOf(IAstModification.ReplaceNode(functionCallExpr, toInline.value!!.copy(), parent))
}
+44 -10
View File
@@ -23,16 +23,20 @@ sys {
const ubyte target = 8 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL
const ubyte sizeof_bool = 1
const ubyte sizeof_byte = 1
const ubyte sizeof_ubyte = 1
const ubyte sizeof_word = 2
const ubyte sizeof_uword = 2
const ubyte sizeof_float = 0 ; undefined, no float support
asmsub init_system() {
; Initializes the machine to a sane starting state.
; Called automatically by the loader program logic.
; TODO
%asm {{
sei
cld
clc
; TODO reset screen mode etc etc
clv
cli
rts
}}
@@ -40,7 +44,26 @@ sys {
asmsub init_system_phase2() {
%asm {{
rts ; no phase 2 steps on the Atari
cld
clc
clv
rts
}}
}
asmsub cleanup_at_exit() {
; executed when the main subroutine does rts
%asm {{
_exitcodeCarry = *+1
lda #0
lsr a
_exitcode = *+1
lda #0 ; exit code possibly modified in exit()
_exitcodeX = *+1
ldx #0
_exitcodeY = *+1
ldy #0
rts
}}
}
@@ -248,27 +271,38 @@ save_SCRATCH_ZPWORD2 .word 0
asmsub exit(ubyte returnvalue @A) {
; -- immediately exit the program with a return code in the A register
; TODO where to store A as exit code?
%asm {{
sta cleanup_at_exit._exitcode
ldx prog8_lib.orig_stackpointer
txs
rts ; return to original caller
jmp cleanup_at_exit
}}
}
asmsub exit2(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y) {
; -- immediately exit the program with result values in the A, X and Y registers.
; TODO where to store A,X,Y as exit code?
%asm {{
jmp exit
sta cleanup_at_exit._exitcode
stx cleanup_at_exit._exitcodeX
sty cleanup_at_exit._exitcodeY
ldx prog8_lib.orig_stackpointer
txs
jmp cleanup_at_exit
}}
}
asmsub exit3(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc) {
; -- immediately exit the program with result values in the A, X and Y registers, and the Carry flag in the status register.
; TODO where to store A,X,Y,Carry as exit code?
%asm {{
jmp exit
sta cleanup_at_exit._exitcode
lda #0
rol a
sta cleanup_at_exit._exitcodeCarry
stx cleanup_at_exit._exitcodeX
sty cleanup_at_exit._exitcodeY
ldx prog8_lib.orig_stackpointer
txs
jmp cleanup_at_exit
}}
}
+1 -1
View File
@@ -1,4 +1,4 @@
; experimental buffer data structures
; **experimental** buffer data structures, API subject to change!!
%option no_symbol_prefixing, ignore_unused
+12 -4
View File
@@ -351,6 +351,14 @@ sys {
const ubyte target = 128 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
const ubyte sizeof_bool = 1
const ubyte sizeof_byte = 1
const ubyte sizeof_ubyte = 1
const ubyte sizeof_word = 2
const ubyte sizeof_uword = 2
const ubyte sizeof_float = 5
asmsub init_system() {
; Initializes the machine to a sane starting state.
; Called automatically by the loader program logic.
@@ -360,7 +368,6 @@ asmsub init_system() {
; Uppercase charset is activated.
%asm {{
sei
cld
lda #0
sta $ff00 ; select default bank 15
jsr cbm.IOINIT
@@ -373,8 +380,6 @@ asmsub init_system() {
lda #0
sta c64.BGCOL0
jsr disable_runstop_and_charsetswitch
clc
clv
cli
rts
}}
@@ -382,7 +387,10 @@ asmsub init_system() {
asmsub init_system_phase2() {
%asm {{
rts ; no phase 2 steps on the C128
cld
clc
clv
rts
}}
}
+11 -4
View File
@@ -347,6 +347,13 @@ sys {
const ubyte target = 64 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
const ubyte sizeof_bool = 1
const ubyte sizeof_byte = 1
const ubyte sizeof_ubyte = 1
const ubyte sizeof_word = 2
const ubyte sizeof_uword = 2
const ubyte sizeof_float = 5
asmsub init_system() {
; Initializes the machine to a sane starting state.
@@ -357,7 +364,6 @@ asmsub init_system() {
; Uppercase charset is activated.
%asm {{
sei
cld
lda #%00101111
sta $00
lda #%00100111
@@ -372,8 +378,6 @@ asmsub init_system() {
lda #0
sta c64.BGCOL0
jsr disable_runstop_and_charsetswitch
clc
clv
cli
rts
}}
@@ -381,7 +385,10 @@ asmsub init_system() {
asmsub init_system_phase2() {
%asm {{
rts ; no phase 2 steps on the C64
cld
clc
clv
rts
}}
}
+409
View File
@@ -0,0 +1,409 @@
; **experimental** data compression/decompression routines, API subject to change!!
compression {
%option no_symbol_prefixing, ignore_unused
sub encode_rle_outfunc(uword data, uword size, uword output_function, bool is_last_block) {
; -- Compress the given data block using ByteRun1 aka PackBits RLE encoding.
; output_function = address of a routine that gets a byte arg in A,
; this is the next RLE byte to write to the compressed output buffer or file.
; is_last_block = usually true, but you can set it to false if you want to concatenate multiple
; compressed blocks (for instance if the source data is >64Kb)
; Worst case result storage size needed = (size + (size+126) / 127) + 1
; This routine is not optimized for speed but for readability and ease of use.
uword idx = 0
uword literals_start_idx = 0
ubyte literals_length = 0
asmsub call_output_function(ubyte arg @A) {
%asm {{
jmp (p8v_output_function)
}}
}
sub next_same_span() {
; returns length in cx16.r1L, and the byte value in cx16.r1H
cx16.r1H = data[idx]
cx16.r1L = 0
while data[idx]==cx16.r1H and cx16.r1L<128 and idx<size {
idx++
cx16.r1L++
}
}
sub output_literals() {
call_output_function(literals_length-1)
uword dataptr = data + literals_start_idx
ubyte i
for i in 0 to literals_length-1 {
call_output_function(@(dataptr))
dataptr++
}
literals_length = 0
}
while idx<size {
next_same_span() ; count in r1L, value in r1H
if cx16.r1L>1 {
; a replicate run
if literals_length>0
output_literals()
call_output_function((cx16.r1L^255)+2) ; 257-cx16.r1L
call_output_function(cx16.r1H)
}
else {
; add more to the literals run
if literals_length==128
output_literals()
if literals_length==0
literals_start_idx = idx-1
literals_length++
}
}
if literals_length>0
output_literals()
if is_last_block
call_output_function(128)
}
sub encode_rle(uword data, uword size, uword target, bool is_last_block) -> uword {
; -- Compress the given data block using ByteRun1 aka PackBits RLE encoding.
; Returns the size of the compressed RLE data. Worst case result storage size needed = (size + (size+126) / 127) + 1.
; is_last_block = usually true, but you can set it to false if you want to concatenate multiple
; compressed blocks (for instance if the source data is >64Kb)
; This routine is not optimized for speed but for readability and ease of use.
uword idx = 0
uword literals_start_idx = 0
ubyte literals_length = 0
uword orig_target = target
sub next_same_span() {
; returns length in cx16.r1L, and the byte value in cx16.r1H
cx16.r1H = data[idx]
cx16.r1L = 0
while data[idx]==cx16.r1H and cx16.r1L<128 and idx<size {
idx++
cx16.r1L++
}
}
sub output_literals() {
@(target) = literals_length-1
target++
uword dataptr = data + literals_start_idx
ubyte i
for i in 0 to literals_length-1 {
@(target) = @(dataptr)
target++
dataptr++
}
literals_length = 0
}
while idx<size {
next_same_span() ; count in r1L, value in r1H
if cx16.r1L>1 {
; a replicate run
if literals_length>0
output_literals()
@(target) = (cx16.r1L^255)+2 ; 257-cx16.r1L
target++
@(target) = cx16.r1H
target++
}
else {
; add more to the literals run
if literals_length==128
output_literals()
if literals_length==0
literals_start_idx = idx-1
literals_length++
}
}
if literals_length>0
output_literals()
if is_last_block {
@(target) = 128
target ++
}
return target-orig_target
}
asmsub decode_rle_srcfunc(uword source_function @AY, uword target @R0, uword maxsize @R1) clobbers(X) -> uword @AY {
; -- decodes "ByteRun1" (aka PackBits) RLE compressed data. Control byte value 128 ends the decoding.
; instead of a source buffer, you provide a callback function that must return the next byte to compress in A.
; Stops decompressing when the maxsize has been reached.
%asm {{
sta _cb_mod1+1
sty _cb_mod1+2
sta _cb_mod2+1
sty _cb_mod2+2
sta _cb_mod3+1
sty _cb_mod3+2
lda cx16.r0L
ldy cx16.r0H
sta P8ZP_SCRATCH_W2 ; target ptr
sta _orig_target
sty P8ZP_SCRATCH_W2+1
sty _orig_target+1
lda cx16.r0L
clc
adc cx16.r1L
sta cx16.r1L
lda cx16.r0H
adc cx16.r1H
sta cx16.r1H ; decompression limit
_loop
; while target (W2) < limit (r1)
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
cmp cx16.r1L
tya
sbc cx16.r1H
bcs _end
_cb_mod1 jsr $ffff ; modified
bpl _literals
cmp #128
beq _end
; replicate next byte -n+1 times
eor #255
clc
adc #2
sta P8ZP_SCRATCH_REG
_cb_mod2 jsr $ffff ; modified
ldx P8ZP_SCRATCH_REG
ldy #0
- sta (P8ZP_SCRATCH_W2),y
iny
dex
bne -
; add A to target
lda P8ZP_SCRATCH_REG
clc
adc P8ZP_SCRATCH_W2
sta P8ZP_SCRATCH_W2
lda #0
adc P8ZP_SCRATCH_W2+1
sta P8ZP_SCRATCH_W2+1
jmp _loop
_literals
; copy the next n+1 bytes
pha
sta P8ZP_SCRATCH_B1
ldy #0
sty P8ZP_SCRATCH_REG
_cb_mod3 jsr $ffff ; modified
ldy P8ZP_SCRATCH_REG
sta (P8ZP_SCRATCH_W2),y
inc P8ZP_SCRATCH_REG
dec P8ZP_SCRATCH_B1
bpl _cb_mod3
; add N+1 to target
pla
sec
adc P8ZP_SCRATCH_W2
sta P8ZP_SCRATCH_W2
lda #0
adc P8ZP_SCRATCH_W2+1
sta P8ZP_SCRATCH_W2+1
jmp _loop
_orig_target .word 0
_end
; return w2-orig_target, the size of the decompressed data
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
sec
sbc _orig_target
tax
tya
sbc _orig_target+1
tay
txa
rts
}}
}
asmsub decode_rle(uword compressed @AY, uword target @R0, uword maxsize @R1) clobbers(X) -> uword @AY {
; -- decodes "ByteRun1" (aka PackBits) RLE compressed data. Control byte value 128 ends the decoding.
; Stops decompressing when the maxsize has been reached.
%asm {{
sta P8ZP_SCRATCH_W1 ; compressed data ptr
sty P8ZP_SCRATCH_W1+1
lda cx16.r0L
ldy cx16.r0H
sta P8ZP_SCRATCH_W2 ; target ptr
sta _orig_target
sty P8ZP_SCRATCH_W2+1
sty _orig_target+1
lda cx16.r0L
clc
adc cx16.r1L
sta cx16.r1L
lda cx16.r0H
adc cx16.r1H
sta cx16.r1H ; decompression limit
_loop ; while target (W2) < limit (r1)
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
cmp cx16.r1L
tya
sbc cx16.r1H
bcs _end
ldy #0
lda (P8ZP_SCRATCH_W1),y
bpl _literals
cmp #128
beq _end
; replicate next byte -n+1 times
eor #255
clc
adc #2
pha
tax
iny
lda (P8ZP_SCRATCH_W1),y
ldy #0
- sta (P8ZP_SCRATCH_W2),y
iny
dex
bne -
; add A to target
pla
clc
adc P8ZP_SCRATCH_W2
sta P8ZP_SCRATCH_W2
lda #0
adc P8ZP_SCRATCH_W2+1
sta P8ZP_SCRATCH_W2+1
; increase source by 2
clc
lda P8ZP_SCRATCH_W1
adc #2
sta P8ZP_SCRATCH_W1
lda #0
adc P8ZP_SCRATCH_W1+1
sta P8ZP_SCRATCH_W1+1
jmp _loop
_literals
; copy the next n+1 bytes
pha
tax
inc P8ZP_SCRATCH_W1
bne +
inc P8ZP_SCRATCH_W1+1
+ ldy #0
- lda (P8ZP_SCRATCH_W1),y
sta (P8ZP_SCRATCH_W2),y
iny
dex
bpl -
; add N+1 to source
pla
tax
sec
adc P8ZP_SCRATCH_W1
sta P8ZP_SCRATCH_W1
lda #0
adc P8ZP_SCRATCH_W1+1
sta P8ZP_SCRATCH_W1+1
; add N+1 to target as well
txa
sec
adc P8ZP_SCRATCH_W2
sta P8ZP_SCRATCH_W2
lda #0
adc P8ZP_SCRATCH_W2+1
sta P8ZP_SCRATCH_W2+1
jmp _loop
_orig_target .word 0
_end
; return w2-orig_target, the size of the decompressed data
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
sec
sbc _orig_target
tax
tya
sbc _orig_target+1
tay
txa
rts
}}
}
/***
; prog8 source code for the asm routine above:
sub decode_rle_prog8(uword @zp compressed, uword @zp target, uword maxsize) -> uword {
cx16.r0 = target ; original target
cx16.r1 = target+maxsize ; decompression limit
while target<cx16.r1 {
cx16.r2L = @(compressed)
if_neg {
if cx16.r2L==128
break
; replicate the next byte -n+1 times
compressed++
cx16.r3L = @(compressed)
repeat 2+(cx16.r2L^255) {
@(target) = cx16.r3L
target++
}
compressed++
} else {
; copy the next n+1 bytes
compressed++
repeat cx16.r2L+1 {
@(target) = @(compressed)
compressed++
target++
}
}
}
return target-cx16.r0
}
sub decode_rle_callback_prog8(uword producer_callback, uword @zp target, uword maxsize) -> uword {
cx16.r0 = target ; original target
cx16.r1 = target+maxsize ; decompression limit
while target<cx16.r1 {
cx16.r2L = lsb(call(producer_callback))
if_neg {
if cx16.r2L==128
break
; replicate the next byte -n+1 times
cx16.r3L = lsb(call(producer_callback))
repeat 2+(cx16.r2L^255) {
@(target) = cx16.r3L
target++
}
} else {
; copy the next n+1 bytes
repeat cx16.r2L+1 {
@(target) = lsb(call(producer_callback))
target++
}
}
}
return target-cx16.r0
}
***/
}
+459
View File
@@ -0,0 +1,459 @@
%import syslib
; Stubs for the audio routines in rom bank 10
; They use JSRFAR to select the correct bank, so user code doesn't have to bother.
;
; The stubs here still use the romsub definitions of the routines from syslib, but those are
; just the jump addresses and are unaware of the kernal bank. Wrapping in JSRFAR fixes this.
audio {
const ubyte rom_bank = $0a
asmsub audio_init() clobbers(A,X,Y) -> bool @Pc { ; (re)initialize both vera PSG and YM audio chips
%asm{{
jsr cx16.JSRFAR
.word cx16.audio_init
.byte p8c_rom_bank
rts
}}
}
asmsub bas_fmfreq(ubyte channel @A, uword freq @XY, bool noretrigger @Pc) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_fmfreq
.byte p8c_rom_bank
rts
}}
}
asmsub bas_fmnote(ubyte channel @A, ubyte note @X, ubyte fracsemitone @Y, bool noretrigger @Pc) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_fmnote
.byte p8c_rom_bank
rts
}}
}
asmsub bas_fmplaystring(ubyte length @A, str string @XY) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_fmplaystring
.byte p8c_rom_bank
rts
}}
}
asmsub bas_fmvib(ubyte speed @A, ubyte depth @X) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_fmvib
.byte p8c_rom_bank
rts
}}
}
asmsub bas_playstringvoice(ubyte channel @A) clobbers(Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_playstringvoice
.byte p8c_rom_bank
rts
}}
}
asmsub bas_psgfreq(ubyte voice @A, uword freq @XY) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_psgfreq
.byte p8c_rom_bank
rts
}}
}
asmsub bas_psgnote(ubyte voice @A, ubyte note @X, ubyte fracsemitone @Y) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_psgnote
.byte p8c_rom_bank
rts
}}
}
asmsub bas_psgwav(ubyte voice @A, ubyte waveform @X) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_psgwav
.byte p8c_rom_bank
rts
}}
}
asmsub bas_psgplaystring(ubyte length @A, str string @XY) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_psgplaystring
.byte p8c_rom_bank
rts
}}
}
asmsub bas_fmchordstring(ubyte length @A, str string @XY) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_fmchordstring
.byte p8c_rom_bank
rts
}}
}
asmsub bas_psgchordstring(ubyte length @A, str string @XY) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.bas_psgchordstring
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_bas2fm(ubyte note @X) clobbers(A) -> ubyte @X, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_bas2fm
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_bas2midi(ubyte note @X) clobbers(A) -> ubyte @X, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_bas2midi
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_bas2psg(ubyte note @X, ubyte fracsemitone @Y) clobbers(A) -> uword @XY, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_bas2psg
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_fm2bas(ubyte note @X) clobbers(A) -> ubyte @X, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_fm2bas
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_fm2midi(ubyte note @X) clobbers(A) -> ubyte @X, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_fm2midi
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_fm2psg(ubyte note @X, ubyte fracsemitone @Y) clobbers(A) -> uword @XY, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_fm2psg
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_freq2bas(uword freqHz @XY) clobbers(A) -> ubyte @X, ubyte @Y, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_freq2bas
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_freq2fm(uword freqHz @XY) clobbers(A) -> ubyte @X, ubyte @Y, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_freq2fm
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_freq2midi(uword freqHz @XY) clobbers(A) -> ubyte @X, ubyte @Y, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_freq2midi
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_freq2psg(uword freqHz @XY) clobbers(A) -> uword @XY, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_freq2psg
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_midi2bas(ubyte note @X) clobbers(A) -> ubyte @X, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_midi2bas
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_midi2fm(ubyte note @X) clobbers(A) -> ubyte @X, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_midi2fm
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_midi2psg(ubyte note @X, ubyte fracsemitone @Y) clobbers(A) -> uword @XY, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_midi2psg
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_psg2bas(uword freq @XY) clobbers(A) -> ubyte @X, ubyte @Y, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_psg2bas
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_psg2fm(uword freq @XY) clobbers(A) -> ubyte @X, ubyte @Y, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_psg2fm
.byte p8c_rom_bank
rts
}}
}
asmsub notecon_psg2midi(uword freq @XY) clobbers(A) -> ubyte @X, ubyte @Y, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.notecon_psg2midi
.byte p8c_rom_bank
rts
}}
}
asmsub psg_init() clobbers(A,X,Y) { ; (re)init Vera PSG
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_init
.byte p8c_rom_bank
rts
}}
}
asmsub psg_playfreq(ubyte voice @A, uword freq @XY) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_playfreq
.byte p8c_rom_bank
rts
}}
}
asmsub psg_read(ubyte offset @X, bool cookedVol @Pc) clobbers(Y) -> ubyte @A{
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_read
.byte p8c_rom_bank
rts
}}
}
asmsub psg_setatten(ubyte voice @A, ubyte attenuation @X) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_setatten
.byte p8c_rom_bank
rts
}}
}
asmsub psg_setfreq(ubyte voice @A, uword freq @XY) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_setfreq
.byte p8c_rom_bank
rts
}}
}
asmsub psg_setpan(ubyte voice @A, ubyte panning @X) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_setpan
.byte p8c_rom_bank
rts
}}
}
asmsub psg_setvol(ubyte voice @A, ubyte volume @X) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_setvol
.byte p8c_rom_bank
rts
}}
}
asmsub psg_write(ubyte value @A, ubyte offset @X) clobbers(Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_write
.byte p8c_rom_bank
rts
}}
}
asmsub psg_write_fast(ubyte value @A, ubyte offset @X) clobbers(Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_write_fast
.byte p8c_rom_bank
rts
}}
}
asmsub psg_getatten(ubyte voice @A) clobbers(Y) -> ubyte @X{
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_getatten
.byte p8c_rom_bank
rts
}}
}
asmsub psg_getpan(ubyte voice @A) clobbers(Y) -> ubyte @X{
%asm{{
jsr cx16.JSRFAR
.word cx16.psg_getpan
.byte p8c_rom_bank
rts
}}
}
asmsub ym_init() clobbers(A,X,Y) -> bool @Pc { ; (re)init YM chip
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_init
.byte p8c_rom_bank
rts
}}
}
asmsub ym_loaddefpatches() clobbers(A,X,Y) -> bool @Pc { ; load default YM patches
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_loaddefpatches
.byte p8c_rom_bank
rts
}}
}
asmsub ym_loadpatch(ubyte channel @A, uword patchOrAddress @XY, bool what @Pc) clobbers(A,X,Y){
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_loadpatch
.byte p8c_rom_bank
rts
}}
}
asmsub ym_loadpatchlfn(ubyte channel @A, ubyte lfn @X) clobbers(X,Y) -> ubyte @A, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_loadpatchlfn
.byte p8c_rom_bank
rts
}}
}
asmsub ym_playdrum(ubyte channel @A, ubyte note @X) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_playdrum
.byte p8c_rom_bank
rts
}}
}
asmsub ym_playnote(ubyte channel @A, ubyte kc @X, ubyte kf @Y, bool notrigger @Pc) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_playnote
.byte p8c_rom_bank
rts
}}
}
asmsub ym_setatten(ubyte channel @A, ubyte attenuation @X) clobbers(Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_setatten
.byte p8c_rom_bank
rts
}}
}
asmsub ym_setdrum(ubyte channel @A, ubyte note @X) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_setdrum
.byte p8c_rom_bank
rts
}}
}
asmsub ym_setnote(ubyte channel @A, ubyte kc @X, ubyte kf @Y) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_setnote
.byte p8c_rom_bank
rts
}}
}
asmsub ym_setpan(ubyte channel @A, ubyte panning @X) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_setpan
.byte p8c_rom_bank
rts
}}
}
asmsub ym_read(ubyte register @X, bool cooked @Pc) clobbers(Y) -> ubyte @A, bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_read
.byte p8c_rom_bank
rts
}}
}
asmsub ym_release(ubyte channel @A) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_release
.byte p8c_rom_bank
rts
}}
}
asmsub ym_trigger(ubyte channel @A, bool noRelease @Pc) clobbers(A,X,Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_trigger
.byte p8c_rom_bank
rts
}}
}
asmsub ym_write(ubyte value @A, ubyte register @X) clobbers(Y) -> bool @Pc{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_write
.byte p8c_rom_bank
rts
}}
}
asmsub ym_getatten(ubyte channel @A) clobbers(Y) -> ubyte @X{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_getatten
.byte p8c_rom_bank
rts
}}
}
asmsub ym_getpan(ubyte channel @A) clobbers(Y) -> ubyte @X{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_getpan
.byte p8c_rom_bank
rts
}}
}
asmsub ym_get_chip_type() clobbers(X) -> ubyte @A{
%asm{{
jsr cx16.JSRFAR
.word cx16.ym_get_chip_type
.byte p8c_rom_bank
rts
}}
}
}
+5
View File
@@ -757,6 +757,11 @@ internal_vload:
}}
}
; note: There is no vsave_raw() routine because the Kernal doesn't have a VSAVE routine.
; You'll have to write your own loop that reads vram data and use
; cbm.CHROUT or cx16.MCIOUT to write it to an open output file.
sub chdir(str path) {
; -- change current directory.
list_filename[0] = 'c'
+75 -42
View File
@@ -2,6 +2,8 @@
; bitmap image needs to start at VRAM addres $00000.
; This is compatible with the CX16's screen mode 128. (void cx16.set_screen_mode(128))
%import verafx
gfx_lores {
@@ -19,15 +21,74 @@ gfx_lores {
}
sub clear_screen(ubyte color) {
if verafx.available() {
; use verafx cache writes to quicly clear the screen
const ubyte vbank = 0
const uword vaddr = 0
cx16.VERA_CTRL = 0
cx16.VERA_ADDR_H = vbank | %00110000 ; 4-byte increment
cx16.VERA_ADDR_M = msb(vaddr)
cx16.VERA_ADDR_L = lsb(vaddr)
cx16.VERA_CTRL = 6<<1 ; dcsel = 6, fill the 32 bits cache
cx16.VERA_FX_CACHE_L = color
cx16.VERA_FX_CACHE_M = color
cx16.VERA_FX_CACHE_H = color
cx16.VERA_FX_CACHE_U = color
cx16.VERA_CTRL = 2<<1 ; dcsel = 2
cx16.VERA_FX_MULT = 0
cx16.VERA_FX_CTRL = %01000000 ; cache write enable
repeat 320/4/4 {
%asm {{
ldy #240
- stz cx16.VERA_DATA0
stz cx16.VERA_DATA0
stz cx16.VERA_DATA0
stz cx16.VERA_DATA0
dey
bne -
}}
}
cx16.VERA_FX_CTRL = 0 ; cache write disable
cx16.VERA_CTRL = 0
return
}
; fallback to cpu clear
cx16.VERA_CTRL=0
cx16.VERA_ADDR=0
cx16.VERA_ADDR_H = 1<<4 ; 1 pixel auto increment
repeat 240
cs_innerloop320(color)
repeat 240 {
%asm {{
lda p8v_color
ldy #320/8
- .rept 8
sta cx16.VERA_DATA0
.endrept
dey
bne -
}}
}
cx16.VERA_ADDR=0
cx16.VERA_ADDR_H = 0
}
asmsub plot(uword x @AX, ubyte y @Y, ubyte color @R0) {
; x in r0, y in r1, color.
%asm {{
clc
adc times320_lo,y
sta cx16.VERA_ADDR_L
txa
adc times320_mid,y
sta cx16.VERA_ADDR_M
lda #0
adc times320_hi,y
sta cx16.VERA_ADDR_H
lda cx16.r0L
sta cx16.VERA_DATA0
rts
}}
}
sub line(uword x1, ubyte y1, uword x2, ubyte y2, ubyte color) {
; Bresenham algorithm.
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
@@ -133,7 +194,7 @@ gfx_lores {
}
asmsub plot() {
; x in r0, y in r1, color.
; internal plot routine for the line algorithm: x in r0, y in r1, color in variable.
%asm {{
ldy cx16.r1L
clc
@@ -151,23 +212,12 @@ gfx_lores {
rts
}}
}
%asm {{
; multiplication by 320 lookup table
times320 := 320*range(240)
times320_lo .byte <times320
times320_mid .byte >times320
times320_hi .byte `times320
}}
}
sub horizontal_line(uword xx, ubyte yy, uword length, ubyte color) {
if length==0
return
vera_setaddr(xx, yy)
plot(xx, yy, color) ; set starting position by reusing plot routine
; set vera auto-increment to 1 pixel
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | (1<<4)
@@ -191,45 +241,28 @@ times320_hi .byte `times320
}
sub vertical_line(uword xx, ubyte yy, ubyte lheight, ubyte color) {
vera_setaddr(xx,yy)
if lheight==0
return
plot(xx, yy, color) ; set starting position by reusing plot routine
; set vera auto-increment to 320 pixel increment (=next line)
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | (14<<4)
%asm {{
ldy p8v_lheight
beq +
lda p8v_color
- sta cx16.VERA_DATA0
dey
bne -
+
}}
}
asmsub cs_innerloop320(ubyte color @A) clobbers(Y) {
; using verafx 32 bits writes here would make this faster but it's safer to
; use verafx only explicitly when you know what you're doing.
%asm {{
ldy #40
- sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
dey
bne -
rts
}}
}
%asm {{
; multiplication by 320 lookup table
times320 := 320*range(240)
inline asmsub vera_setaddr(uword xx @R0, ubyte yy @R1) {
; set the correct vera start address (no auto increment yet!)
%asm {{
jsr p8s_line.p8s_plot
}}
}
times320_lo .byte <times320
times320_mid .byte >times320
times320_hi .byte `times320
}}
}
+1 -2
View File
@@ -1,5 +1,4 @@
%import syslib
%import textio
; Bitmap pixel graphics module for the CommanderX16
; Wraps the graphics functions that are in ROM.
@@ -35,7 +34,7 @@ graphics {
sub disable_bitmap_mode() {
; enables text mode, erase the text screen, color white
void cx16.screen_mode(0, false)
txt.clear_screen()
cbm.CHROUT(147)
}
+66 -19
View File
@@ -819,31 +819,14 @@ invert:
while cx16.r12L!=0 {
pop_stack()
xx = x1
while xx >= 0 {
if pget(xx as uword, yy as uword) as ubyte != cx16.r11L
break
xx--
}
if x1!=xx
horizontal_line(xx as uword+1, yy as uword, x1-xx as uword, cx16.r10L as bool)
else
goto skip
if fill_scanline_left() goto skip
left = xx + 1
if left < x1
push_stack(left, x1 - 1, yy, -dy)
xx = x1 + 1
do {
cx16.r9s = xx
while xx <= width-1 {
if pget(xx as uword, yy as uword) as ubyte != cx16.r11L
break
xx++
}
if cx16.r9s!=xx
horizontal_line(cx16.r9, yy as uword, xx-cx16.r9s as uword, cx16.r10L as bool)
fill_scanline_right()
push_stack(left, xx - 1, yy, dy)
if xx > x2 + 1
push_stack(x2 + 1, xx - 1, yy, -dy)
@@ -857,6 +840,70 @@ skip:
left = xx
} until xx>x2
}
sub fill_scanline_left() -> bool {
; TODO maybe this could use vera auto decrement, but that would require some clever masking calculations
cx16.r9s = xx
while xx >= 0 {
if pgetset()
break
xx--
}
return xx==cx16.r9s
}
sub fill_scanline_right() {
; TODO maybe this could use vera auto increment, but that would require some clever masking calculations
cx16.r9s = xx
while xx <= width-1 {
if pgetset()
break
xx++
}
}
sub pgetset() -> bool {
; test and optionally set a pixel
word @zp xpos = xx
%asm {{
lda p8v_xpos
and #7
pha ; xbits
}}
xpos /= 8
if width==320
xpos += yy*(320/8) as uword
else
xpos += yy*(640/8) as uword
%asm {{
stz cx16.VERA_CTRL
stz cx16.VERA_ADDR_H
lda p8v_xpos+1
sta cx16.VERA_ADDR_M
lda p8v_xpos
sta cx16.VERA_ADDR_L
ply ; xbits
lda p8s_plot.p8v_maskbits,y
and cx16.VERA_DATA0
beq +
lda #1
+
; cx16.r11L = seed color to check against
eor cx16.r11L
beq +
rts
+ ; cx16.r10L = new color to set
lda p8s_plot.p8v_maskbits,y
ldx cx16.r10L
beq +
tsb cx16.VERA_DATA0
bra ++
+ trb cx16.VERA_DATA0
+ lda #0
rts
}}
}
}
sub position(uword @zp xx, uword yy) {
+84
View File
@@ -106,6 +106,90 @@ palette {
}
}
sub fade_step_multi(ubyte startindex, ubyte endindex, uword target_rgb) -> bool {
; Perform one color fade step for multiple consecutive palette entries.
; startindex = palette index of first color to fade
; endindex = palette index of last color to fade
; target_rgb = $RGB color value to fade towards
; Returns true if one or more colors were changed, false if no fade steps were done anymore.
; So you usually keep calling this until it returns false.
bool changed = false
while startindex <= endindex {
if fade_step(startindex, target_rgb)
changed=true
startindex++
if_z
break
}
return changed
}
sub fade_step_colors(ubyte startindex, ubyte endindex, uword target_colors) -> bool {
; Perform one color fade step for multiple consecutive palette entries, to different target colors.
; startindex = palette index of first color to fade
; endindex = palette index of last color to fade
; target_colors = address of uword $RGB array of colors to fade towards
; Returns true if one or more colors were changed, false if no fade steps were done anymore.
; So you usually keep calling this until it returns false.
bool changed = false
ubyte target_index = 0
while startindex <= endindex {
if fade_step(startindex, peekw(target_colors+target_index))
changed=true
target_index += 2
startindex++
if_z
break
}
return changed
}
sub fade_step(ubyte index, uword target_rgb) -> bool {
; Perform one color fade step for a single palette entry.
; index = palette index of the color to fade
; target_rgb = $RGB color value to fade towards
; Returns true if the color was changed, false if no fade step was done anymore.
; So you usually keep calling this until it returns false.
uword color = palette.get_color(index)
cx16.r0L = msb(color) ; r
cx16.r1L = lsb(color) >> 4 ; g
cx16.r2L = lsb(color) & 15 ; b
cx16.r0H = msb(target_rgb) & 15 ; r2
cx16.r1H = lsb(target_rgb) >> 4 ; g2
cx16.r2H = lsb(target_rgb) & 15 ; b2
ubyte changed
; use cmp() + status bits branches, to avoid multiple compares that could be done just once
cmp(cx16.r0L, cx16.r0H)
if_ne {
if_cc
cx16.r0L++
else
cx16.r0L--
changed++
}
cmp(cx16.r1L, cx16.r1H)
if_ne {
if_cc
cx16.r1L++
else
cx16.r1L--
changed++
}
cmp(cx16.r2L, cx16.r2H)
if_ne {
if_cc
cx16.r2L++
else
cx16.r2L--
changed++
}
palette.set_color(index, mkword(cx16.r0L, cx16.r1L<<4 | cx16.r2L))
return changed!=0
}
sub set_c64pepto() {
; set first 16 colors to the "Pepto" PAL commodore-64 palette http://www.pepto.de/projects/colorvic/
uword[] colors = [
+14 -6
View File
@@ -483,7 +483,7 @@ romsub $C006 = x16edit_loadfile_options(ubyte firstbank @X, ubyte lastbank @Y, s
uword filenameLengthAndOptions @R1, uword tabstopAndWordwrap @R2,
uword disknumberAndColors @R3, uword headerAndStatusColors @R4) clobbers(A,X,Y)
; Audio (rom bank 10 - you have to activate this bank manually first! Or use callfar/JSRFAR.)
; Audio (rom bank 10 - you have to activate this bank manually first! Or use the stubs in the audio module. Or use callfar/JSRFAR manually.)
romsub $C09F = audio_init() clobbers(A,X,Y) -> bool @Pc ; (re)initialize both vera PSG and YM audio chips
romsub $C000 = bas_fmfreq(ubyte channel @A, uword freq @XY, bool noretrigger @Pc) clobbers(A,X,Y) -> bool @Pc
romsub $C003 = bas_fmnote(ubyte channel @A, ubyte note @X, ubyte fracsemitone @Y, bool noretrigger @Pc) clobbers(A,X,Y) -> bool @Pc
@@ -1238,11 +1238,10 @@ sub search_x16edit() -> ubyte {
str @shared signature = petscii:"x16edit"
for cx16.r1L in 31 downto 0 {
cx16.rombank(cx16.r1L)
cx16.r2 = $fff0
%asm {{
ldy #0
- lda signature,y
cmp (cx16.r2),y
cmp $fff0,y
bne +
iny
cpy #7
@@ -1361,6 +1360,13 @@ sys {
const ubyte target = 16 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
const ubyte sizeof_bool = 1
const ubyte sizeof_byte = 1
const ubyte sizeof_ubyte = 1
const ubyte sizeof_word = 2
const ubyte sizeof_uword = 2
const ubyte sizeof_float = 5
asmsub init_system() {
; Initializes the machine to a sane starting state.
; Called automatically by the loader program logic.
@@ -1370,7 +1376,6 @@ asmsub init_system() {
tax
tay
jsr cx16.mouse_config ; disable mouse
cld
lda cx16.VERA_DC_VIDEO
and #%00000111 ; retain chroma + output mode
sta P8ZP_SCRATCH_REG
@@ -1398,10 +1403,9 @@ asmsub init_system() {
lda #PROG8_VARSHIGH_RAMBANK
sta $00 ; select ram bank
lda #0
sta $01 ; set ROM bank to kernal bank to speed up kernal calls
tax
tay
clc
clv
cli
rts
}}
@@ -1416,7 +1420,11 @@ asmsub init_system_phase2() {
sta restore_irq._orig_irqvec+1
lda #PROG8_VARSHIGH_RAMBANK
sta $00 ; select ram bank
stz $01 ; set ROM bank to kernal bank to speed up kernal calls
cli
cld
clc
clv
rts
}}
}
+28 -11
View File
@@ -1,4 +1,8 @@
; Somewhat experimental Vera FX support.
; Partial Vera FX support:
; - fast 32 bit cached writes (clear, copy)
; - transparent write setting
; - hardware 16 bits multiplications
;
; Docs:
; https://github.com/X16Community/x16-docs/blob/fb63156cca2d6de98be0577aacbe4ddef458f896/X16%20Reference%20-%2010%20-%20VERA%20FX%20Reference.md
; https://docs.google.com/document/d/1q34uWOiM3Be2pnaHRVgSdHySI-qsiQWPTo_gfE54PTg
@@ -8,17 +12,18 @@ verafx {
sub available() -> bool {
; returns true if Vera FX is available (Vera V0.3.1 or later), false if not.
cx16.r1L = 0
cx16.r0L = cx16.VERA_CTRL
cx16.r0H = 0
cx16.VERA_CTRL = $7e
if cx16.VERA_DC_VER0 == $56 {
; Vera version number is valid.
; Vera fx is available on Vera version 0.3.1 and later,
; so no need to even check VERA_DC_VER1, which contains 0 (or higher)
cx16.r1L = mkword(cx16.VERA_DC_VER2, cx16.VERA_DC_VER3) >= $0301 as ubyte
; Vera version number is valid. Vera fx is available on Vera version 0.3.1 and later.
if cx16.VERA_DC_VER1>0
cx16.r0H = 1
else
cx16.r0H = mkword(cx16.VERA_DC_VER2, cx16.VERA_DC_VER3) >= $0301 as ubyte
}
cx16.VERA_CTRL = cx16.r0L
return cx16.r1L as bool
return cx16.r0H as bool
}
sub clear(ubyte vbank, uword vaddr, ubyte data, uword num_longwords) {
@@ -109,17 +114,28 @@ verafx {
cx16.VERA_CTRL = 0
}
; unsigned multiplication just passes the values as signed to muls
; if you do this yourself in your call to muls, it will save a few instructions.
inline asmsub mult(uword value1 @R0, uword value2 @R1) clobbers(X) -> uword @AY, uword @R0 {
; Returns the 32 bits unsigned result in AY and R0 (lower word, upper word).
asmsub mult16(uword value1 @R0, uword value2 @R1) clobbers(X) -> uword @AY {
; Returns the 16 bits unsigned result of R0*R1 in AY.
; Note: only the lower 16 bits! (the upper 16 bits are not valid for unsigned word multiplications, only for signed)
; Verafx doesn't support unsigned values like this for full 32 bit result.
%asm {{
lda cx16.r0
sta P8ZP_SCRATCH_W1
lda cx16.r0+1
sta P8ZP_SCRATCH_W1+1
jsr verafx.muls
ldx P8ZP_SCRATCH_W1
stx cx16.r0
ldx P8ZP_SCRATCH_W1+1
stx cx16.r0+1
rts
}}
}
asmsub muls(word value1 @R0, word value2 @R1) clobbers(X) -> word @AY, word @R0 {
; Returns the 32 bits signed result in AY and R0 (lower word, upper word).
; Vera Fx multiplication support only works on signed values!
%asm {{
lda #(2 << 1)
sta cx16.VERA_CTRL ; $9F25
@@ -160,6 +176,7 @@ verafx {
ldx cx16.VERA_DATA0
stx cx16.r0s+1
stz cx16.VERA_FX_CTRL ; Cache write disable
stz cx16.VERA_FX_MULT ; $9F2C reset multiply bit
stz cx16.VERA_CTRL ; reset DCSEL
rts
}}
+6 -5
View File
@@ -55,13 +55,14 @@ _multiplier = P8ZP_SCRATCH_REG
multiply_words .proc
; -- multiply two 16-bit words into a 32-bit result (signed and unsigned)
; -- multiply two 16-bit words into a 32-bit result (UNSIGNED)
; input: A/Y = first 16-bit number, multiply_words.multiplier = second 16-bit number
; output: multiply_words.result, 4-bytes/32-bits product, LSB order (low-to-high) low 16 bits also in AY.
; you can retrieve the upper 16 bits via math.mul16_last_upper()
; NOTE: the result (which includes the multiplier parameter on entry) is a 4-byte array.
; this routine could be faster if we could stick that into zeropage,
; but there currently is no way to use 4 consecutive bytes in ZP (without disabling irq and saving/restoring them)...
; NOTE FOR NEGATIVE VALUES:
; The routine also works for NEGATIVE (signed) word values, but ONLY the lower 16 bits of the result are correct then!
; Prog8 only uses those so that's not an issue, but math.mul16_last_upper() no longer gives the correct result here.
; mult62.a
; from: https://github.com/TobyLobster/multiply_test/blob/main/tests/mult62.a
@@ -179,7 +180,7 @@ _inner_loop2
ldy result+1
rts
result .byte 0,0,0,0
result .byte 0,0,0,0 ; routine could be faster if this were in Zeropage...
.pend
+3
View File
@@ -168,6 +168,9 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
; for instance, simply printing a number may already result in new multiplication calls being performed
; - not all multiplications in the source code result in an actual multiplication call:
; some simpler multiplications will be optimized away into faster routines. These will not set the upper 16 bits at all!
; - THE RESULT IS ONLY VALID IF THE MULTIPLICATION WAS DONE WITH UWORD ARGUMENTS (or two positive WORD arguments)
; as soon as a negative word value (or 2) was used in the multiplication, these upper 16 bits are not valid!!
; Suggestion (if you are on the Commander X16): use verafx.muls() to get a hardware accelerated 32 bit signed multplication.
%asm {{
lda multiply_words.result+2
ldy multiply_words.result+3
+12 -4
View File
@@ -98,19 +98,24 @@ sys {
const ubyte target = 32 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 32=PET
const ubyte sizeof_bool = 1
const ubyte sizeof_byte = 1
const ubyte sizeof_ubyte = 1
const ubyte sizeof_word = 2
const ubyte sizeof_uword = 2
const ubyte sizeof_float = 0 ; undefined, no floats supported
asmsub init_system() {
; Initializes the machine to a sane starting state.
; Called automatically by the loader program logic.
; Uppercase charset is activated.
%asm {{
sei
cld
lda #142
jsr cbm.CHROUT ; uppercase
lda #147
jsr cbm.CHROUT ; clear screen
clc
clv
cli
rts
}}
@@ -118,7 +123,10 @@ asmsub init_system() {
asmsub init_system_phase2() {
%asm {{
rts ; no phase 2 steps on the PET
cld
clc
clv
rts
}}
}
+18
View File
@@ -5,6 +5,24 @@
orig_stackpointer .byte 0 ; stores the Stack pointer register at program start
program_startup_clear_bss .proc
; this is always ran first thing from the start routine to clear out the BSS area
.if prog8_bss_section_size>0
; reset all variables in BSS section to zero
lda #<prog8_bss_section_start
ldy #>prog8_bss_section_start
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldx #<prog8_bss_section_size
ldy #>prog8_bss_section_size
lda #0
jsr prog8_lib.memset
.endif
rts
.pend
read_byte_from_address_in_AY_into_A .proc
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
@@ -0,0 +1,99 @@
compression {
sub decode_rle(uword @zp compressed, uword @zp target, uword maxsize) -> uword {
cx16.r0 = target ; original target
cx16.r1 = target+maxsize ; decompression limit
while target<cx16.r1 {
cx16.r2L = @(compressed)
if_neg {
if cx16.r2L==128
break
; replicate the next byte -n+1 times
compressed++
cx16.r3L = @(compressed)
repeat 2+(cx16.r2L^255) {
@(target) = cx16.r3L
target++
}
compressed++
} else {
; copy the next n+1 bytes
compressed++
repeat cx16.r2L+1 {
@(target) = @(compressed)
compressed++
target++
}
}
}
return target-cx16.r0
}
sub encode_rle(uword data, uword size, uword target, bool is_last_block) -> uword {
; -- Compress the given data block using ByteRun1 aka PackBits RLE encoding.
; Returns the size of the compressed RLE data. Worst case result storage size needed = (size + (size+126) / 127) + 1.
; is_last_block = usually true, but you can set it to false if you want to concatenate multiple
; compressed blocks (for instance if the source data is >64Kb)
; This routine is not optimized for speed but for readability and ease of use.
uword idx = 0
uword literals_start_idx = 0
ubyte literals_length = 0
uword orig_target = target
sub next_same_span() {
; returns length in cx16.r1L, and the byte value in cx16.r1H
cx16.r1H = data[idx]
cx16.r1L = 0
while data[idx]==cx16.r1H and cx16.r1L<128 and idx<size {
idx++
cx16.r1L++
}
}
sub output_literals() {
@(target) = literals_length-1
target++
uword dataptr = data + literals_start_idx
ubyte i
for i in 0 to literals_length-1 {
@(target) = @(dataptr)
target++
dataptr++
}
literals_length = 0
}
while idx<size {
next_same_span() ; count in r1L, value in r1H
if cx16.r1L>1 {
; a replicate run
if literals_length>0
output_literals()
@(target) = (cx16.r1L^255)+2 ; 257-cx16.r1L
target++
@(target) = cx16.r1H
target++
}
else {
; add more to the literals run
if literals_length==128
output_literals()
if literals_length==0
literals_start_idx = idx-1
literals_length++
}
}
if literals_length>0
output_literals()
if is_last_block {
@(target) = 128
target ++
}
return target-orig_target
}
}
+3 -1
View File
@@ -199,7 +199,7 @@ math {
%ir {{
loadm.w r65534,math.rndseed.seed1
loadm.w r65535,math.rndseed.seed2
syscall 19 (r65534.w, r65535.w)
syscall 18 (r65534.w, r65535.w)
return
}}
}
@@ -293,6 +293,8 @@ math {
; for instance, simply printing a number may already result in new multiplication calls being performed
; - not all multiplications in the source code result in an actual multiplication call:
; some simpler multiplications will be optimized away into faster routines. These will not set the upper 16 bits at all!
; - THE RESULT IS ONLY VALID IF THE MULTIPLICATION WAS DONE WITH UWORD ARGUMENTS (or two positive WORD arguments)
; as soon as a negative word value (or 2) was used in the multiplication, these upper 16 bits are not valid!!
%ir {{
syscall 33 (): r0.w
returnr.w r0
+8
View File
@@ -7,6 +7,14 @@ sys {
const ubyte target = 255 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL, 255 = virtual
const ubyte sizeof_bool = 1
const ubyte sizeof_byte = 1
const ubyte sizeof_ubyte = 1
const ubyte sizeof_word = 2
const ubyte sizeof_uword = 2
const ubyte sizeof_float = 8
sub reset_system() {
; Soft-reset the system back to initial power-on Basic prompt.
%ir {{
+11 -6
View File
@@ -107,14 +107,14 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
)
}
determineProgramLoadAddress(program, compilationOptions, args.errors)
args.errors.report()
postprocessAst(program, args.errors, compilationOptions)
args.errors.report()
// println("*********** COMPILER AST BEFORE ASSEMBLYGEN *************")
// printProgram(program)
determineProgramLoadAddress(program, compilationOptions, args.errors)
args.errors.report()
if (args.writeAssembly) {
// re-initialize memory areas with final compilationOptions
@@ -248,7 +248,7 @@ internal fun determineProgramLoadAddress(program: Program, options: CompilationO
}
if(loadAddress==null) {
errors.err("load address must be specified with these output options", program.toplevelModule.position)
errors.err("load address must be specified with the specifid output/launcher options", program.toplevelModule.position)
return
}
@@ -434,7 +434,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
}
removeUnusedCode(program, errors,compilerOptions)
while (true) {
for(num_cycles in 0..10000) {
// keep optimizing expressions and statements until no more steps remain
val optsDone1 = program.simplifyExpressions(errors)
val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions)
@@ -444,8 +444,13 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
errors.report()
break
}
if (optsDone1 + optsDone2 + optsDone3 == 0)
val numOpts = optsDone1 + optsDone2 + optsDone3
if (numOpts == 0)
break
if(num_cycles==10000) {
throw InternalCompilerException("optimizeAst() is looping endlessly, numOpts = $numOpts")
}
}
removeUnusedCode(program, errors, compilerOptions)
if(errors.noErrors()) {
@@ -16,7 +16,7 @@ import kotlin.io.path.Path
import kotlin.math.floor
/**
* Semantic analysis.
* Semantic analysis and error reporting.
*/
internal class AstChecker(private val program: Program,
private val errors: IErrorReporter,
@@ -139,8 +139,7 @@ internal class AstChecker(private val program: Program,
// you can return a string or array when an uword (pointer) is returned
} else if(valueDt istype DataType.UWORD && expectedReturnValues[0]==DataType.STR) {
// you can return a uword pointer when the return type is a string
}
else {
} else {
errors.err("type $valueDt of return value doesn't match subroutine's return type ${expectedReturnValues[0]}",returnStmt.value!!.position)
}
}
@@ -222,8 +221,8 @@ internal class AstChecker(private val program: Program,
}
DataType.WORD -> {
if(iterableDt!= DataType.BYTE && iterableDt!= DataType.WORD &&
iterableDt != DataType.ARRAY_B && iterableDt!= DataType.ARRAY_W &&
iterableDt != DataType.ARRAY_W_SPLIT)
iterableDt != DataType.ARRAY_B && iterableDt != DataType.ARRAY_UB &&
iterableDt != DataType.ARRAY_W && iterableDt != DataType.ARRAY_W_SPLIT)
errors.err("word loop variable can only loop over bytes or words", forLoop.position)
}
DataType.FLOAT -> {
@@ -242,7 +241,7 @@ internal class AstChecker(private val program: Program,
val to = range.to as? NumericLiteral
if(from != null)
checkValueTypeAndRange(loopvar.datatype, from)
else if(range.from.inferType(program) isnot loopvar.datatype)
else if(range.from.inferType(program).isNotAssignableTo(loopvar.datatype))
errors.err("range start value is incompatible with loop variable type", range.position)
if(to != null)
checkValueTypeAndRange(loopvar.datatype, to)
@@ -280,8 +279,13 @@ internal class AstChecker(private val program: Program,
errors.err("identifiers cannot start with an underscore", block.position)
val addr = block.address
if(addr!=null && addr>65535u) {
errors.err("block memory address must be valid integer 0..\$ffff", block.position)
if (addr!=null) {
if (addr > 65535u)
errors.err("block address must be valid integer 0..\$ffff", block.position)
if(compilerOptions.loadAddress!=0u) {
if (addr < compilerOptions.loadAddress + 20u)
errors.err("block address must be at least program load address + 20 (to allow for startup logic)", block.position)
}
}
for (statement in block.statements) {
@@ -322,7 +326,7 @@ internal class AstChecker(private val program: Program,
checkLongType(numLiteral)
}
private fun hasReturnOrJumpOrRts(scope: IStatementContainer): Boolean {
private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean {
class Searcher: IAstVisitor
{
var count=0
@@ -331,7 +335,14 @@ internal class AstChecker(private val program: Program,
count++
}
override fun visit(jump: Jump) {
count++
val jumpTarget = jump.identifier?.targetStatement(program)
if(jumpTarget!=null) {
val sub = jump.definingSubroutine
val targetSub = if(jumpTarget is Subroutine) jumpTarget else jumpTarget.definingSubroutine
if(sub !== targetSub)
count++
}
else count++
}
override fun visit(inlineAssembly: InlineAssembly) {
@@ -374,11 +385,11 @@ internal class AstChecker(private val program: Program,
// subroutine must contain at least one 'return' or 'goto'
// (or if it has an asm block, that must contain a 'rts' or 'jmp' or 'bra')
if(!hasReturnOrJumpOrRts(subroutine)) {
if(!hasReturnOrExternalJumpOrRts(subroutine)) {
if (subroutine.returntypes.isNotEmpty()) {
// for asm subroutines with an address, no statement check is possible.
if (subroutine.asmAddress == null && !subroutine.inline)
err("non-inline subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or the assembler equivalent in case of %asm)")
err("non-inline subroutine has result value(s) and thus must have at least one 'return' or external 'goto' in it (or the assembler equivalent in case of %asm)")
}
}
@@ -538,10 +549,8 @@ internal class AstChecker(private val program: Program,
fun checkType(target: AssignTarget, value: Expression, augmentable: Boolean) {
val targetDt = target.inferType(program)
val valueDt = value.inferType(program)
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) {
if(targetDt.isIterable)
errors.err("cannot assign value to string or array", value.position)
else if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) {
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt) && !targetDt.isIterable) {
if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) {
if(targetDt.isUnknown) {
if(target.identifier?.targetStatement(program)!=null)
errors.err("target datatype is unknown", target.position)
@@ -578,14 +587,22 @@ internal class AstChecker(private val program: Program,
checkMultiAssignment(assignment, fcall, fcallTarget)
} else if(fcallTarget!=null) {
if(fcallTarget.returntypes.size!=1) {
errors.err("number of assignment targets doesn't match number of return values from the subroutine", fcall.position)
return
return numberOfReturnValuesError(1, fcallTarget.returntypes, fcall.position)
}
}
super.visit(assignment)
}
private fun numberOfReturnValuesError(actual: Int, expectedTypes: List<DataType>, position: Position) {
if(actual<expectedTypes.size) {
val missing = expectedTypes.drop(actual).joinToString(", ")
errors.err("some return values are not assigned: expected ${expectedTypes.size} got $actual, missing assignments for: $missing", position)
}
else
errors.err("too many return values are assigned: expected ${expectedTypes.size} got $actual", position)
}
private fun checkMultiAssignment(assignment: Assignment, fcall: IFunctionCall?, fcallTarget: Subroutine?) {
// multi-assign: check the number of assign targets vs. the number of return values of the subroutine
// also check the types of the variables vs the types of each return value
@@ -595,8 +612,7 @@ internal class AstChecker(private val program: Program,
}
val targets = assignment.target.multi!!
if(fcallTarget.returntypes.size!=targets.size) {
errors.err("number of assignment targets doesn't match number of return values from the subroutine", fcall.position)
return
return numberOfReturnValuesError(targets.size, fcallTarget.returntypes, fcall.position)
}
fcallTarget.returntypes.zip(targets).withIndex().forEach { (index, p) ->
val (returnType, target) = p
@@ -649,7 +665,7 @@ internal class AstChecker(private val program: Program,
if (assignment.value !is BinaryExpression && assignment.value !is PrefixExpression && assignment.value !is ContainmentCheck)
errors.err("invalid assignment value, maybe forgot '&' (address-of)", assignment.value.position)
} else {
checkAssignmentCompatible(targetDatatype.getOr(DataType.UNDEFINED),
checkAssignmentCompatible(assignTarget, targetDatatype.getOr(DataType.UNDEFINED),
sourceDatatype.getOr(DataType.UNDEFINED), assignment.value)
}
}
@@ -680,6 +696,7 @@ internal class AstChecker(private val program: Program,
}
fun err(msg: String) = errors.err(msg, decl.position)
fun valueerr(msg: String) = errors.err(msg, decl.value?.position ?: decl.position)
// the initializer value can't refer to the variable itself (recursive definition)
if(decl.value?.referencesIdentifier(listOf(decl.name)) == true || decl.arraysize?.indexExpr?.referencesIdentifier(listOf(decl.name)) == true)
@@ -700,11 +717,11 @@ internal class AstChecker(private val program: Program,
if(decl.type== VarDeclType.MEMORY)
err("memory mapped array must have a size specification")
if(decl.value==null) {
err("array variable is missing a size specification or an initialization value")
valueerr("array variable is missing a size specification or an initialization value")
return
}
if(decl.value is NumericLiteral) {
err("unsized array declaration cannot use a single literal initialization value")
valueerr("unsized array declaration cannot use a single literal initialization value")
return
}
if(decl.value is RangeExpression)
@@ -730,7 +747,7 @@ internal class AstChecker(private val program: Program,
}
else -> {
if(decl.type==VarDeclType.CONST) {
err("const declaration needs a compile-time constant initializer value")
valueerr("const declaration needs a compile-time constant initializer value")
super.visit(decl)
return
}
@@ -760,10 +777,10 @@ internal class AstChecker(private val program: Program,
val numvalue = decl.value as? NumericLiteral
if(numvalue!=null) {
if (numvalue.type !in IntegerDatatypes || numvalue.number.toInt() < 0 || numvalue.number.toInt() > 65535) {
err("memory address must be valid integer 0..\$ffff")
valueerr("memory address must be valid integer 0..\$ffff")
}
} else {
err("value of memory mapped variable can only be a constant, maybe use an address pointer type instead?")
valueerr("value of memory mapped variable can only be a constant, maybe use an address pointer type instead?")
}
}
}
@@ -775,10 +792,10 @@ internal class AstChecker(private val program: Program,
if(decl.isArray) {
val eltDt = ArrayToElementTypes.getValue(decl.datatype)
if(iDt isnot eltDt)
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
valueerr("value has incompatible type ($iDt) for the variable (${decl.datatype})")
} else {
if(!(iDt.isBool && decl.datatype==DataType.UBYTE || iDt.istype(DataType.UBYTE) && decl.datatype==DataType.BOOL))
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
valueerr("value has incompatible type ($iDt) for the variable (${decl.datatype})")
}
}
}
@@ -827,7 +844,7 @@ internal class AstChecker(private val program: Program,
if(decl.type==VarDeclType.MEMORY)
err("strings can't be memory mapped")
else
err("string var must be initialized with a string literal")
valueerr("string var must be initialized with a string literal")
}
}
@@ -992,6 +1009,13 @@ internal class AstChecker(private val program: Program,
errors.err("array literal for iteration must contain constants. Try using a separate array variable instead?", array.position)
}
if(array.parent is Assignment) {
val arraydt = array.inferType(program)
val assignTarget = (array.parent as Assignment).target
val targetDt = assignTarget.inferType(program)
if(arraydt!=targetDt)
errors.err("value has incompatible type ($arraydt) for the variable ($targetDt)", array.position)
}
super.visit(array)
}
@@ -1258,11 +1282,15 @@ internal class AstChecker(private val program: Program,
}
override fun visit(bfc: BuiltinFunctionCall) {
// most function calls, even to builtin functions, are still regular FunctionCall nodes here.
// they get converted to the more specialized node type in BeforeAsmTypecastCleaner
checkLongType(bfc)
super.visit(bfc)
}
override fun visit(functionCallStatement: FunctionCallStatement) {
// most function calls, even to builtin functions, are still regular FunctionCall nodes here.
// they get converted to the more specialized node type in BeforeAsmTypecastCleaner
val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors)
if(targetStatement!=null) {
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
@@ -1339,7 +1367,7 @@ internal class AstChecker(private val program: Program,
if(target.name=="call") {
if(args[0] is AddressOf)
errors.err("can't call this indirectly, just use normal function call syntax", args[0].position)
if(args[0] is IdentifierReference) {
else if(args[0] is IdentifierReference) {
val callTarget = (args[0] as IdentifierReference).targetStatement(program)
if(callTarget !is VarDecl)
errors.err("can't call this indirectly, just use normal function call syntax", args[0].position)
@@ -1600,7 +1628,7 @@ internal class AstChecker(private val program: Program,
return err("boolean array length must be 1-256")
val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value")
if (arraySize != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return err("array size mismatch (expecting $expectedSize, got $arraySize)")
return true
}
return err("invalid boolean array size, must be 1-256")
@@ -1619,7 +1647,7 @@ internal class AstChecker(private val program: Program,
return err("byte array length must be 1-256")
val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value")
if (arraySize != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return err("array size mismatch (expecting $expectedSize, got $arraySize)")
return true
}
return err("invalid byte array size, must be 1-256")
@@ -1639,7 +1667,7 @@ internal class AstChecker(private val program: Program,
return err("array length must be 1-$maxLength")
val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value")
if (arraySize != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return err("array size mismatch (expecting $expectedSize, got $arraySize)")
return true
}
return err("invalid array size, must be 1-$maxLength")
@@ -1658,7 +1686,7 @@ internal class AstChecker(private val program: Program,
return err("float array length must be 1-51")
val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value")
if (arraySize != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return err("array size mismatch (expecting $expectedSize, got $arraySize)")
} else
return err("invalid float array size, must be 1-51")
@@ -1727,7 +1755,7 @@ internal class AstChecker(private val program: Program,
return true
}
private fun checkArrayValues(value: ArrayLiteral, type: DataType): Boolean {
private fun checkArrayValues(value: ArrayLiteral, targetDt: DataType): Boolean {
val array = value.value.map {
when (it) {
is NumericLiteral -> it.number.toInt()
@@ -1739,13 +1767,13 @@ internal class AstChecker(private val program: Program,
if(cast==null || !cast.isValid)
-9999999
else
cast.valueOrZero().number.toInt()
cast.valueOrZero().number
}
else -> -9999999
}
}
val correct: Boolean
when (type) {
when (targetDt) {
DataType.ARRAY_UB -> {
correct = array.all { it in 0..255 }
}
@@ -1762,18 +1790,29 @@ internal class AstChecker(private val program: Program,
correct = array.all { it==0 || it==1 }
}
DataType.ARRAY_F -> correct = true
else -> throw FatalAstException("invalid array type $type")
else -> throw FatalAstException("invalid type $targetDt")
}
if (!correct)
errors.err("array value out of range for type $type", value.position)
errors.err("array element out of range for type $targetDt", value.position)
return correct
}
private fun checkAssignmentCompatible(targetDatatype: DataType,
private fun checkAssignmentCompatible(target: AssignTarget,
targetDatatype: DataType,
sourceDatatype: DataType,
sourceValue: Expression) : Boolean {
val position = sourceValue.position
if(sourceValue is ArrayLiteral && targetDatatype in ArrayDatatypes) {
val vardecl=target.identifier?.targetVarDecl(program)
val targetSize = vardecl?.arraysize?.constIndex()
if(targetSize!=null) {
if(sourceValue.value.size != targetSize) {
errors.err("array size mismatch (expecting $targetSize, got ${sourceValue.value.size})", sourceValue.position)
}
}
}
if(sourceValue is RangeExpression) {
errors.err("can't assign a range value to something else", position)
return false
@@ -1793,8 +1832,12 @@ internal class AstChecker(private val program: Program,
DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype == DataType.STR
else -> {
errors.err("cannot assign new value to variable of type $targetDatatype", position)
false
if(targetDatatype in ArrayDatatypes && sourceValue is ArrayLiteral)
true // assigning array literal to an array variable is allowed, size and type are checked elsewhere
else {
errors.err("cannot assign this value to variable of type $targetDatatype", position)
false
}
}
}
@@ -1815,12 +1858,21 @@ internal class AstChecker(private val program: Program,
else if(targetDatatype==DataType.UWORD && sourceDatatype in PassByReferenceDatatypes) {
// this is allowed: a pass-by-reference datatype into a uword (pointer value).
}
else if(sourceDatatype in ArrayDatatypes && targetDatatype in ArrayDatatypes) {
// this is allowed (assigning array to array)
}
else if(sourceDatatype==DataType.BOOL && targetDatatype!=DataType.BOOL) {
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
else if(targetDatatype==DataType.BOOL && sourceDatatype!=DataType.BOOL) {
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
else if(targetDatatype==DataType.STR) {
if(sourceDatatype==DataType.UWORD)
errors.err("can't assign UWORD to STR. If the source is a string and you actually want to overwrite the target string, use an explicit string.copy(src,tgt) instead.", position)
else
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
else {
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
@@ -27,6 +27,15 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
errors.warn("name '$name' shadows the definition at ${existing.position.file} line ${existing.position.line}", position)
}
private fun invalidNumberOfArgsError(pos: Position, numArgs: Int, params: List<String>) {
if(numArgs<params.size) {
val missing = params.drop(numArgs).joinToString(", ")
errors.err("invalid number of arguments: expected ${params.size} got $numArgs, missing: $missing", pos)
}
else
errors.err("invalid number of arguments: expected ${params.size} got $numArgs", pos)
}
override fun visit(block: Block) {
val existing = blocks[block.name]
if(existing!=null) {
@@ -166,7 +175,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
val expectedNumberOfArgs: Int = target.parameters.size
if(call.args.size != expectedNumberOfArgs) {
val pos = (if(call.args.any()) call.args[0] else (call as Node)).position
errors.err("invalid number of arguments", pos)
invalidNumberOfArgsError(pos, call.args.size, target.parameters.map { it.name })
}
}
is BuiltinFunctionPlaceholder -> {
@@ -174,7 +183,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
val expectedNumberOfArgs: Int = func.parameters.size
if(call.args.size != expectedNumberOfArgs) {
val pos = (if(call.args.any()) call.args[0] else (call as Node)).position
errors.err("invalid number of arguments", pos)
invalidNumberOfArgsError(pos, call.args.size, func.parameters.map {it.name })
}
if(target.name=="memory") {
val name = call.args[0] as? StringLiteral
@@ -49,6 +49,8 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
}
} else {
val arrayDt = array.guessDatatype(program)
if(arrayDt.isUnknown)
return noModifications
val elementDt = ArrayToElementTypes.getValue(arrayDt.getOr(DataType.UNDEFINED))
val maxSize = when(elementDt) {
in ByteDatatypesWithBoolean -> PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE
@@ -210,15 +210,11 @@ internal class StatementReorderer(
val targetType = assignment.target.inferType(program)
if(targetType.isArray && valueType.isArray) {
if (assignment.value is ArrayLiteral) {
errors.err("cannot assign array literal here, use separate assignment per element", assignment.position)
} else {
return copyArrayValue(assignment)
}
checkCopyArrayValue(assignment)
}
if(!assignment.isAugmentable) {
if (valueType.isString && (targetType istype DataType.STR || targetType istype DataType.ARRAY_B || targetType istype DataType.ARRAY_UB)) {
if (valueType istype DataType.STR && targetType istype DataType.STR) {
// replace string assignment by a call to stringcopy
return copyStringValue(assignment)
}
@@ -247,33 +243,35 @@ internal class StatementReorderer(
return noModifications
}
private fun copyArrayValue(assign: Assignment): List<IAstModification> {
private fun checkCopyArrayValue(assign: Assignment) {
val identifier = assign.target.identifier!!
val targetVar = identifier.targetVarDecl(program)!!
if(targetVar.arraysize==null) {
errors.err("array has no defined size", assign.position)
return noModifications
return
}
if(assign.value !is IdentifierReference) {
errors.err("invalid array value to assign to other array", assign.value.position)
return noModifications
if(assign.value is ArrayLiteral) {
return // invalid assignment of literals will be reported elsewhere
}
if(assign.value !is IdentifierReference) {
return // invalid assignment value will be reported elsewhere
}
val sourceIdent = assign.value as IdentifierReference
val sourceVar = sourceIdent.targetVarDecl(program)!!
if(!sourceVar.isArray) {
errors.err("value must be an array", sourceIdent.position)
} else {
if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex())
errors.err("element count mismatch", assign.position)
errors.err("array size mismatch (expecting ${targetVar.arraysize!!.constIndex()}, got ${sourceVar.arraysize!!.constIndex()})", assign.value.position)
val sourceEltDt = ArrayToElementTypes.getValue(sourceVar.datatype)
val targetEltDt = ArrayToElementTypes.getValue(targetVar.datatype)
if (!sourceEltDt.equalsSize(targetEltDt)) {
errors.err("element size mismatch", assign.position)
}
}
return noModifications
}
private fun copyStringValue(assign: Assignment): List<IAstModification> {
@@ -308,6 +308,13 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(subroutine.returntypes.size==1) {
val subReturnType = subroutine.returntypes.first()
val returnDt = returnValue.inferType(program)
if(returnDt isnot subReturnType && returnValue is NumericLiteral) {
// see if we might change the returnvalue into the expected type
val castedValue = returnValue.convertTypeKeepValue(subReturnType)
if(castedValue.isValid) {
return listOf(IAstModification.ReplaceNode(returnValue, castedValue.valueOrZero(), returnStmt))
}
}
if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType))
return noModifications
if (returnValue is NumericLiteral) {
@@ -343,12 +350,40 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
override fun after(range: RangeExpression, parent: Node): Iterable<IAstModification> {
val fromDt = range.from.inferType(program).getOr(DataType.UNDEFINED)
val toDt = range.to.inferType(program).getOr(DataType.UNDEFINED)
val fromConst = range.from.constValue(program)
val toConst = range.to.constValue(program)
val varDt = if (parent is ContainmentCheck)
parent.element.inferType(program)
else if (parent is ForLoop)
parent.loopVarDt(program)
else
InferredTypes.InferredType.unknown()
return adjustRangeDts(range, fromConst, fromDt, toConst, toDt, varDt.getOr(DataType.UNDEFINED), parent)
}
private fun adjustRangeDts(
range: RangeExpression,
fromConst: NumericLiteral?,
fromDt: DataType,
toConst: NumericLiteral?,
toDt: DataType,
varDt: DataType,
parent: Node
): List<IAstModification> {
if(varDt!=DataType.UNDEFINED) {
if(fromDt==varDt && toDt==varDt) {
return noModifications
} else if(fromDt==toDt && fromDt.isAssignableTo(varDt)) {
return noModifications
}
}
if(fromConst!=null) {
val smaller = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position)
if(fromConst.type.largerThan(smaller.type)) {
if(fromDt.largerThan(smaller.type)) {
val toType = range.to.inferType(program)
if(toType isnot smaller.type) {
if(toConst!=null) {
@@ -367,7 +402,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
if(toConst!=null) {
val smaller = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position)
if(toConst.type.largerThan(smaller.type)) {
if(toDt.largerThan(smaller.type)) {
val fromType = range.from.inferType(program)
if(fromType isnot smaller.type) {
if(fromConst!=null) {
@@ -386,8 +421,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
val modifications = mutableListOf<IAstModification>()
val fromDt = range.from.inferType(program).getOr(DataType.UNDEFINED)
val toDt = range.to.inferType(program).getOr(DataType.UNDEFINED)
val (commonDt, toChange) = BinaryExpression.commonDatatype(fromDt, toDt, range.from, range.to)
if(toChange!=null)
addTypecastOrCastedValueModification(modifications, toChange, commonDt, range)
@@ -135,7 +135,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
}
if(isMultiComparisonRecurse(leftBinExpr1)) {
val elementType = needle.inferType(program).getOrElse { throw FatalAstException("invalid needle dt") }
val elementIType = needle.inferType(program)
if(elementIType.isUnknown) return noModifications
val elementType = elementIType.getOrElse { DataType.UNDEFINED }
if(values.size==2 || values.size==3 && (elementType==DataType.UBYTE || elementType==DataType.UWORD)) {
val numbers = values.map{it.number}.toSet()
if(numbers == setOf(0.0, 1.0)) {
+4 -5
View File
@@ -114,8 +114,9 @@ class TestCompilerOnExamplesCx16: FunSpec({
"sprites/dragon",
"sprites/dragons",
"amiga",
"audio",
"audioroutines",
"automatons",
"balloonflight",
"bdmusic",
"bobs",
"bubbleuniverse",
@@ -127,7 +128,6 @@ class TestCompilerOnExamplesCx16: FunSpec({
"cxlogo",
"diskspeed",
"fileseek",
"highresbitmap",
"kefrenbars",
"keyboardhandler",
"life",
@@ -139,6 +139,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
"showbmx",
"snow",
"spotlight",
"starszoom",
"tehtriz",
"testgfx2",
"testmonogfx",
@@ -168,8 +169,7 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
"cube3d-gfx",
"dirlist",
"fibonacci",
"line-circle-gfx",
"line-circle-txt",
"fractal-tree",
"maze",
"mandelbrot",
"mandelbrot-gfx",
@@ -177,7 +177,6 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
"primes",
"queens",
"screencodes",
"sincos",
"swirl",
"swirl-float",
"tehtriz",
+38
View File
@@ -10,6 +10,7 @@ import prog8.ast.expressions.ArrayLiteral
import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteral
import prog8.ast.expressions.StringLiteral
import prog8.ast.statements.AnonymousScope
import prog8.code.core.DataType
import prog8.code.core.Encoding
import prog8.code.core.Position
@@ -183,4 +184,41 @@ class TestNumericLiteral: FunSpec({
NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).type shouldBe DataType.WORD
NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).number shouldBe -1234.0
}
test("cast can change value") {
fun num(dt: DataType, num: Double): NumericLiteral {
val n = NumericLiteral(dt, num, Position.DUMMY)
n.linkParents(AnonymousScope(mutableListOf(), Position.DUMMY))
return n
}
val cast1 = num(DataType.UBYTE, 200.0).cast(DataType.BYTE, false)
cast1.isValid shouldBe true
cast1.valueOrZero().number shouldBe -56.0
val cast2 = num(DataType.BYTE, -50.0).cast(DataType.UBYTE, false)
cast2.isValid shouldBe true
cast2.valueOrZero().number shouldBe 206.0
val cast3 = num(DataType.UWORD, 55555.0).cast(DataType.WORD, false)
cast3.isValid shouldBe true
cast3.valueOrZero().number shouldBe -9981.0
val cast4 = num(DataType.WORD, -3333.0).cast(DataType.UWORD, false)
cast4.isValid shouldBe true
cast4.valueOrZero().number shouldBe 62203.0
}
test("convert cannot change value") {
fun num(dt: DataType, num: Double): NumericLiteral {
val n = NumericLiteral(dt, num, Position.DUMMY)
n.linkParents(AnonymousScope(mutableListOf(), Position.DUMMY))
return n
}
num(DataType.UBYTE, 200.0).convertTypeKeepValue(DataType.BYTE).isValid shouldBe false
num(DataType.BYTE, -50.0).convertTypeKeepValue(DataType.UBYTE).isValid shouldBe false
num(DataType.UWORD, 55555.0).convertTypeKeepValue(DataType.WORD).isValid shouldBe false
num(DataType.WORD, -3333.0).convertTypeKeepValue(DataType.UWORD).isValid shouldBe false
num(DataType.UBYTE, 42.0).convertTypeKeepValue(DataType.BYTE).isValid shouldBe true
num(DataType.BYTE, 42.0).convertTypeKeepValue(DataType.UBYTE).isValid shouldBe true
num(DataType.UWORD, 12345.0).convertTypeKeepValue(DataType.WORD).isValid shouldBe true
num(DataType.WORD, 12345.0).convertTypeKeepValue(DataType.UWORD).isValid shouldBe true
}
})
+24
View File
@@ -47,6 +47,30 @@ class TestOptimization: FunSpec({
}
}
test("scan all asmsubs to see if another subroutine is referenced") {
val src="""
main {
sub foo() {
cx16.r0++
}
asmsub baz() {
%asm{{
jsr p8s_foo
}}
}
asmsub bar() {
%asm{{
inx
jmp p8s_foo
}}
}
sub start() {
bar()
}
}"""
compileText(C64Target(), true, src) shouldNotBe null
}
test("don't remove empty subroutine if it's referenced") {
val sourcecode = """
main {
+1 -1
View File
@@ -33,7 +33,7 @@ class TestSubroutines: FunSpec({
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "type mismatch, was: STR expected: UBYTE"
errors.errors[1] shouldContain "initialisation value has incompatible type"
errors.errors[1] shouldContain "value has incompatible type"
}
test("stringParameter") {
+30
View File
@@ -857,4 +857,34 @@ main {
errors.errors.size shouldBe 2
errors.errors[1] shouldContain "undefined symbol"
}
test("return unsigned values for signed results ok if value fits") {
val src = """
main {
sub start() {
void foo()
void bar()
void overflow1()
void overflow2()
}
sub foo() -> byte {
return 42
}
sub bar() -> word {
return 12345
}
sub overflow1() -> byte {
return 200
}
sub overflow2() -> word {
return 44444
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "17:16: type UBYTE of return value doesn't match subroutine's return type BYTE"
errors.errors[1] shouldContain "20:16: type UWORD of return value doesn't match subroutine's return type WORD"
}
})
+52
View File
@@ -237,4 +237,56 @@ main {
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "name conflict"
}
test("various range datatype checks allow differences in type") {
val src="""
main {
sub func() -> ubyte {
cx16.r0++
return cx16.r0L
}
sub start() {
bool[256] @shared cells
word starw
byte bb
uword uw
ubyte ub
starw = (240-64 as word) + func()
for starw in 50 downto 10 {
cx16.r0++
}
for starw in cx16.r0L downto 10 {
cx16.r0++
}
for ub in 0 to len(cells)-1 {
cx16.r0++
}
for ub in cx16.r0L to len(cells)-1 {
cx16.r0++
}
for bb in 50 downto 10 {
cx16.r0++
}
for bb in cx16.r0sL downto 10 {
cx16.r0++
}
for starw in 500 downto 10 {
cx16.r0++
}
for uw in 50 downto 10 {
cx16.r0++
}
for uw in 500 downto 10 {
cx16.r0++
}
}
}"""
compileText(C64Target(), false, src, writeAssembly = false) shouldNotBe null
compileText(C64Target(), true, src, writeAssembly = false) shouldNotBe null
}
})
+2 -2
View File
@@ -884,7 +884,7 @@ class TestProg8Parser: FunSpec( {
main {
sub start() {
str string = "hello"
ubyte[] array = [1,2,3,4]
ubyte[ ] array = [1,2,3,4]
bool bb
ubyte cc
@@ -915,7 +915,7 @@ class TestProg8Parser: FunSpec( {
main {
sub start() {
bool @shared cc
ubyte[] array = [1,2,3]
ubyte [ ] array = [1,2,3]
cc = 99 in 12345
cc = 9999 in array
}
+3
View File
@@ -92,8 +92,11 @@ main {
main {
sub start() {
uword func = 12345
uword[] pointers = [1234,6789]
void call(func) ; ok
void call(12345) ; ok
void call(pointers[1]) ; ok
void call(cx16.r0+10) ; ok
cx16.r0 = call(func) ; ok
void call(&start) ; error
void call(start) ; error
@@ -638,5 +638,53 @@ main {
errors.errors[1] shouldEndWith "cannot assign to 'void', perhaps a void function call was intended"
errors.errors[2] shouldEndWith "cannot assign to 'void', perhaps a void function call was intended"
}
test("missing return value is a syntax error") {
val src="""
main {
sub start() {
cx16.r0 = runit1()
cx16.r1 = runit2()
}
sub runit1() -> uword {
repeat {
cx16.r0++
goto runit1
}
}
sub runit2() -> uword {
cx16.r0++
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), optimize=false, src, writeAssembly=false, errors = errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "has result value"
errors.errors[1] shouldContain "has result value"
}
test("missing return value is not a syntax error if there's an external goto") {
val src="""
main {
sub start() {
cx16.r0 = runit1()
runit2()
}
sub runit1() -> uword {
repeat {
cx16.r0++
goto runit2
}
}
sub runit2() {
cx16.r0++
}
}"""
compileText(C64Target(), optimize=false, src, writeAssembly=false) shouldNotBe null
}
})
@@ -4,6 +4,7 @@ import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests
@@ -327,5 +328,80 @@ main {
errors.errors[1] shouldContain "out of bounds"
errors.errors[2] shouldContain "out of bounds"
}
test("array assignments should check for number of elements and element type correctness") {
val src="""
%option enable_floats
main {
sub start() {
ubyte[] array = 1 to 4
ubyte[] array2 = [1,2,3,4]
str[] names = ["apple", "banana", "tomato"]
array = [10,11,12,13] ; ok!
array = 20 to 23 ; ok!
names = ["x1", "x2", "x3"] ; ok!
ubyte[] array3 = [1,2,3,4000] ; error: element type
array = 10 to 15 ; error: array size
array = 1000 to 1003 ; error: element type
names = ["x1", "x2", "x3", "x4"] ; error: array size
names = [1.1, 2.2, 3.3, 4.4] ; error: array size AND element type
names = [1.1, 2.2, 999999.9] ; error: element type
names = [1.1, 2.2, 9.9] ; error: element type
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = true, errors = errors) shouldBe null
errors.errors.size shouldBe 8
errors.errors[0] shouldContain "incompatible type"
errors.errors[1] shouldContain "array size mismatch"
errors.errors[2] shouldContain "array element out of range"
errors.errors[3] shouldContain "array size mismatch"
errors.errors[4] shouldContain "array size mismatch"
errors.errors[5] shouldContain "value has incompatible type"
errors.errors[6] shouldContain "value has incompatible type"
errors.errors[7] shouldContain "value has incompatible type"
}
test("array assignments should work via array copy call") {
val src="""
%option enable_floats
main {
sub start() {
ubyte[] array = [1,2,3]
ubyte[3] array2
float[] flarray = [1.1, 2.2, 3.3]
float[3] flarray2
word[] warray = [-2222,42,3333]
word[3] warray2
str[] names = ["apple", "banana", "tomato"]
str[3] names2
; 8 array assignments -> 8 arraycopies:
array = [8,7,6]
array = array2
flarray = [99.9, 88.8, 77.7]
flarray = flarray2
warray = [4444,5555,6666]
warray = warray2
names = ["x1", "x2", "x3"]
names = names2
}
}"""
compileText(VMTarget(), false, src, writeAssembly = true) shouldNotBe null
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
val x = result.codegenAst!!.entrypoint()!!
(x.children[12] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[13] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[14] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[15] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[16] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[17] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[18] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
(x.children[19] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
}
})
@@ -110,8 +110,8 @@ class TestVariables: FunSpec({
val errors = ErrorReporterForTests()
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "initialisation value has incompatible type"
errors.errors[1] shouldContain "initialisation value has incompatible type"
errors.errors[0] shouldContain "value has incompatible type"
errors.errors[1] shouldContain "value has incompatible type"
}
test("initialization of boolean array with single value") {
@@ -384,6 +384,32 @@ main {
compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
}
test("block start address must be greater than program load address") {
val src = """
%output raw
%launcher none
%address ${'$'}2000
main $2000 {
sub start() {
sys.clear_carry()
}
}
otherblock ${'$'}2013 {
%option force_output
}
thirdblock ${'$'}2014 {
%option force_output
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "6:1: block address must be at least program load address + 20"
errors.errors[1] shouldContain "12:1: block address must be at least program load address + 20"
}
test("for loops with just 1 iteration") {
val src="""
main {
@@ -254,7 +254,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
output("goto ")
when {
jump.address!=null -> output(jump.address!!.toHex())
jump.generatedLabel!=null -> output(jump.generatedLabel)
jump.identifier!=null -> jump.identifier.accept(this)
}
}
@@ -316,16 +315,16 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
}
override fun visit(array: ArrayLiteral) {
outputListMembers(array.value.asSequence())
outputListMembers(array.value)
}
private fun outputListMembers(array: Sequence<Expression>) {
private fun outputListMembers(array: Array<Expression>) {
var counter = 0
output("[")
scopelevel++
for (v in array) {
for ((idx, v) in array.withIndex()) {
v.accept(this)
if (v !== array.last())
if (idx != array.size-1)
output(", ")
counter++
if (counter > 16) {
+1 -1
View File
@@ -158,6 +158,6 @@ class Program(val name: String,
fun jumpLabel(label: Label): Jump {
val ident = IdentifierReference(listOf(label.name), label.position)
return Jump(null, ident, null, label.position)
return Jump(null, ident, label.position)
}
}
@@ -2,30 +2,53 @@ package prog8.ast
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.code.core.DataType
import prog8.code.core.ZeropageWish
import prog8.code.core.toHex
import prog8.code.core.*
import java.io.PrintStream
fun printSymbols(program: Program) {
println()
val printer = SymbolPrinter(::print, program, false)
printer.visit(program)
val symbols = SymbolDumper(false)
symbols.visit(program)
symbols.write(System.out)
println()
}
class SymbolPrinter(val output: (text: String) -> Unit, val program: Program, val skipLibraries: Boolean): IAstVisitor {
private fun outputln(text: String) = output(text + "\n")
private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor {
private val moduleOutputs = mutableMapOf<Module, MutableList<String>>()
private var currentModule = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("dummy"))
private fun output(line: String) {
var lines = moduleOutputs[currentModule]
if(lines == null) {
lines = mutableListOf()
moduleOutputs[currentModule] = lines
}
lines.add(line)
}
private fun outputln(line: String) = output(line + '\n')
fun write(out: PrintStream) {
for((module, lines) in moduleOutputs.toSortedMap(compareBy { it.name })) {
if(lines.any()) {
val moduleName = "LIBRARY MODULE NAME: ${module.source.name}"
out.println()
out.println(moduleName)
out.println("-".repeat(moduleName.length))
out.println()
for (line in lines) {
out.print(line)
}
}
}
}
override fun visit(module: Module) {
if(!module.isLibrary || !skipLibraries) {
if(module.source.isFromFilesystem || module.source.isFromResources) {
val moduleName = "LIBRARY MODULE NAME: ${module.source.name}"
outputln(moduleName)
outputln("-".repeat(moduleName.length))
currentModule = module
super.visit(module)
output("\n")
}
}
}
@@ -284,7 +284,7 @@ private fun ReturnstmtContext.toAst() : Return {
private fun UnconditionaljumpContext.toAst(): Jump {
val address = integerliteral()?.toAst()?.number?.toUInt()
val identifier = scoped_identifier()?.toAst()
return Jump(address, identifier, null, toPosition())
return Jump(address, identifier, toPosition())
}
private fun LabeldefContext.toAst(): Statement =
@@ -503,8 +503,16 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
if(scoped_identifier()!=null)
return scoped_identifier().toAst()
if(bop!=null)
return BinaryExpression(left.toAst(), bop.text.trim(), right.toAst(), toPosition(), insideParentheses=insideParentheses)
if(bop!=null) {
val operator = bop.text.trim().replace("\\s+".toRegex(), " ")
return BinaryExpression(
left.toAst(),
operator,
right.toAst(),
toPosition(),
insideParentheses = insideParentheses
)
}
if(prefix!=null)
return PrefixExpression(prefix.text, expression(0).toAst(), toPosition())
@@ -419,25 +419,31 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), position)
override fun constValue(program: Program): NumericLiteral? {
val target = this.identifier.targetStatement(program) as? VarDecl
if(target?.type==VarDeclType.MEMORY || target?.type==VarDeclType.CONST) {
var address = target.value?.constValue(program)?.number
if(address!=null) {
if(arrayIndex!=null) {
val index = arrayIndex?.constIndex()
if (index != null) {
address += when (target.datatype) {
DataType.UWORD -> index
in ArrayDatatypes -> program.memsizer.memorySize(target.datatype, index)
else -> throw FatalAstException("need array or uword ptr")
}
val target = this.identifier.targetStatement(program)
val targetVar = target as? VarDecl
if(targetVar!=null) {
if (targetVar.type == VarDeclType.MEMORY || targetVar.type == VarDeclType.CONST) {
var address = targetVar.value?.constValue(program)?.number
if (address != null) {
if (arrayIndex != null) {
val index = arrayIndex?.constIndex()
if (index != null) {
address += when (targetVar.datatype) {
DataType.UWORD -> index
in ArrayDatatypes -> program.memsizer.memorySize(targetVar.datatype, index)
else -> throw FatalAstException("need array or uword ptr")
}
} else
return null
}
else
return null
return NumericLiteral(DataType.UWORD, address, position)
}
return NumericLiteral(DataType.UWORD, address, position)
}
}
val targetSub = target as? Subroutine
if(targetSub?.asmAddress!=null) {
return NumericLiteral(DataType.UWORD, targetSub.asmAddress.toDouble(), position)
}
return null
}
override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true
@@ -606,6 +612,9 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
}
private fun internalCast(targettype: DataType, implicit: Boolean): ValueAfterCast {
// NOTE: this MAY convert a value into another when switching from singed to unsigned!!!
if(type==targettype)
return ValueAfterCast(true, null, this)
if (implicit) {
@@ -730,6 +739,49 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
}
return ValueAfterCast(false, "no cast available from $type to $targettype", null)
}
fun convertTypeKeepValue(targetDt: DataType): ValueAfterCast {
if(type==targetDt)
return ValueAfterCast(true, null, this)
when(type) {
DataType.UBYTE -> {
when(targetDt) {
DataType.BYTE -> if(number<=127.0) return cast(targetDt, false)
DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT -> return cast(targetDt, false)
else -> {}
}
}
DataType.BYTE -> {
when(targetDt) {
DataType.UBYTE, DataType.UWORD -> if(number>=0.0) return cast(targetDt, false)
DataType.WORD, DataType.LONG, DataType.FLOAT -> return cast(targetDt, false)
else -> {}
}
}
DataType.UWORD -> {
when(targetDt) {
DataType.UBYTE -> if(number<=255.0) return cast(targetDt, false)
DataType.BYTE -> if(number<=127.0) return cast(targetDt, false)
DataType.WORD -> if(number<=32767.0) return cast(targetDt, false)
DataType.LONG, DataType.FLOAT -> return cast(targetDt, false)
else -> {}
}
}
DataType.WORD -> {
when(targetDt) {
DataType.UBYTE -> if(number in 0.0..255.0) return cast(targetDt, false)
DataType.BYTE -> if(number in -128.0..127.0) return cast(targetDt, false)
DataType.UWORD -> if(number in 0.0..32767.0) return cast(targetDt, false)
DataType.LONG, DataType.FLOAT -> return cast(targetDt, false)
else -> {}
}
}
DataType.LONG, DataType.FLOAT -> return cast(targetDt, false)
else -> {}
}
return ValueAfterCast(false, "no type conversion possible from $type to $targetDt", null)
}
}
class CharLiteral private constructor(val value: Char,
@@ -642,7 +642,6 @@ data class AssignTarget(var identifier: IdentifierReference?,
class Jump(var address: UInt?,
val identifier: IdentifierReference?,
val generatedLabel: String?, // can be used in code generation scenarios
override val position: Position) : Statement() {
override lateinit var parent: Node
@@ -658,13 +657,13 @@ class Jump(var address: UInt?,
else
throw FatalAstException("can't replace $node")
}
override fun copy() = Jump(address, identifier?.copy(), generatedLabel, position)
override fun copy() = Jump(address, identifier?.copy(), position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun referencesIdentifier(nameInSource: List<String>): Boolean = identifier?.referencesIdentifier(nameInSource)==true
override fun toString() =
"Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
"Jump(addr: $address, identifier: $identifier, pos=$position)"
}
class FunctionCallStatement(override var target: IdentifierReference,
+10 -8
View File
@@ -162,20 +162,22 @@ class CallGraph(private val program: Program) : IAstVisitor {
fun unused(sub: Subroutine): Boolean {
if(sub in usedSubroutines)
return false
val asm = nameInAssemblyCode(sub.name, listOf("p8s_", ""))
if(asm!=null) {
val asms = nameInAssemblyCode(sub.name, listOf("p8s_", ""))
if(asms.isEmpty())
return true
val allUnused = asms.all { asm->
// check that the asm block that calls us, is inside a subroutine that is unused or not
val containingSub = asm.definingSubroutine
return if(containingSub != null && containingSub !== sub)
if(containingSub != null && containingSub !== sub)
unused(containingSub)
else
false
}
return true
return allUnused
}
fun unused(block: Block): Boolean {
return block !in usedBlocks && nameInAssemblyCode(block.name, listOf("p8b_", ""))==null
return block !in usedBlocks && nameInAssemblyCode(block.name, listOf("p8b_", "")).isEmpty()
}
fun unused(decl: VarDecl): Boolean {
@@ -198,13 +200,13 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
private val prefixes = listOf("p8b_", "p8v_", "p8s_", "p8c_", "p8l_", "p8_", "")
private fun nameInAssemblyCode(name: String, knownAsmPrefixes: List<String> = emptyList()): InlineAssembly? {
private fun nameInAssemblyCode(name: String, knownAsmPrefixes: List<String> = emptyList()): List<InlineAssembly> {
if(knownAsmPrefixes.isNotEmpty())
return allAssemblyNodes.firstOrNull {
return allAssemblyNodes.filter {
knownAsmPrefixes.any { prefix -> prefix+name in it.names }
}
return allAssemblyNodes.firstOrNull {
return allAssemblyNodes.filter {
prefixes.any { prefix -> prefix+name in it.names }
}
}
+3
View File
@@ -1,5 +1,8 @@
; all library modules for the atari compiler target
%import anyall
%import buffers
%import compression
%import conv
%import cx16logo
%import diskio
+3
View File
@@ -1,5 +1,8 @@
; all library modules for the c128 compiler target
%import anyall
%import buffers
%import compression
%import conv
%import cx16logo
%import diskio
+3
View File
@@ -1,5 +1,8 @@
; all library modules for the c64 compiler target
%import anyall
%import buffers
%import compression
%import conv
%import cx16logo
%import diskio
+4
View File
@@ -1,6 +1,10 @@
; all library modules for the cx16 compiler target
%import audio
%import anyall
%import buffers
%import bmx
%import compression
%import conv
%import cx16logo
%import diskio
+3
View File
@@ -1,5 +1,8 @@
; all library modules for the pet32 compiler target
%import anyall
%import buffers
%import compression
%import conv
%import cx16logo
%import diskio
+3
View File
@@ -1,5 +1,8 @@
; all library modules for the virtual compiler target
%import anyall
%import buffers
%import compression
%import conv
%import cx16logo
%import diskio
@@ -1,13 +1,66 @@
Prog8 compiler v10.4.1 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v10.4.2 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-atari.p8
Compiler target: atari
LIBRARY MODULE NAME: anyall
---------------------------
anyall {
all (uword arrayptr, uword num_elements) -> bool
allw (uword arrayptr, uword num_elements) -> bool
any (uword arrayptr, uword num_elements) -> bool
anyw (uword arrayptr, uword num_elements) -> bool
}
LIBRARY MODULE NAME: buffers
----------------------------
smallringbuffer {
ubyte[] buffer
ubyte fill
ubyte head
ubyte tail
get () -> ubyte
getw () -> uword
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
ringbuffer {
uword buffer_ptr
uword fill
uword head
uword tail
get () -> ubyte
getw () -> uword
inc_head ()
inc_tail ()
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
LIBRARY MODULE NAME: conv
-------------------------
conv {
str @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
@@ -37,6 +90,7 @@ conv {
LIBRARY MODULE NAME: cx16logo
-----------------------------
cx16logo {
uword[] logo_lines
logo ()
@@ -44,58 +98,126 @@ cx16logo {
}
LIBRARY MODULE NAME: textio
LIBRARY MODULE NAME: diskio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A)
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
get_column () -> ubyte
get_cursor (uword colptr, uword rowptr)
get_row () -> ubyte
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
plot (ubyte col, ubyte rownum)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum)
scroll_down (bool alsocolors @Pc) -> clobbers (A)
scroll_left (bool alsocolors @Pc) -> clobbers (A,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A)
scroll_up (bool alsocolors @Pc) -> clobbers (A)
setcc (ubyte col, ubyte row, ubyte char, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: syslib
---------------------------
atari {
&uword COLCRS
&uword IRQ_VEC
@@ -108,7 +230,14 @@ atari {
}
sys {
const ubyte sizeof_bool
const ubyte sizeof_byte
const ubyte sizeof_float
const ubyte sizeof_ubyte
const ubyte sizeof_uword
const ubyte sizeof_word
const ubyte target
cleanup_at_exit ()
clear_carry ()
clear_irqd ()
disable_caseswitch ()
@@ -242,122 +371,62 @@ cx16 {
}
LIBRARY MODULE NAME: diskio
---------------------------
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: test_stack
-------------------------------
test_stack {
test ()
}
LIBRARY MODULE NAME: textio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A)
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
get_column () -> ubyte
get_cursor (uword colptr, uword rowptr)
get_row () -> ubyte
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
plot (ubyte col, ubyte rownum)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum)
scroll_down (bool alsocolors @Pc) -> clobbers (A)
scroll_left (bool alsocolors @Pc) -> clobbers (A,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A)
scroll_up (bool alsocolors @Pc) -> clobbers (A)
setcc (ubyte col, ubyte row, ubyte char, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
}
+230 -165
View File
@@ -1,13 +1,66 @@
Prog8 compiler v10.4.1 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v10.4.2 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c128.p8
Compiler target: c128
LIBRARY MODULE NAME: anyall
---------------------------
anyall {
all (uword arrayptr, uword num_elements) -> bool
allw (uword arrayptr, uword num_elements) -> bool
any (uword arrayptr, uword num_elements) -> bool
anyw (uword arrayptr, uword num_elements) -> bool
}
LIBRARY MODULE NAME: buffers
----------------------------
smallringbuffer {
ubyte[] buffer
ubyte fill
ubyte head
ubyte tail
get () -> ubyte
getw () -> uword
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
ringbuffer {
uword buffer_ptr
uword fill
uword head
uword tail
get () -> ubyte
getw () -> uword
inc_head ()
inc_tail ()
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
LIBRARY MODULE NAME: conv
-------------------------
conv {
str @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
@@ -37,6 +90,7 @@ conv {
LIBRARY MODULE NAME: cx16logo
-----------------------------
cx16logo {
uword[] logo_lines
logo ()
@@ -44,62 +98,126 @@ cx16logo {
}
LIBRARY MODULE NAME: textio
LIBRARY MODULE NAME: diskio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte char @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col @A) -> clobbers (A,X,Y)
fill_screen (ubyte char @A, ubyte color @Y) -> clobbers (A)
get_column () -> ubyte @Y
get_cursor (uword colptr, uword rowptr)
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
home ()
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
scroll_down (bool alsocolors @Pc) -> clobbers (A,X)
scroll_left (bool alsocolors @Pc) -> clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A,X)
scroll_up (bool alsocolors @Pc) -> clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: syslib
---------------------------
cbm {
&uword CBINV
&uword CINV
@@ -327,6 +445,12 @@ c128 {
}
sys {
const ubyte sizeof_bool
const ubyte sizeof_byte
const ubyte sizeof_float
const ubyte sizeof_ubyte
const ubyte sizeof_uword
const ubyte sizeof_word
const ubyte target
cleanup_at_exit ()
clear_carry ()
@@ -468,125 +592,66 @@ cx16 {
}
LIBRARY MODULE NAME: diskio
---------------------------
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: test_stack
-------------------------------
test_stack {
test ()
}
LIBRARY MODULE NAME: textio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte char @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col @A) -> clobbers (A,X,Y)
fill_screen (ubyte char @A, ubyte color @Y) -> clobbers (A)
get_column () -> ubyte @Y
get_cursor (uword colptr, uword rowptr)
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
home ()
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
scroll_down (bool alsocolors @Pc) -> clobbers (A,X)
scroll_left (bool alsocolors @Pc) -> clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A,X)
scroll_up (bool alsocolors @Pc) -> clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
}
+350 -288
View File
@@ -1,12 +1,66 @@
Prog8 compiler v10.4.1 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v10.4.2 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c64.p8
Compiler target: c64
LIBRARY MODULE NAME: anyall
---------------------------
anyall {
all (uword arrayptr, uword num_elements) -> bool
allw (uword arrayptr, uword num_elements) -> bool
any (uword arrayptr, uword num_elements) -> bool
anyw (uword arrayptr, uword num_elements) -> bool
}
LIBRARY MODULE NAME: buffers
----------------------------
smallringbuffer {
ubyte[] buffer
ubyte fill
ubyte head
ubyte tail
get () -> ubyte
getw () -> uword
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
ringbuffer {
uword buffer_ptr
uword fill
uword head
uword tail
get () -> ubyte
getw () -> uword
inc_head ()
inc_tail ()
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
LIBRARY MODULE NAME: conv
-------------------------
conv {
str @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
@@ -36,6 +90,7 @@ conv {
LIBRARY MODULE NAME: cx16logo
-----------------------------
cx16logo {
uword[] logo_lines
logo ()
@@ -43,62 +98,245 @@ cx16logo {
}
LIBRARY MODULE NAME: textio
LIBRARY MODULE NAME: diskio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col @A) -> clobbers (A,X,Y)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
get_column () -> ubyte @Y
get_cursor (uword colptr, uword rowptr)
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
home ()
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
scroll_down (bool alsocolors @Pc) -> clobbers (A,X)
scroll_left (bool alsocolors @Pc) -> clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A,X)
scroll_up (bool alsocolors @Pc) -> clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: floats
---------------------------
floats {
&uword AYINT_facmo
const float PI
const float TWOPI
const float π
ABS () = $bc58
ATN () -> clobbers (A,X,Y) = $e30e
AYINT () -> clobbers (A,X,Y) = $b1bf
CONUPK (uword mflpt @AY) -> clobbers (A,Y) = $ba8c
COS () -> clobbers (A,X,Y) = $e264
DIV10 () -> clobbers (A,X,Y) = $bafe
EXP () -> clobbers (A,X,Y) = $bfed
FADD (uword mflpt @AY) -> clobbers (A,X,Y) = $b867
FADDH () -> clobbers (A,X,Y) = $b849
FADDT () -> clobbers (A,X,Y) = $b86a
FAREADMEM () -> clobbers (A,Y) = $ba90
FCOMP (uword mflpt @AY) -> clobbers (X,Y) -> ubyte @A = $bc5b
FDIV (uword mflpt @AY) -> clobbers (A,X,Y) = $bb0f
FDIVT () -> clobbers (A,X,Y) = $bb12
FINLOG (byte value @A) -> clobbers (A,X,Y) = $bd7e
FMULT (uword mflpt @AY) -> clobbers (A,X,Y) = $ba28
FMULTT () -> clobbers (A,X,Y) = $ba2b
FOUT () -> clobbers (X) -> uword @AY = $bddd
FPRINTLN () -> clobbers (A,X,Y) = $aabc
FPWR (uword mflpt @AY) -> clobbers (A,X,Y) = $bf78
FPWRT () -> clobbers (A,X,Y) = $bf7b
FREADMEM () -> clobbers (A,Y) = $bba6
FREADS24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y)
FREADS32 () -> clobbers (A,X,Y)
FREADSA (byte value @A) -> clobbers (A,X,Y) = $bc3c
FREADSTR (ubyte length @A) -> clobbers (A,X,Y) = $b7b5
FREADU24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y) -> float @FAC1
FREADUS32 () -> clobbers (A,X,Y)
FREADUY (ubyte value @Y) -> clobbers (A,X,Y) = $b3a2
FSUB (uword mflpt @AY) -> clobbers (A,X,Y) = $b850
FSUBT () -> clobbers (A,X,Y) = $b853
GETADR () -> clobbers (X) -> ubyte @Y, ubyte @A = $b7f7
GETADRAY () -> clobbers (X) -> uword @AY
GIVAYF (ubyte lo @Y, ubyte hi @A) -> clobbers (A,X,Y) = $b391
GIVAYFAY (uword value @AY) -> clobbers (A,X,Y)
GIVUAYFAY (uword value @AY) -> clobbers (A,X,Y)
INT () -> clobbers (A,X,Y) = $bccc
LOG () -> clobbers (A,X,Y) = $b9ea
MOVAF () -> clobbers (A,X) = $bc0c
MOVEF () -> clobbers (A,X) = $bc0f
MOVFA () -> clobbers (A,X) = $bbfc
MOVFM (uword mflpt @AY) -> clobbers (A,Y) = $bba2
MOVMF (uword mflpt @XY) -> clobbers (A,Y) = $bbd4
MUL10 () -> clobbers (A,X,Y) = $bae2
NEGOP () -> clobbers (A) = $bfb4
NORMAL () -> clobbers (A) = $b8d7
NOTOP () -> clobbers (A,X,Y) = $aed4
QINT () -> clobbers (A,X,Y) = $bc9b
RND () -> clobbers (A,X,Y) = $e097
SGN () -> clobbers (A,X,Y) = $bc39
SIGN () -> ubyte @A = $bc2b
SIN () -> clobbers (A,X,Y) = $e26b
SQR () -> clobbers (A,X,Y) = $bf71
SQRA () -> clobbers (A,X,Y) = $bf74
TAN () -> clobbers (A,X,Y) = $e2b4
atan (float value) -> float
atan2 (float y, float x) -> float
ceil (float value) -> float
clampf (float value, float minimum, float maximum) -> float
cos (float angle) -> float
cot (float value) -> float
csc (float value) -> float
deg (float angle) -> float
floor (float value) -> float
ln (float value) -> float
log2 (float value) -> float
maxf (float f1, float f2) -> float
minf (float f1, float f2) -> float
normalize (float value @FAC1) -> float @FAC1
parse (str value @AY) -> float @FAC1
pop () -> float @FAC1
pow (float value, float power) -> float
print (float value @FAC1) -> clobbers (A,X,Y)
push (float value @FAC1)
rad (float angle) -> float
rnd () -> float
rndseed (float seed)
round (float value) -> float
secant (float value) -> float
sin (float angle) -> float
tan (float value) -> float
time () -> float @FAC1
tostr (float value @FAC1) -> clobbers (X) -> str @AY
}
LIBRARY MODULE NAME: graphics
-----------------------------
graphics {
const uword BITMAP_ADDRESS
const uword CHARS_ADDRESS
const ubyte HEIGHT
const uword WIDTH
uword @zp internal_plotx
circle (uword xcenter, ubyte ycenter, ubyte radius)
clear_screen (ubyte pixelcolor, ubyte bgcolor)
disable_bitmap_mode ()
disc (uword xcenter, ubyte ycenter, ubyte radius)
enable_bitmap_mode ()
fillrect (uword xx, ubyte yy, uword width, ubyte height)
get_y_lookup (ubyte yy @Y) -> uword @AY
horizontal_line (uword xx, ubyte yy, uword length)
internal_plot (ubyte ploty @A) -> clobbers (A,X,Y)
line (uword x1, ubyte y1, uword x2, ubyte y2)
plot (uword plotx @XY, ubyte ploty @A) -> clobbers (A,X,Y)
rect (uword xx, ubyte yy, uword width, ubyte height)
vertical_line (uword xx, ubyte yy, ubyte height)
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: syslib
---------------------------
cbm {
&uword CBINV
&uword CINV
@@ -328,6 +566,12 @@ c64 {
}
sys {
const ubyte sizeof_bool
const ubyte sizeof_byte
const ubyte sizeof_float
const ubyte sizeof_ubyte
const ubyte sizeof_uword
const ubyte sizeof_word
const ubyte target
cleanup_at_exit ()
clear_carry ()
@@ -469,248 +713,66 @@ cx16 {
}
LIBRARY MODULE NAME: shared_cbm_textio_functions
------------------------------------------------
LIBRARY MODULE NAME: diskio
---------------------------
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: shared_string_functions
--------------------------------------------
LIBRARY MODULE NAME: floats
---------------------------
floats {
&uword AYINT_facmo
const float PI
const float TWOPI
const float π
ABS () = $bc58
ATN () -> clobbers (A,X,Y) = $e30e
AYINT () -> clobbers (A,X,Y) = $b1bf
CONUPK (uword mflpt @AY) -> clobbers (A,Y) = $ba8c
COS () -> clobbers (A,X,Y) = $e264
DIV10 () -> clobbers (A,X,Y) = $bafe
EXP () -> clobbers (A,X,Y) = $bfed
FADD (uword mflpt @AY) -> clobbers (A,X,Y) = $b867
FADDH () -> clobbers (A,X,Y) = $b849
FADDT () -> clobbers (A,X,Y) = $b86a
FAREADMEM () -> clobbers (A,Y) = $ba90
FCOMP (uword mflpt @AY) -> clobbers (X,Y) -> ubyte @A = $bc5b
FDIV (uword mflpt @AY) -> clobbers (A,X,Y) = $bb0f
FDIVT () -> clobbers (A,X,Y) = $bb12
FINLOG (byte value @A) -> clobbers (A,X,Y) = $bd7e
FMULT (uword mflpt @AY) -> clobbers (A,X,Y) = $ba28
FMULTT () -> clobbers (A,X,Y) = $ba2b
FOUT () -> clobbers (X) -> uword @AY = $bddd
FPRINTLN () -> clobbers (A,X,Y) = $aabc
FPWR (uword mflpt @AY) -> clobbers (A,X,Y) = $bf78
FPWRT () -> clobbers (A,X,Y) = $bf7b
FREADMEM () -> clobbers (A,Y) = $bba6
FREADS24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y)
FREADS32 () -> clobbers (A,X,Y)
FREADSA (byte value @A) -> clobbers (A,X,Y) = $bc3c
FREADSTR (ubyte length @A) -> clobbers (A,X,Y) = $b7b5
FREADU24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y) -> float @FAC1
FREADUS32 () -> clobbers (A,X,Y)
FREADUY (ubyte value @Y) -> clobbers (A,X,Y) = $b3a2
FSUB (uword mflpt @AY) -> clobbers (A,X,Y) = $b850
FSUBT () -> clobbers (A,X,Y) = $b853
GETADR () -> clobbers (X) -> ubyte @Y, ubyte @A = $b7f7
GETADRAY () -> clobbers (X) -> uword @AY
GIVAYF (ubyte lo @Y, ubyte hi @A) -> clobbers (A,X,Y) = $b391
GIVAYFAY (uword value @AY) -> clobbers (A,X,Y)
GIVUAYFAY (uword value @AY) -> clobbers (A,X,Y)
INT () -> clobbers (A,X,Y) = $bccc
LOG () -> clobbers (A,X,Y) = $b9ea
MOVAF () -> clobbers (A,X) = $bc0c
MOVEF () -> clobbers (A,X) = $bc0f
MOVFA () -> clobbers (A,X) = $bbfc
MOVFM (uword mflpt @AY) -> clobbers (A,Y) = $bba2
MOVMF (uword mflpt @XY) -> clobbers (A,Y) = $bbd4
MUL10 () -> clobbers (A,X,Y) = $bae2
NEGOP () -> clobbers (A) = $bfb4
NORMAL () -> clobbers (A) = $b8d7
NOTOP () -> clobbers (A,X,Y) = $aed4
QINT () -> clobbers (A,X,Y) = $bc9b
RND () -> clobbers (A,X,Y) = $e097
SGN () -> clobbers (A,X,Y) = $bc39
SIGN () -> ubyte @A = $bc2b
SIN () -> clobbers (A,X,Y) = $e26b
SQR () -> clobbers (A,X,Y) = $bf71
SQRA () -> clobbers (A,X,Y) = $bf74
TAN () -> clobbers (A,X,Y) = $e2b4
atan (float value) -> float
atan2 (float y, float x) -> float
ceil (float value) -> float
clampf (float value, float minimum, float maximum) -> float
cos (float angle) -> float
cot (float value) -> float
csc (float value) -> float
deg (float angle) -> float
floor (float value) -> float
ln (float value) -> float
log2 (float value) -> float
maxf (float f1, float f2) -> float
minf (float f1, float f2) -> float
normalize (float value @FAC1) -> float @FAC1
parse (str value @AY) -> float @FAC1
pop () -> float @FAC1
pow (float value, float power) -> float
print (float value @FAC1) -> clobbers (A,X,Y)
push (float value @FAC1)
rad (float angle) -> float
rnd () -> float
rndseed (float seed)
round (float value) -> float
secant (float value) -> float
sin (float angle) -> float
tan (float value) -> float
time () -> float @FAC1
tostr (float value @FAC1) -> clobbers (X) -> str @AY
}
LIBRARY MODULE NAME: graphics
-----------------------------
graphics {
const uword BITMAP_ADDRESS
const uword CHARS_ADDRESS
const ubyte HEIGHT
const uword WIDTH
uword @zp internal_plotx
circle (uword xcenter, ubyte ycenter, ubyte radius)
clear_screen (ubyte pixelcolor, ubyte bgcolor)
disable_bitmap_mode ()
disc (uword xcenter, ubyte ycenter, ubyte radius)
enable_bitmap_mode ()
fillrect (uword xx, ubyte yy, uword width, ubyte height)
get_y_lookup (ubyte yy @Y) -> uword @AY
horizontal_line (uword xx, ubyte yy, uword length)
internal_plot (ubyte ploty @A) -> clobbers (A,X,Y)
line (uword x1, ubyte y1, uword x2, ubyte y2)
plot (uword plotx @XY, ubyte ploty @A) -> clobbers (A,X,Y)
rect (uword xx, ubyte yy, uword width, ubyte height)
vertical_line (uword xx, ubyte yy, ubyte height)
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: test_stack
-------------------------------
test_stack {
test ()
}
LIBRARY MODULE NAME: textio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col @A) -> clobbers (A,X,Y)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
get_column () -> ubyte @Y
get_cursor (uword colptr, uword rowptr)
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
home ()
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
scroll_down (bool alsocolors @Pc) -> clobbers (A,X)
scroll_left (bool alsocolors @Pc) -> clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A,X)
scroll_up (bool alsocolors @Pc) -> clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
}
File diff suppressed because it is too large. Load diff
@@ -1,13 +1,66 @@
Prog8 compiler v10.4.1 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v10.4.2 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-pet32.p8
Compiler target: pet32
LIBRARY MODULE NAME: anyall
---------------------------
anyall {
all (uword arrayptr, uword num_elements) -> bool
allw (uword arrayptr, uword num_elements) -> bool
any (uword arrayptr, uword num_elements) -> bool
anyw (uword arrayptr, uword num_elements) -> bool
}
LIBRARY MODULE NAME: buffers
----------------------------
smallringbuffer {
ubyte[] buffer
ubyte fill
ubyte head
ubyte tail
get () -> ubyte
getw () -> uword
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
ringbuffer {
uword buffer_ptr
uword fill
uword head
uword tail
get () -> ubyte
getw () -> uword
inc_head ()
inc_tail ()
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
LIBRARY MODULE NAME: conv
-------------------------
conv {
str @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
@@ -37,6 +90,7 @@ conv {
LIBRARY MODULE NAME: cx16logo
-----------------------------
cx16logo {
uword[] logo_lines
logo ()
@@ -44,56 +98,126 @@ cx16logo {
}
LIBRARY MODULE NAME: textio
LIBRARY MODULE NAME: diskio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color)
cls ()
color (ubyte txtcol)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
home ()
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
scroll_down () -> clobbers (A,X)
scroll_left () -> clobbers (A,X,Y)
scroll_right () -> clobbers (A,X)
scroll_up () -> clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col, ubyte row, ubyte color)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: syslib
---------------------------
cbm {
&uword CBINV
&uword CINV
@@ -124,6 +248,12 @@ cbm {
}
sys {
const ubyte sizeof_bool
const ubyte sizeof_byte
const ubyte sizeof_float
const ubyte sizeof_ubyte
const ubyte sizeof_uword
const ubyte sizeof_word
const ubyte target
cleanup_at_exit ()
clear_carry ()
@@ -259,125 +389,60 @@ cx16 {
}
LIBRARY MODULE NAME: diskio
---------------------------
diskio {
const ubyte READ_IO_CHANNEL
const ubyte WRITE_IO_CHANNEL
ubyte @shared drivenumber
bool iteration_in_progress
uword list_blocks
str list_filename
str list_filetype
uword list_pattern
bool list_skip_disk_name
delete (uword filenameptr)
directory () -> bool
diskname () -> uword
f_close ()
f_close_w ()
f_open (uword filenameptr) -> bool
f_open_w (uword filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (uword bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
lf_end_list ()
lf_next_entry () -> bool
lf_start_list (uword pattern_ptr) -> bool
list_filenames (uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte
load (uword filenameptr, uword address_override) -> uword
load_raw (uword filenameptr, uword start_address) -> uword
rename (uword oldfileptr, uword newfileptr)
reset_read_channel ()
reset_write_channel ()
save (uword filenameptr, uword start_address, uword savesize) -> bool
send_command (uword commandptr)
status () -> uword
status_code () -> ubyte
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (uword target @R0, uword suffix @R1) -> clobbers (Y) -> ubyte @A
compare (uword string1 @R0, uword string2 @AY) -> clobbers (Y) -> byte @A
contains (uword string @AY, ubyte character @X) -> bool @Pc
copy (uword source @R0, uword target @AY) -> clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
findstr (str haystack, str needle) -> ubyte
hash (str string @R0) -> ubyte @A
isdigit (ubyte petsciichar @A) -> bool @Pc
isletter (ubyte petsciichar @A) -> bool @Pc
islower (ubyte petsciichar @A) -> bool @Pc
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (uword source @AX, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
length (uword string @AY) -> clobbers (A) -> ubyte @Y
lower (uword st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
rfind (uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (uword source @AY, ubyte length @X, uword target @R1) -> clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (uword source @R0, ubyte start @A, ubyte length @Y, uword target @R1) -> clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (uword st @AY) -> ubyte @Y
upperchar (ubyte character @A) -> ubyte @A
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value @A)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
diffw (uword w1 @R0, uword w2 @AY) -> uword @AY
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndw () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
}
LIBRARY MODULE NAME: test_stack
-------------------------------
test_stack {
test ()
}
LIBRARY MODULE NAME: textio
---------------------------
txt {
const ubyte DEFAULT_HEIGHT
const ubyte DEFAULT_WIDTH
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color)
cls ()
color (ubyte txtcol)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
home ()
input_chars (uword buffer @AY) -> clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
scroll_down () -> clobbers (A,X)
scroll_left () -> clobbers (A,X,Y)
scroll_right () -> clobbers (A,X)
scroll_up () -> clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col, ubyte row, ubyte color)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
}
@@ -1,13 +1,64 @@
Prog8 compiler v10.4.1 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v10.4.2 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-virtual.p8
Compiler target: virtual
LIBRARY MODULE NAME: anyall
---------------------------
anyall {
all (uword arrayptr, uword num_elements) -> bool
allw (uword arrayptr, uword num_elements) -> bool
any (uword arrayptr, uword num_elements) -> bool
anyw (uword arrayptr, uword num_elements) -> bool
}
LIBRARY MODULE NAME: buffers
----------------------------
smallringbuffer {
ubyte[] buffer
ubyte fill
ubyte head
ubyte tail
get () -> ubyte
getw () -> uword
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
ringbuffer {
uword buffer_ptr
uword fill
uword head
uword tail
get () -> ubyte
getw () -> uword
inc_head ()
inc_tail ()
init ()
put (ubyte value) -> bool
putw (uword value) -> bool
}
LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed, uword target, uword maxsize) -> uword
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
}
LIBRARY MODULE NAME: conv
-------------------------
conv {
str hex_digits
str string_out
@@ -35,6 +86,7 @@ conv {
LIBRARY MODULE NAME: cx16logo
-----------------------------
cx16logo {
uword[] logo_lines
logo ()
@@ -42,43 +94,9 @@ cx16logo {
}
LIBRARY MODULE NAME: textio
---------------------------
txt {
bell ()
chrout (ubyte char)
clear_screen ()
cls ()
column (ubyte col)
height () -> ubyte
home ()
input_chars (uword buffer) -> ubyte
lowercase ()
nl ()
petscii2scr (ubyte petscii_char) -> ubyte
petscii2scr_str (str petscii_string)
plot (ubyte col, ubyte row)
print (str text)
print_b (byte value)
print_bool (bool value)
print_ub (ubyte value)
print_ub0 (ubyte value)
print_ubbin (ubyte value, bool prefix)
print_ubhex (ubyte value, bool prefix)
print_uw (uword value)
print_uw0 (uword value)
print_uwbin (uword value, bool prefix)
print_uwhex (uword value, bool prefix)
print_w (word value)
setchr (ubyte col, ubyte row, ubyte char)
spc ()
uppercase ()
width () -> ubyte
}
LIBRARY MODULE NAME: diskio
---------------------------
diskio {
chdir (str path)
curdir () -> uword
@@ -108,9 +126,175 @@ diskio {
}
LIBRARY MODULE NAME: emudbg
---------------------------
emudbg {
console_chrout (ubyte char)
console_value1 (ubyte value)
console_value2 (ubyte value)
console_write (str message)
is_emulator () -> bool
}
LIBRARY MODULE NAME: floats
---------------------------
floats {
const float PI
const float TWOPI
const float π
atan (float value) -> float
atan2 (float y, float x) -> float
ceil (float value) -> float
clampf (float value, float minimum, float maximum) -> float
cos (float angle) -> float
cot (float value) -> float
csc (float value) -> float
deg (float angle) -> float
floor (float value) -> float
ln (float value) -> float
log2 (float value) -> float
maxf (float f1, float f2) -> float
minf (float f1, float f2) -> float
normalize (float value) -> float
parse (str value) -> float
pop () -> float
pow (float value, float power) -> float
print (float value)
push (float value)
rad (float angle) -> float
rnd () -> float
rndseed (float seed)
round (float value) -> float
secant (float value) -> float
sin (float angle) -> float
tan (float value) -> float
tostr (float value) -> str
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
cos8 (ubyte angle) -> byte
cos8u (ubyte angle) -> ubyte
cosr8 (ubyte radians) -> byte
cosr8u (ubyte radians) -> ubyte
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value)
diff (ubyte b1, ubyte b2) -> ubyte
diffw (uword w1, uword w2) -> uword
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant, ubyte xdelta, ubyte ydelta) -> ubyte
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value) -> ubyte
log2w (uword value) -> ubyte
mul16_last_upper () -> uword
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> ubyte
rndseed (uword seed1, uword seed2)
rndw () -> uword
sin8 (ubyte angle) -> byte
sin8u (ubyte angle) -> ubyte
sinr8 (ubyte radians) -> byte
sinr8u (ubyte radians) -> ubyte
}
LIBRARY MODULE NAME: monogfx
----------------------------
monogfx {
const ubyte MODE_INVERT
const ubyte MODE_NORMAL
const ubyte MODE_STIPPLE
uword height
ubyte mode
uword width
circle (uword xcenter, uword ycenter, ubyte radius, bool draw)
clear_screen (bool draw)
disc (uword xcenter, uword ycenter, ubyte radius, bool draw)
drawmode (ubyte dm)
fill (uword x, uword y, bool draw)
fillrect (uword xx, uword yy, uword rwidth, uword rheight, bool draw)
hires ()
horizontal_line (uword xx, uword yy, uword length, bool draw)
line (uword x1, uword y1, uword x2, uword y2, bool draw)
lores ()
pget (uword xx, uword yy) -> bool
plot (uword xx, uword yy, bool draw)
rect (uword xx, uword yy, uword rwidth, uword rheight, bool draw)
safe_circle (uword xcenter, uword ycenter, ubyte radius, bool draw)
safe_disc (uword xcenter, uword ycenter, ubyte radius, bool draw)
safe_horizontal_line (uword xx, uword yy, uword length, bool draw)
safe_plot (uword xx, uword yy, bool draw)
text (uword xx, uword yy, bool draw, str sctextptr)
text_charset (ubyte charset)
textmode ()
vertical_line (uword xx, uword yy, uword lheight, bool draw)
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (str target, str suffix) -> ubyte
compare (str st1, str st2) -> byte
contains (str st, ubyte character) -> bool
copy (str source, str target) -> ubyte
endswith (str st, str suffix) -> bool
find (str st, ubyte character) -> ubyte
findstr (str haystack, str needle) -> ubyte
hash (str st) -> ubyte
isdigit (ubyte character) -> bool
isletter (ubyte character) -> bool
islower (ubyte character) -> bool
isprint (ubyte character) -> bool
isspace (ubyte character) -> bool
isupper (ubyte character) -> bool
left (str source, ubyte slen, str target)
length (str st) -> ubyte
lower (str st) -> ubyte
lowerchar (ubyte char) -> ubyte
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
rfind (uword stringptr, ubyte character) -> ubyte
right (str source, ubyte slen, str target)
rstrip (str s)
rtrim (str s)
slice (str source, ubyte start, ubyte slen, str target)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (str st) -> ubyte
upperchar (ubyte char) -> ubyte
}
LIBRARY MODULE NAME: syslib
---------------------------
sys {
const ubyte sizeof_bool
const ubyte sizeof_byte
const ubyte sizeof_float
const ubyte sizeof_ubyte
const ubyte sizeof_uword
const ubyte sizeof_word
const ubyte target
clear_carry ()
clear_irqd ()
@@ -241,165 +425,47 @@ cx16 {
}
LIBRARY MODULE NAME: emudbg
---------------------------
emudbg {
console_chrout (ubyte char)
console_value1 (ubyte value)
console_value2 (ubyte value)
console_write (str message)
is_emulator () -> bool
}
LIBRARY MODULE NAME: floats
---------------------------
floats {
const float PI
const float TWOPI
const float π
atan (float value) -> float
atan2 (float y, float x) -> float
ceil (float value) -> float
clampf (float value, float minimum, float maximum) -> float
cos (float angle) -> float
cot (float value) -> float
csc (float value) -> float
deg (float angle) -> float
floor (float value) -> float
ln (float value) -> float
log2 (float value) -> float
maxf (float f1, float f2) -> float
minf (float f1, float f2) -> float
normalize (float value) -> float
parse (str value) -> float
pop () -> float
pow (float value, float power) -> float
print (float value)
push (float value)
rad (float angle) -> float
rnd () -> float
rndseed (float seed)
round (float value) -> float
secant (float value) -> float
sin (float angle) -> float
tan (float value) -> float
tostr (float value) -> str
}
LIBRARY MODULE NAME: math
-------------------------
math {
atan2 (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
cos8 (ubyte angle) -> byte
cos8u (ubyte angle) -> ubyte
cosr8 (ubyte radians) -> byte
cosr8u (ubyte radians) -> ubyte
crc16 (uword data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value)
crc32 (uword data, uword length)
crc32_end ()
crc32_start ()
crc32_update (ubyte value)
diff (ubyte b1, ubyte b2) -> ubyte
diffw (uword w1, uword w2) -> uword
direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte
direction_qd (ubyte quadrant, ubyte xdelta, ubyte ydelta) -> ubyte
direction_sc (byte x1, byte y1, byte x2, byte y2) -> ubyte
log2 (ubyte value) -> ubyte
log2w (uword value) -> ubyte
mul16_last_upper () -> uword
randrange (ubyte n) -> ubyte
randrangew (uword n) -> uword
rnd () -> ubyte
rndseed (uword seed1, uword seed2)
rndw () -> uword
sin8 (ubyte angle) -> byte
sin8u (ubyte angle) -> ubyte
sinr8 (ubyte radians) -> byte
sinr8u (ubyte radians) -> ubyte
}
LIBRARY MODULE NAME: monogfx
----------------------------
monogfx {
const ubyte MODE_INVERT
const ubyte MODE_NORMAL
const ubyte MODE_STIPPLE
uword height
ubyte mode
uword width
circle (uword xcenter, uword ycenter, ubyte radius, bool draw)
clear_screen (bool draw)
disc (uword xcenter, uword ycenter, ubyte radius, bool draw)
drawmode (ubyte dm)
fill (uword x, uword y, bool draw)
fillrect (uword xx, uword yy, uword rwidth, uword rheight, bool draw)
hires ()
horizontal_line (uword xx, uword yy, uword length, bool draw)
line (uword x1, uword y1, uword x2, uword y2, bool draw)
lores ()
pget (uword xx, uword yy) -> bool
plot (uword xx, uword yy, bool draw)
rect (uword xx, uword yy, uword rwidth, uword rheight, bool draw)
safe_circle (uword xcenter, uword ycenter, ubyte radius, bool draw)
safe_disc (uword xcenter, uword ycenter, ubyte radius, bool draw)
safe_horizontal_line (uword xx, uword yy, uword length, bool draw)
safe_plot (uword xx, uword yy, bool draw)
text (uword xx, uword yy, bool draw, str sctextptr)
text_charset (ubyte charset)
textmode ()
vertical_line (uword xx, uword yy, uword lheight, bool draw)
}
LIBRARY MODULE NAME: string
---------------------------
string {
append (str target, str suffix) -> ubyte
compare (str st1, str st2) -> byte
contains (str st, ubyte character) -> bool
copy (str source, str target) -> ubyte
endswith (str st, str suffix) -> bool
find (str st, ubyte character) -> ubyte
findstr (str haystack, str needle) -> ubyte
hash (str st) -> ubyte
isdigit (ubyte character) -> bool
isletter (ubyte character) -> bool
islower (ubyte character) -> bool
isprint (ubyte character) -> bool
isspace (ubyte character) -> bool
isupper (ubyte character) -> bool
left (str source, ubyte slen, str target)
length (str st) -> ubyte
lower (str st) -> ubyte
lowerchar (ubyte char) -> ubyte
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
rfind (uword stringptr, ubyte character) -> ubyte
right (str source, ubyte slen, str target)
rstrip (str s)
rtrim (str s)
slice (str source, ubyte start, ubyte slen, str target)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
upper (str st) -> ubyte
upperchar (ubyte char) -> ubyte
}
LIBRARY MODULE NAME: test_stack
-------------------------------
test_stack {
test ()
}
LIBRARY MODULE NAME: textio
---------------------------
txt {
bell ()
chrout (ubyte char)
clear_screen ()
cls ()
column (ubyte col)
height () -> ubyte
home ()
input_chars (uword buffer) -> ubyte
lowercase ()
nl ()
petscii2scr (ubyte petscii_char) -> ubyte
petscii2scr_str (str petscii_string)
plot (ubyte col, ubyte row)
print (str text)
print_b (byte value)
print_bool (bool value)
print_ub (ubyte value)
print_ub0 (ubyte value)
print_ubbin (ubyte value, bool prefix)
print_ubhex (ubyte value, bool prefix)
print_uw (uword value)
print_uw0 (uword value)
print_uwbin (uword value, bool prefix)
print_uwhex (uword value, bool prefix)
print_w (word value)
setchr (ubyte col, ubyte row, ubyte char)
spc ()
uppercase ()
width () -> ubyte
}
+102
View File
@@ -0,0 +1,102 @@
.. _comparingprog8:
============================
Prog8 versus other languages
============================
This chapter is meant for new Prog8 users coming with existing knowledge in another programming language such as C or Python.
It discusses some key design aspects of Prog8 and how it differs from what you may know from those languages.
The language
------------
- Prog8 is a structured imperative programming language. It looks like a mix of Python and C.
- It is meant to sit well above low level assembly code, but still allows that low level access to the system it runs on.
Via language features, or even simply by using inline hand-written assembly code.
- Prog8 is targeting very CPU and memory constrained 8-bit systems, this reflects many design choices to work within those limitations
(single digit Megaherz cpu clock speeds, and memory capacity counted in Kilobytes)
- Identifiers and string literals can contain non-ASCII characters so for example ``knäckebröd`` and ``見せしめ`` are valid identifiers.
- There's usually a single statement per line. There is no statement separator.
- Semicolon ``;`` is used to start a line comment. Multi-line comments are also possible by enclosing it all in ``/*`` and ``*/``.
No linker
---------
- Even though your programs can consist of many separate module files, the compiler always outputs a single program file. There is no separate linker step.
Currently, it's not easily possible to integrate object files created elsewhere.
- The prog8 compiler is self-contained in a single jar file. You do need 1 external tool namely 64tass, which performs the assembler step.
Data types
----------
- There are byte, word (16 bits) and float datatypes for numbers. There are no bigger integer types natively available.
- There is no automatic type enlargement: calculations remain within the data type of the operands. Any overflow silently wraps or truncates.
You'll have to add explicit casts to increase the size of the value if required.
For example when adding two byte variables having values 100 and 200, the result won't be 300, because that doesn't fit in a byte. It will be 44.
You'll have to cast one or both of the *operands* to a word type first if you want to accomodate the actual result value of 300.
- strings and arrays are allocated once, statically, and never resized.
- strings and arrays are mutable: you can change their contents, but always keep the original storage size in mind to avoid overwriting memory outside of the buffer.
- maximum string length is 255 characters + a trailing 0 byte.
- maximum storage size for arrays is 256 bytes (512 for split word arrays) , the maximum number of elements in the array depends on the size of a single element value.
Variables
---------
- There is no dynamic memory management in the language; all variables are statically allocated.
(but user written libraries are possible that provide that indirectly).
- Variables can be declared everywhere inside the code but all variable declarations in a subroutine
are moved to the top of the subroutine. A for loop, or if/else blocks do not introduce a new scope.
A subroutine (also nested ones) *do* introduce a new scope.
- All variables are initialized at the start of the program. There is no random garbage in them: they are zero or any other initialization value you provide.
- This als means you can run a Prog8 program multiple times without having to reload it from disk, unlike programs produced by most other compilers targeting these 8 bit platforms.
Subroutines
-----------
- There is no function overloading (except for a couple of builtin functions).
- Some subroutine types can return multiple return values, and you can multi-assign those in a single statement.
- Because every declared variable allocates some memory, it might be beneficial to share the same variables over different subroutines
instead of defining the same sort of variables in every subroutine.
This reduces the memory needed for variables. A convenient way to do this is by using nested subroutines - these can easily access the
variables declared in their parent subroutine(s).
- Everything in prog8 is publicly accessible from everywhere else (via fully scoped names) - there is no notion of private or public symbol accessibility.
Pointers
--------
- There is no specific pointer datatype.
However, variables of the ``uword`` datatype can be used as a pointer to one of the possible 65536 memory locations,
so the value it points to is always a single byte. This is similar to ``uint8_t*`` from C.
You have to deal with the uword manually if the object it points to is something different.
- Note that there is the ``peekw`` builtin function that *does* allow you to directy obtain the *word* value at the given memory location.
So if you use this, you can use uword pointers as pointers to word values without much hassle.
- "dereferencing" a uword pointer is done via array indexing (where index value can be 0-65535!) or via the memory read operator ``@(ptr)``, or ``peek/peekw(ptr)``.
- Pointers don't have to be a variable, you can immediately access the value of a given memory location using ``@($d020)`` for instance.
Reading is done by assigning it to a variable, writing is done by just assigning the new value to it.
Foreign function interface (external/ROM calls)
-----------------------------------------------
- You can use the ``romsub`` keyword to define the call signature of foreign functions (usually ROM routines, hence the name) in a natural way.
Calling those generates code that is as efficient or even more efficient as calling regular subroutines.
No additional stubs are needed. (unless there is bank switching going on, but this *may* be improved in a future language version)
Optimizations
-------------
- Prog8 contains many compiler optimizations to generate efficient code, but also lacks many optimizations that modern compilers do have.
While empirical evidence shows that Prog8 generates more efficent code than some C compilers that also target the same 8 bit systems,
the optimizations it makes on your code aren't super sophisticated.
- For time critical code, it may be worth it to inspect the generated assembly code to see if you can write things differently
to help the compiler generate more efficient code (or even replace it with hand written inline assembly altogether).
For example, if you repeat an expression multiple times it will be evaluated every time, so maybe you should store it
in a variable instead and reuse that variable::
if board[i+1]==col or board[i+1]-j==col-row or board[i+1]+j==col+row {
...do something...
}
; more efficiently written as:
ubyte boardvalue = board[i+1]
if boardvalue==col or boardvalue-j==col-row or boardvalue+j==col+row {
...do something...
}
+16 -15
View File
@@ -8,7 +8,7 @@ First, getting a working compiler
---------------------------------
Before you can compile Prog8 programs, you'll have to download or build the compiler itself.
First make sure you have installed the :ref:`requirements`.
Then make sure you have installed the :ref:`requirements`.
Then you can choose a few ways to get a compiler:
**Download an official release version from Github:**
@@ -82,26 +82,27 @@ For normal use, the ``installDist`` task should suffice and after succesful comp
.. image:: _static/antlrparser.png
:alt: Generating the Antlr4 parser files
.. _requirements:
What is a Prog8 "Program" anyway?
---------------------------------
Required additional tools
-------------------------
A "complete runnable program" is a compiled, assembled, and linked together single unit.
It contains all of the program's code and data and has a certain file format that
allows it to be loaded directly on the target system. Prog8 currently has no built-in
support for programs that exceed 64 Kb of memory, nor for multi-part loaders.
`64tass <https://sourceforge.net/projects/tass64/>`_ - cross assembler. Install this program somewhere on your shell's search path.
It's easy to compile yourself, but a recent precompiled .exe (only for Windows) can be obtained from
`the files section <https://sourceforge.net/projects/tass64/files/binaries/>`_ in the official project on sourceforge.
*You need at least version 1.58.0 of this assembler.*
If you are on Linux, there's probably a "64tass" package in the repositories, but check if it is a recent enough version.
A **Java runtime (jre or jdk), version 11 or newer** is required to run the prog8 compiler itself.
If you're scared of Oracle's licensing terms, get one of the versions of another vendor. Even Microsoft provides their own version.
Other OpenJDK builds can be found at `Adoptium <https://adoptium.net/temurin/releases/?version=11>`_ .
For MacOS you can also use the Homebrew system to install a recent version of OpenJDK.
For the Commodore 64, most programs will have a tiny BASIC launcher that does a SYS into the generated machine code.
This way the user can load it as any other program and simply RUN it to start. (This is a regular ".prg" program).
Prog8 can create those, but it is also possible to output plain binary programs
that can be loaded into memory anywhere.
Running the compiler
--------------------
Make sure you have installed the :ref:`requirements`.
You run the Prog8 compiler on a main source code module file.
Other modules that this code needs will be loaded and processed via imports from within that file.
The compiler will link everything together into one output program at the end.
@@ -113,7 +114,7 @@ For normal use the compiler can be invoked with the command:
(Use the appropriate name and version of the jar file downloaded from one of the Git releases.
Other ways to invoke the compiler are also available: see the introduction page about how
to build and run the compiler yourself. The -target option is required, in this case we
to build and run the compiler yourself. The ``-target`` option is always required, in this case we
tell it to compile a program for the Commander X16)
@@ -188,7 +189,7 @@ One or more .p8 module files
Generate an assembler listing file as well.
``-check``
Quickly check the program for errors. No output will be produced.
Quickly check the program for errors. No actual compilation will be performed.
``-breakinstr <instruction>``
Also output the specified CPU instruction for a ``%breakpoint``, as well as the entry in the vice monitor list file.
+15 -30
View File
@@ -28,6 +28,10 @@ You can compile programs for various machines:
* Commodore PET (limited support)
* Atari 800 XL (limited support)
Some language features are mentioned below, and you can also read :ref:`comparingprog8` if you
want to quickly read about how Prog8 compares to well-known other languages.
Open source Software License
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Full source code is on github: https://github.com/irmen/prog8.git
@@ -84,30 +88,28 @@ Features
- provides a convenient and fast edit/compile/run cycle by being able to directly launch
the compiled program in an emulator and provide debugging information to this emulator.
- the language looks like a mix of Python and C so should be quite easy to learn
- Modular programming, scoping via modules, code blocks, and subroutines. No need for forward declarations.
- Provide high level programming constructs but at the same time stay close to the metal;
- Modular programming, scoping via module source files, code blocks, and subroutines. No need for forward declarations.
- Provides high level programming constructs but at the same time stay close to the metal;
still able to directly use memory addresses and ROM subroutines,
and inline assembly to have full control when every register, cycle or byte matters
- Subroutines with parameters and return values of various types
- Complex nested expressions are possible
- Variables are all allocated statically, no memory allocator overhead
- Variables are all allocated statically, no memory allocation overhead
- Conditional branches for status flags that map 1:1 to processor branch instructions for optimal efficiency
- ``when`` statement to avoid if-else chains
- ``in`` expression for concise and efficient multi-value/containment test
- Several specialized built-in functions, such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
- Variable data types include signed and unsigned bytes and words, arrays, strings.
- Various powerful built-in libraries to do I/O, number conversions, graphics and more
- Floating point math is supported on select compiler targets.
- Floating point math is supported on certain compiler targets.
- Easy and highly efficient integration with external subroutines and ROM routines on the target systems.
- Strings can contain escaped characters but also many symbols directly if they have a PETSCII equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \\, {, } and | are also accepted and converted to the closest PETSCII equivalents.
- Encode strings and characters into petscii or screencodes or even other encodings, as desired (C64/Cx16)
- Identifiers can contain Unicode Letters, so ``knäckebröd``, ``приблизительно``, ``見せしめ`` and ``π`` are all valid identifiers.
- Advanced code optimizations to make the resulting program smaller and faster
- Programs can be restarted after exiting (i.e. run them multiple times without having to reload everything), due to automatic variable (re)initializations.
- Supports the sixteen 'virtual' 16-bit registers R0 to R15 as defined on the Commander X16. These are also available on the other compilation targets!
- Supports the sixteen 'virtual' 16-bit registers R0 to R15 as defined on the Commander X16. You can look at them as general purpose global variables. These are also available on the other compilation targets!
- On the Commander X16: Support for low level system features such as Vera Fx, which includes 16x16 bits multiplication in hardware and fast memory copy and fill.
- Many library routines are available across compiler targets. This means that as long as you only use standard Kernal
and core prog8 library routines, it is sometimes possible to compile the *exact same program* for different machines (just change the compilation target flag).
and core prog8 library routines, it is sometimes possible to compile the *exact same program* for different machines by just changing the compilation target flag.
Code example
@@ -184,31 +186,14 @@ when the exact same program is compiled for the Commander X16 target, and run on
:alt: result when run on CX16 emulator
Getting the compiler
Getting the software
--------------------
Usually you just download a fat jar of an official released version, but you can also build
it yourself from source.
Usually you just download a fat jar of an official released compiler version, but you can also build it yourself from source.
Detailed instructions on how to obtain a version of the compiler are in :ref:`building_compiler`.
You can also read there what extra tools you need to get going.
.. _requirements:
Required additional tools
-------------------------
`64tass <https://sourceforge.net/projects/tass64/>`_ - cross assembler. Install this program somewhere on your shell's search path.
It's easy to compile yourself, but a recent precompiled .exe (only for Windows) can be obtained from
`the files section <https://sourceforge.net/projects/tass64/files/binaries/>`_ in the official project on sourceforge.
*You need at least version 1.58.0 of this assembler.*
If you are on Linux, there's probably a "64tass" package in the repositories, but check if it is a recent enough version.
A **Java runtime (jre or jdk), version 11 or newer** is required to run the prog8 compiler itself.
If you're scared of Oracle's licensing terms, get one of the versions of another vendor. Even Microsoft provides their own version.
Other OpenJDK builds can be found at `Adoptium <https://adoptium.net/temurin/releases/?version=11>`_ .
For MacOS you can also use the Homebrew system to install a recent version of OpenJDK.
Finally: an **emulator** (or a real machine of course) to test and run your programs on.
You may look for an **emulator** (or a real machine of course) to test and run your programs on.
For the PET, C64 and C128 targets, the compiler assumes the presence of the `VICE emulator <http://vice-emu.sourceforge.net/>`_.
If you're targeting the Commander X16 instead,
download a recent emulator version for the CommanderX16, such as `x16emu <https://cx16forum.com/forum/viewforum.php?f=30>`_
@@ -221,11 +206,11 @@ If multiple options are listed above, you can select which one you want to launc
Look in the `syntax-files <https://github.com/irmen/prog8/tree/master/syntax-files>`_ directory in the github repository to find them.
.. toctree::
:maxdepth: 2
:caption: Contents of this manual:
comparing.rst
compiling.rst
programming.rst
syntaxreference.rst
+36 -10
View File
@@ -186,6 +186,7 @@ memory (name, size, alignment)
call (address) -> uword
Calls a subroutine given by its memory address. You cannot pass arguments directly,
although it is ofcourse possible to do this via the global ``cx16.r0...`` registers for example.
It is *not* possible to use cpu registers to pass arguments, because these are clobbered while performing the call!
It is assumed the subroutine returns a word value (in AY), if it does not, just add void to the call to ignore the result value.
This function effectively creates an "indirect JSR" if you use it on a ``uword`` pointer variable.
But because it doesn't handle bank switching etcetera by itself,
@@ -199,6 +200,10 @@ callfar (bank, address, argumentword) -> uword ; NOTE: specific to cx16 targ
NOTE: this routine is very inefficient, so don't use it to call often. Set the bank yourself
or even write a custom tailored trampoline routine if you need to. Or use ``call`` if you can.
callfar2 (bank, address, argA, argX, argY, argCarry) -> uword ; NOTE: specific to cx16 target for now
Identical to ``callfar``, except here you can give arguments not only for AY,
but for each of the A, X and Y registers (each an ubyte) and the Carry status bit as well (a boolean).
syscall (callnr), syscall1 (callnr, arg), syscall2 (callnr, arg1, arg2), syscall3 (callnr, arg1, arg2, arg3)
Functions for doing a system call on targets that support this. Currently no actual target
uses this though except, possibly, the experimental code generation target!
@@ -583,9 +588,7 @@ floats
.. note::
Floating point support is only available on c64, cx16 and virtual targets for now.
Provides definitions for the ROM/Kernal subroutines and utility routines dealing with floating
point variables. This includes ``print_f``, the routine used to print floating point numbers.
Provides definitions for the ROM/Kernal subroutines and utility routines dealing with floating point variables.
``π`` and ``PI``
float const for the number Pi, 3.141592653589793...
@@ -789,6 +792,10 @@ but perhaps the provided ones can be of service too.
It does not work for the verafx multiplication routines on the Commander X16!
These have a different way to obtain the upper 16 bits of the result: just read cx16.r0.
**NOTE:** the result is only valid if the multiplication was done with uword arguments (or two positive word arguments).
As soon as a single negative word value (or both) was used in the multiplication, these upper 16 bits are not valid!
Suggestion (if you are on the Commander X16): use ``verafx.muls()`` to get a hardware accelerated 32 bit signed multiplication.
``crc16 (uword data, uword length) -> uword``
Returns a CRC-16 (XMODEM) checksum over the given data buffer.
Note: on the Commander X16, there is a CRC-16 routine in the kernal: cx16.memory_crc().
@@ -947,6 +954,18 @@ Read the `psg source code <https://github.com/irmen/prog8/tree/master/compiler/r
to see what's in there.
audio (cx16 only)
------------------
Available for the Cx16 target.
Contains stub routines for all of the kernal audio routines available in rom bank 10.
The stubs use JSRFAR calls so you don't have to bother with selecting the correct rom bank in your own program code.
See the cx16/audioroutines.p8 example on how to use them.
Read the `audio source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/audio.p8>`_
to see what's in there.
sprites (cx16 only)
--------------------
Available for the Cx16 target. Simple routines to manipulate sprites.
@@ -968,15 +987,22 @@ the emulators already support it).
``available``
Returns true if Vera FX is available, false if not (that would be an older Vera chip)
``mult`` , ``muls``
The hardware 16*16 multiplier is exposed via ``mult`` and ``muls`` routines (unsigned and signed respectively).
They are about 4 to 5 times faster as the default 6502 cpu routine for word multiplication.
But they depend on some Vera manipulation and 4 bytes in vram just below the PSG registers for storage.
``muls``
The VeraFX signed word 16*16 to 32 multiplier is accessible via the ``muls`` routine.
It is about 4 to 5 times faster than the default 6502 cpu routine for word multiplication.
But it depends on some Vera manipulation and 4 bytes in vram just below the PSG registers for storage.
Note: there is a block level %option "verafxmuls" that automatically replaces all word multiplications in that block
by calls to verafx.muls/mult, but be careful with it because it may interfere with other Vera operations or IRQs.
by calls to verafx, but be careful with it because it may interfere with other Vera operations or IRQs.
The full 32 bits result value is returned in two result values: lower word, upper word.
Note: the lower 16 bits of the 32 bits result is returned as the normal subroutine's returnvalue,
but the upper 16 bits is returned in cx16.r0 so you can still access those separately.
``mult16``
VeraFX hardware multiplication of two unsigned words.
NOTE: it only returns the lower 16 bits of the full 32 bits result, because the upper 16 bits are not valid for unsigned word multiplications here
(the signed word multiplier ``muls`` does return the full 32 bits result).
It is about 4 to 5 times faster than the default 6502 cpu routine for word multiplication.
But it depends on some Vera manipulation and 4 bytes in vram just below the PSG registers for storage.
Note: there is a block level %option "verafxmuls" that automatically replaces all word multiplications in that block
by calls to verafx, but be careful with it because it may interfere with other Vera operations or IRQs.
``clear``
Very quickly clear a piece of vram to a given byte value (it writes 4 bytes at a time).
+8 -15
View File
@@ -1,8 +1,6 @@
.. _programstructure:
==========================
What makes a Prog8 program
==========================
====================
Programming in Prog8
====================
This chapter describes a high level overview of the elements that make up a program.
Details about the syntax can be found in the :ref:`syntaxreference` chapter.
@@ -288,8 +286,7 @@ Arrays
^^^^^^
Array types are also supported. They can be formed from a list of booleans, bytes, words, floats, or addresses of other variables
(such as explicit address-of expressions, strings, or other array variables) - values in an array literal
always have to be constants. Putting variables inside an array has to be done on a value-by-value basis.
Here are some examples of arrays::
always have to be constants. Here are some examples of arrays::
byte[10] array ; array of 10 bytes, initially set to 0
byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value
@@ -302,6 +299,7 @@ Here are some examples of arrays::
value = array[3] ; the fourth value in the array (index is 0-based)
char = string[4] ; the fifth character (=byte) in the string
char = string[-2] ; the second-to-last character in the string (Python-style indexing from the end)
flags = [false, true] ; reset all flags in the array
.. note::
Right now, the array should be small enough to be indexable by a single byte index.
@@ -314,10 +312,9 @@ Note that the various keywords for the data type and variable type (``byte``, ``
can't be used as *identifiers* elsewhere. You can't make a variable, block or subroutine with the name ``byte``
for instance.
It's possible to assign a new array to another array, this will overwrite all elements in the original
array with those in the value array. The number and types of elements have to match.
For large arrays this is a slow operation because every element is copied over. It should probably be avoided.
It is possible to assign an array (variable or array literal) to another array; this will overwrite all elements in the target
array with those in the source array. The number of elements in the arrays and the data types have to match.
For large arrays this is a slow operation because all values are copied over.
Using the ``in`` operator you can easily check if a value is present in an array,
example: ``if choice in [1,2,3,4] {....}``
@@ -652,10 +649,6 @@ Assignment statements assign a single value to a target variable or memory locat
Augmented assignments (such as ``aa += xx``) are also available, but these are just shorthands
for normal assignments (``aa = aa + xx``).
Only variables of type byte, word and float can be assigned a new value.
It's not possible to set a new value to string or array variables etc, because they get allocated
a fixed amount of memory which will not change. (You *can* change the value of elements in a string or array though).
It is possible to "chain" assignments: ``x = y = z = 42``, this is just a shorthand
for the three individual assignments with the same value 42.
+8
View File
@@ -152,10 +152,16 @@ The IRQ handler routine must return a boolean value (0 or 1) in the A register:
**CommanderX16 specific notes**
.. sidebar::
X16 specific routines
For the X16 there are also some specialized IRQ handling routines, see :ref:`x16-specific-irq` below.
Note that for the CommanderX16 the set_rasterirq() will disable VSYNC irqs and never call the system IRQ handler regardless
of the return value of the user handler routine. This also means the default sys.wait() routine won't work anymore,
when using this handler.
These two helper routines are not particularly suited to handle multiple IRQ sources on the Commander X16.
It's possible but it requires correct fiddling with IRQ enable bits, acknowledging the IRQs, and properly calling
or not calling the system IRQ handler routine. See the section below for perhaps a better and easier solution that
@@ -192,6 +198,8 @@ will corrupt any Vera operations that were going on in the main program. The rou
and restored at the end of the handler, further increasing its execution time...
.. _x16-specific-irq:
Commander X16 specific IRQ handling
===================================
+6 -2
View File
@@ -9,12 +9,16 @@ Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEva
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- remove support for array variable initialization with a single value, just require explicitly creating the value array [42] * 10 (which is what the compiler now does for you implicitly)
- should the array-to-array assignment support be removed and instead require an explicit copy function call? What prog8_lib_arraycopy() now does. Or just use memcopy.
- should we add a cleararray builtin function that can efficiently set every element in the array to the given value
- improve detection that a variable is not read before being written so that initializing it to zero can be omitted (only happens now if a vardecl is immediately followed by a for loop for instance)
- Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
- Can we support signed % (remainder) somehow?
- Don't add "random" rts to %asm blocks but instead give a warning about it? (but this breaks existing behavior that others already depend on... command line switch? block directive?)
- IR: implement missing operators in AssignmentGen (array shifts etc)
- IR: CMPI+BSTEQ --> new BEQ reg,value,label instruction (like BGT etc)
- instead of copy-pasting inline asmsubs, make them into a 64tass macro and use that instead.
that will allow them to be reused from custom user written assembly code as well.
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays.
+123 -53
View File
@@ -1,38 +1,33 @@
%import syslib
%import textio
%import math
%import test_stack
%zeropage basicsafe
; note: The flickering in the scrolling is caused by the CPU requiring
; too long to scroll the characters + the colors in course scroll.
; This takes nearly a full frame to accomplish, and causes tearing.
; It's very difficult to remove this flicker: it requires double buffering
; and splitting the coarse character scrolling on multiple phases...
; C64 version of a balloon sprites flying over a mountain landscape.
; There is also a X16 version of this in the examples.
main {
bool perform_scroll = false
bool do_char_scroll = false
sub start() {
uword moon_x = 310
c64.set_sprite_ptr(0, $0f00) ; alternatively, set directly: c64.SPRPTR[0] = $0f00 / 64
c64.SPENA = 1
c64.set_sprite_ptr(1, $0f00+64) ; alternatively, set directly: c64.SPRPTR[0] = $0f00 / 64
c64.SPENA = %00000011
c64.SP0COL = 14
c64.SP1COL = 7
c64.SPXY[0] = 80
c64.SPXY[1] = 100
set_moon_pos(moon_x)
c64.SCROLX &= %11110111 ; 38 column mode
sys.set_rasterirq(&irq.irqhandler, 200) ; enable animation via raster interrupt
sys.set_rasterirq(&irq.irqhandler, 250) ; enable animation via raster interrupt
ubyte target_height = 10
ubyte active_height = 24
ubyte active_height = 25
bool upwards = true
repeat {
;txt.plot(0,0)
;test_stack.test()
ubyte mountain = 223 ; slope upwards
if active_height < target_height {
active_height++
@@ -42,66 +37,129 @@ main {
active_height--
upwards = false
} else {
target_height = 8 + math.rnd() % 16
if upwards
; determine new height for next mountain
ubyte old_height = target_height
if upwards {
mountain = 233
else
while target_height >= old_height
target_height = 9 + math.rnd() % 15
} else {
mountain = 223
while target_height <= old_height
target_height = 9 + math.rnd() % 15
}
}
while not perform_scroll {
while not do_char_scroll {
; let the raster irq do its timing job
}
perform_scroll = false
txt.scroll_left(true)
do_char_scroll = false
scroll_characters_left()
; float the balloon
if math.rnd() & %10000 !=0
; float the balloon and the moon sprites
if math.rnd() & 1 !=0
c64.SPXY[1] ++
else
c64.SPXY[1] --
moon_x--
if msb(moon_x)==255
moon_x = 340
set_moon_pos(moon_x)
; draw new mountain etc.
const ubyte RIGHT_COLUMN = 39
ubyte yy
for yy in 0 to active_height-1 {
txt.setcc(39, yy, 32, 2) ; clear top of screen
txt.setcc(RIGHT_COLUMN, yy, 32, 2) ; clear top of screen
}
txt.setcc(39, active_height, mountain, 8) ; mountain edge
txt.setcc(RIGHT_COLUMN, active_height, mountain, 8) ; mountain edge
for yy in active_height+1 to 24 {
txt.setcc(39, yy, 160, 8) ; draw mountain
txt.setcc(RIGHT_COLUMN, yy, 160, 8) ; draw filled mountain
}
yy = math.rnd()
if yy > 100 {
ubyte clutter = math.rnd()
if clutter > 100 {
; draw a star
txt.setcc(39, yy % (active_height-1), '.', math.rnd())
txt.setcc(RIGHT_COLUMN, clutter % (active_height-1), sc:'.', math.rnd())
}
if yy > 200 {
if clutter > 200 {
; draw a tree
ubyte tree = 30
ubyte tree = sc:'↑'
ubyte treecolor = 5
if yy & %01000000 != 0
tree = 88
else if yy & %00100000 != 0
tree = 65
if clutter & %00010000 != 0
tree = sc:'♣'
else if clutter & %00100000 != 0
tree = sc:'♠'
if math.rnd() > 130
treecolor = 13
txt.setcc(39, active_height, tree, treecolor)
txt.setcc(RIGHT_COLUMN, active_height, tree, treecolor)
}
if yy > 235 {
if clutter > 235 {
; draw a camel
txt.setcc(39, active_height, 94, 9)
txt.setcc(RIGHT_COLUMN, active_height, sc:'π', 9)
}
}
}
sub set_moon_pos(uword x) {
c64.SPXY[2] = lsb(x)
c64.SPXY[3] = 55
if msb(x)!=0
c64.MSIGX |= %00000010
else
c64.MSIGX &= %11111101
}
sub scroll_characters_left () {
; Scroll the bottom half (approx.) of the character screen 1 character to the left
; contents of the rightmost column are unchanged, you should clear/refill this yourself
; Without clever split-screen tricks, the C64 is not fast enough to scroll the whole
; screen smootly without tearing. So for simplicity it's constrained to less rows
; such that what is scrolled, *does* scrolls smoothly.
; For maximum performance the scrolling is done in unrolled assembly code.
%asm {{
ldx #0
ldy #38
-
.for row=10, row<=24, row+=1
lda cbm.Screen + 40*row + 1,x
sta cbm.Screen + 40*row + 0,x
lda cbm.Colors + 40*row + 1,x
sta cbm.Colors + 40*row + 0,x
.next
inx
dey
bpl -
rts
}}
}
}
irq {
; does the smooth scrolling immediately after the visible screen area,
; so there is no screen tearing. The main loop does the "big" character
; scrolling when the soft-scroll runs out after 8 pixels
ubyte smoothx=0
sub irqhandler() -> bool {
smoothx = (smoothx-1) & 7
main.do_char_scroll = smoothx==7
c64.SCROLX = (c64.SCROLX & %11111000) | smoothx
return false
}
}
spritedata $0f00 {
; this memory block contains the sprite data
; it must start on an address aligned to 64 bytes.
; this memory block contains the sprite data. it must start on an address aligned to 64 bytes.
; for simplicity, it's currently statically located at $0f00 (not far in memory after the program code),
; but there are ways to do this more dynamically.
%option force_output ; make sure the data in this block appears in the resulting program
ubyte[] balloonsprite = [ %00000000,%01111111,%00000000,
@@ -124,17 +182,29 @@ spritedata $0f00 {
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000 ]
%00000000,%00011100,%00000000,
0]
ubyte[] moonsprite = [ %00000000,%00000110,%00000000,
%00000000,%00011100,%00000000,
%00000000,%01111000,%00000000,
%00000000,%11111000,%00000000,
%00000001,%11110000,%00000000,
%00000011,%11110000,%00000000,
%00000011,%11110000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000011,%11110000,%00000000,
%00000011,%11110000,%00000000,
%00000001,%11110000,%00000000,
%00000000,%11111000,%00000000,
%00000000,%01111000,%00000000,
%00000000,%00011100,%00000000,
%00000000,%00000110,%00000000,
0]
}
irq {
ubyte smoothx=0
sub irqhandler() -> bool {
smoothx = (smoothx-1) & 7
main.perform_scroll = smoothx==7
c64.SCROLX = (c64.SCROLX & %11111000) | smoothx
return false
}
}
-3
View File
@@ -1,7 +1,6 @@
%import syslib
%import textio
%import math
%import test_stack
spritedata $2000 {
@@ -97,8 +96,6 @@ main {
txt.print(" jiffies/fr = ")
txt.print_ub(60/cbm.TIME_LO)
txt.print(" fps")
; test_stack.test()
}
}
-3
View File
@@ -1,5 +1,4 @@
%import syslib
%import test_stack
%import textio
%import math
@@ -35,8 +34,6 @@ main {
txt.print_ub(60/cbm.TIME_LO)
txt.print(" fps")
cbm.TIME_LO=0
; test_stack.test()
}
}
+12 -9
View File
@@ -92,15 +92,18 @@ main {
for y in 0 to 24 {
ubyte @zp @shared yvalue = ybuf[y]
for x in 0 to 39 {
; @(screen+x) = xbuf[x] + yvalue
; max optimized asm is this: (achieving ~21 fps on the C64):
%asm {{
lda p8v_yvalue
ldy p8v_x
clc
adc p8v_xbuf,y
sta (p8v_screen),y
}}
@(screen+x) = xbuf[x] + yvalue
; optimized asm for the line above is this:
; (achieving ~23 fps on the C64, about 1 or 2 fps more than with the pure prog8 code):
; %asm {{
; lda p8v_yvalue
; ldy p8v_x
; clc
; adc p8v_xbuf,y
; sta (p8v_screen),y
; }}
}
screen += 40
}
-4
View File
@@ -11,7 +11,6 @@
%import syslib
%import textio
%import math
%import test_stack
main {
@@ -68,9 +67,6 @@ waitkey:
}
drawScore()
; txt.plot(0,0)
; test_stack.test()
}
ubyte key
+3 -2
View File
@@ -57,8 +57,9 @@ irq {
uword @zp x = math.sin8u(angle1-spri*16) as uword + 50
ubyte @zp y = math.sin8u(angle2-spri*16) / 2 + 70
c64.SPXYW[spri] = mkword(y, lsb(x))
c64.MSIGX <<= 1
if msb(x)!=0 c64.MSIGX++
if msb(x)!=0
sys.set_carry()
rol(c64.MSIGX)
}
c64.EXTCOL-=8
return true
-3
View File
@@ -1,6 +1,5 @@
%import floats
%import textio
%import test_stack
%zeropage basicsafe
; Note: this program can be compiled for multiple target systems.
@@ -37,8 +36,6 @@ main {
txt.print(" jiffies/fr = ")
txt.print_ub(60/jiffies)
txt.print(" fps")
;test_stack.test()
}
}
-123
View File
@@ -1,123 +0,0 @@
%import textio
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
txt.print("\n\nsimple demonstration of the audio kernal routines.\n")
txt.print("fm demo...\n")
fm_demo()
sys.wait(30)
txt.print("psg demo...\n")
psg_demo()
sys.wait(30)
txt.print("done!\n")
}
sub psg_demo() {
/*
10 PSGINIT
20 PSGCHORD 15,"O3G>CE" : REM STARTS PLAYING A CHORD ON VOICES 15, 0, AND 1
30 PSGPLAY 14,">C<DGB>CDE" : REM PLAYS A SERIES OF NOTES ON VOICE 14
40 PSGCHORD 15,"RRR" : REM RELEASES CHORD ON VOICES 15, 0, AND 1
50 PSGPLAY 14,"O4CAG>C<A" : REM PLAYS A SERIES OF NOTES ON VOICE 14
60 PSGCHORD 0,"O3A>CF" : REM STARTS PLAYING A CHORD ON VOICES 0, 1, AND 2
70 PSGPLAY 14,"L16FGAB->CDEF4" : REM PLAYS A SERIES OF NOTES ON VOICE
80 PSGCHORD 0,"RRR" : REM RELEASES CHORD ON VOICES 0, 1, AND 2
*/
cx16.rombank(10)
cx16.psg_init()
cx16.bas_playstringvoice(15)
cx16.bas_psgchordstring(6, "o3g>ce")
cx16.bas_playstringvoice(14)
cx16.bas_psgplaystring(10, ">c<dgb>cde")
cx16.bas_playstringvoice(15)
cx16.bas_psgchordstring(3, "rrr")
cx16.bas_playstringvoice(14)
cx16.bas_psgplaystring(9, "o4cag>c<a")
cx16.bas_playstringvoice(0)
cx16.bas_psgchordstring(6, "o3a>cf")
cx16.bas_playstringvoice(14)
cx16.bas_psgplaystring(14, "l16fgab->cdef4")
cx16.bas_playstringvoice(0)
cx16.bas_psgchordstring(3, "rrr")
cx16.rombank(0)
}
sub fm_demo() {
/*
10 FMINIT
20 FMVIB 195,10
30 FMINST 1,16:FMINST 2,16:FMINST 3,16 : REM ORGAN
40 FMVOL 1,50:FMVOL 2,50:FMVOL 3,50 : REM MAKE ORGAN QUIETER
50 FMINST 0,11 : REM VIBRAPHONE
60 FMCHORD 1,"O3CG>E T90" : REM START SOME ORGAN CHORDS (CHANNELS 1,2,3)
70 FMPLAY 0,"O4G4.A8G4E2." : REM PLAY MELODY (CHANNEL 0)
80 FMPLAY 0,"O4G4.A8G4E2."
90 FMCHORD 1,"O2G>DB" : REM SWITCH ORGAN CHORDS (CHANNELS 1,2,3)
100 FMPLAY 0,"O5D2D4<B2" : REM PLAY MORE MELODY
110 FMCHORD 1,"O2F" : REM SWITCH ONE OF THE ORGAN CHORD NOTES
120 FMPLAY 0,"R4" : REM PAUSE FOR THE LENGTH OF ONE QUARTER NOTE
130 FMCHORD 1,"O3CEG" : REM SWITCH ALL THREE CHORD NOTES
140 FMPLAY 0,"O5C2C4<G2." : REM PLAY THE REST OF THE MELODY
150 FMCHORD 1,"RRR" : REM RELEASE THE CHANNELS THAT ARE PLAYING THE CHORD
*/
cx16.rombank(10)
void cx16.ym_init()
void cx16.bas_fmvib(195, 10)
cx16.ym_loadpatch(1,16,true)
cx16.ym_loadpatch(2,16,true)
cx16.ym_loadpatch(3,16,true)
void cx16.ym_setatten(1,64-50)
void cx16.ym_setatten(2,64-50)
void cx16.ym_setatten(3,64-50)
cx16.ym_loadpatch(0,11,true)
cx16.bas_playstringvoice(1)
cx16.bas_fmchordstring(11, "o3cg>e t130")
cx16.bas_playstringvoice(0)
cx16.bas_fmplaystring(12, "o4g4.a8g4e2.")
cx16.bas_playstringvoice(0)
cx16.bas_fmplaystring(12, "o4g4.a8g4e2.")
cx16.bas_playstringvoice(1)
cx16.bas_fmchordstring(6, "o2g>db")
cx16.bas_playstringvoice(0)
cx16.bas_fmplaystring(9, "o5d2d4<b2")
cx16.bas_playstringvoice(1)
cx16.bas_fmchordstring(3, "o2f")
cx16.bas_playstringvoice(0)
cx16.bas_fmplaystring(2, "r4")
cx16.bas_playstringvoice(1)
cx16.bas_fmchordstring(5, "o3ceg")
cx16.bas_playstringvoice(0)
cx16.bas_fmplaystring(10, "o5c2c4<g2.")
cx16.bas_playstringvoice(1)
cx16.bas_fmchordstring(3, "rrr")
cx16.rombank(0)
}
}
+122
View File
@@ -0,0 +1,122 @@
%import textio
%import audio
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
txt.print("\n\nsimple demonstration of the audio kernal routines.\n")
txt.print("fm demo...\n")
fm_demo()
sys.wait(30)
txt.print("psg demo...\n")
psg_demo()
sys.wait(30)
txt.print("done!\n")
}
sub psg_demo() {
/*
10 PSGINIT
20 PSGCHORD 15,"O3G>CE" : REM STARTS PLAYING A CHORD ON VOICES 15, 0, AND 1
30 PSGPLAY 14,">C<DGB>CDE" : REM PLAYS A SERIES OF NOTES ON VOICE 14
40 PSGCHORD 15,"RRR" : REM RELEASES CHORD ON VOICES 15, 0, AND 1
50 PSGPLAY 14,"O4CAG>C<A" : REM PLAYS A SERIES OF NOTES ON VOICE 14
60 PSGCHORD 0,"O3A>CF" : REM STARTS PLAYING A CHORD ON VOICES 0, 1, AND 2
70 PSGPLAY 14,"L16FGAB->CDEF4" : REM PLAYS A SERIES OF NOTES ON VOICE
80 PSGCHORD 0,"RRR" : REM RELEASES CHORD ON VOICES 0, 1, AND 2
*/
; Note: the audio module contains stubs for every kernal audio call,
; they use JSRFAR to automatically switch to the correct ROM bank (and back).
; So we don't have to switch rom banks ourselves to access the audio routines in bank 10!
audio.psg_init()
audio.bas_playstringvoice(15)
audio.bas_psgchordstring(6, "o3g>ce")
audio.bas_playstringvoice(14)
audio.bas_psgplaystring(10, ">c<dgb>cde")
audio.bas_playstringvoice(15)
audio.bas_psgchordstring(3, "rrr")
audio.bas_playstringvoice(14)
audio.bas_psgplaystring(9, "o4cag>c<a")
audio.bas_playstringvoice(0)
audio.bas_psgchordstring(6, "o3a>cf")
audio.bas_playstringvoice(14)
audio.bas_psgplaystring(14, "l16fgab->cdef4")
audio.bas_playstringvoice(0)
audio.bas_psgchordstring(3, "rrr")
}
sub fm_demo() {
/*
10 FMINIT
20 FMVIB 195,10
30 FMINST 1,16:FMINST 2,16:FMINST 3,16 : REM ORGAN
40 FMVOL 1,50:FMVOL 2,50:FMVOL 3,50 : REM MAKE ORGAN QUIETER
50 FMINST 0,11 : REM VIBRAPHONE
60 FMCHORD 1,"O3CG>E T90" : REM START SOME ORGAN CHORDS (CHANNELS 1,2,3)
70 FMPLAY 0,"O4G4.A8G4E2." : REM PLAY MELODY (CHANNEL 0)
80 FMPLAY 0,"O4G4.A8G4E2."
90 FMCHORD 1,"O2G>DB" : REM SWITCH ORGAN CHORDS (CHANNELS 1,2,3)
100 FMPLAY 0,"O5D2D4<B2" : REM PLAY MORE MELODY
110 FMCHORD 1,"O2F" : REM SWITCH ONE OF THE ORGAN CHORD NOTES
120 FMPLAY 0,"R4" : REM PAUSE FOR THE LENGTH OF ONE QUARTER NOTE
130 FMCHORD 1,"O3CEG" : REM SWITCH ALL THREE CHORD NOTES
140 FMPLAY 0,"O5C2C4<G2." : REM PLAY THE REST OF THE MELODY
150 FMCHORD 1,"RRR" : REM RELEASE THE CHANNELS THAT ARE PLAYING THE CHORD
*/
void audio.ym_init()
void audio.bas_fmvib(195, 10)
audio.ym_loadpatch(1,16,true)
audio.ym_loadpatch(2,16,true)
audio.ym_loadpatch(3,16,true)
void audio.ym_setatten(1,64-50)
void audio.ym_setatten(2,64-50)
void audio.ym_setatten(3,64-50)
audio.ym_loadpatch(0,11,true)
audio.bas_playstringvoice(1)
audio.bas_fmchordstring(11, "o3cg>e t130")
audio.bas_playstringvoice(0)
audio.bas_fmplaystring(12, "o4g4.a8g4e2.")
audio.bas_playstringvoice(0)
audio.bas_fmplaystring(12, "o4g4.a8g4e2.")
audio.bas_playstringvoice(1)
audio.bas_fmchordstring(6, "o2g>db")
audio.bas_playstringvoice(0)
audio.bas_fmplaystring(9, "o5d2d4<b2")
audio.bas_playstringvoice(1)
audio.bas_fmchordstring(3, "o2f")
audio.bas_playstringvoice(0)
audio.bas_fmplaystring(2, "r4")
audio.bas_playstringvoice(1)
audio.bas_fmchordstring(5, "o3ceg")
audio.bas_playstringvoice(0)
audio.bas_fmplaystring(10, "o5c2c4<g2.")
audio.bas_playstringvoice(1)
audio.bas_fmchordstring(3, "rrr")
}
}
+252
View File
@@ -0,0 +1,252 @@
%import syslib
%import textio
%import sprites
%import palette
%import math
; X16 version of a balloon sprites flying over a mountain landscape.
; There is also a C64 version of this in the examples.
main {
sub start() {
ubyte target_height = txt.DEFAULT_HEIGHT - 10
ubyte active_height = txt.DEFAULT_HEIGHT
bool upwards = true
ubyte draw_column = txt.DEFAULT_WIDTH
word moon_x = 640
word balloon_y = 120
; clear the screen (including all the tiles outside of the visible area)
cx16.vaddr(txt.VERA_TEXTMATRIX_BANK, txt.VERA_TEXTMATRIX_ADDR, 0, 1)
repeat 128 * txt.DEFAULT_HEIGHT {
cx16.VERA_DATA0 = sc:' '
cx16.VERA_DATA0 = $00
}
; activate balloon and moon sprites
sprites.init(1, 0, $0000, sprites.SIZE_32, sprites.SIZE_64, sprites.COLORS_16, 1)
sprites.init(2, 0, $0400, sprites.SIZE_32, sprites.SIZE_32, sprites.COLORS_16, 2)
spritedata.copy_to_vram()
; Scroll!
; Unlike the C64 version, there is no need to copy the whole text matrix 1 character to the left
; every 8 pixels. The X16 has a much larger soft scroll register and the displayed tiles wrap around.
repeat {
sys.waitvsync()
cx16.VERA_L1_HSCROLL ++
if cx16.VERA_L1_HSCROLL & 7 == 0 {
; set balloon pos
if math.rnd() & 1 != 0
balloon_y++
else
balloon_y--
sprites.pos(1, 100, balloon_y)
; set moon pos
moon_x--
if moon_x < -64
moon_x = 640
sprites.pos(2, moon_x, 20)
; update slope height
ubyte mountain = 223 ; slope upwards
if active_height < target_height {
active_height++
upwards = true
} else if active_height > target_height {
mountain = 233 ; slope downwards
active_height--
upwards = false
} else {
; determine new height for next mountain
ubyte old_height = target_height
if upwards {
mountain = 233
while target_height >= old_height
target_height = 28 + (math.rnd() & 31)
} else {
mountain = 223
while target_height <= old_height
target_height = 28 + (math.rnd() & 31)
}
}
; draw new mountain etc.
draw_column++
ubyte yy
for yy in 0 to active_height-1 {
txt.setcc(draw_column, yy, 32, 2) ; clear top of screen
}
txt.setcc(draw_column, active_height, mountain, 8) ; mountain edge
for yy in active_height+1 to txt.DEFAULT_HEIGHT-1 {
txt.setcc(draw_column, yy, 160, 8) ; draw filled mountain
}
ubyte clutter = math.rnd()
if clutter > 100 {
; draw a star
txt.setcc(draw_column, clutter % (active_height-1), sc:'.', math.rnd())
}
if clutter > 200 {
; draw a tree
ubyte tree = sc:'↑'
ubyte treecolor = 5
if clutter & %00010000 != 0
tree = sc:'♣'
else if clutter & %00100000 != 0
tree = sc:'♠'
if math.rnd() > 130
treecolor = 13
txt.setcc(draw_column, active_height, tree, treecolor)
}
if clutter > 235 {
; draw a camel
txt.setcc(draw_column, active_height, sc:'π', 9)
}
}
}
}
}
spritedata {
sub copy_to_vram() {
cx16.vaddr(0, $0000, 0, 1)
for cx16.r0 in 0 to 32*64/2-1
cx16.VERA_DATA0 = @(&balloonsprite + cx16.r0)
cx16.vaddr(0, $0400, 0, 1)
for cx16.r0 in 0 to 32*32/2-1
cx16.VERA_DATA0 = @(&moonsprite + cx16.r0)
for cx16.r1L in 0 to 15 {
palette.set_color(cx16.r1L + 16, balloon_pallette[cx16.r1L])
palette.set_color(cx16.r1L + 32, moon_pallette[cx16.r1L])
}
}
uword[] balloon_pallette = [
$f0f, $312, $603, $125,
$717, $721, $332, $a22,
$268, $d31, $764, $488,
$d71, $997, $ba7, $eb3
]
uword[] moon_pallette = [
$f0f, $444, $444, $555,
$555, $555, $555, $666,
$777, $777, $888, $888,
$999, $aaa, $bbb, $ccc
]
balloonsprite:
%asm {{
.byte $00, $00, $00, $00, $00, $00, $00, $00, $60, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $99, $92, $55, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $05, $ac, $fc, $cf, $c9, $95, $e3, $25, $11, $40, $00, $00, $00
.byte $00, $00, $08, $3c, $ff, $cf, $ff, $c9, $9c, $c8, $37, $21, $33, $00, $00, $00
.byte $00, $00, $6b, $af, $ec, $ff, $ff, $9c, $9c, $fa, $33, $97, $23, $30, $00, $00
.byte $00, $08, $bd, $ef, $fc, $ff, $fc, $99, $99, $fc, $33, $27, $72, $33, $30, $00
.byte $00, $0b, $be, $ff, $cf, $ef, $fc, $9c, $99, $cf, $23, $32, $77, $13, $30, $00
.byte $00, $6b, $ee, $ff, $9f, $ef, $fc, $c9, $97, $cf, $d3, $32, $29, $73, $31, $00
.byte $00, $f8, $fe, $fc, $ff, $ef, $f9, $9c, $99, $ff, $d8, $31, $27, $72, $33, $00
.byte $3b, $fd, $ee, $fc, $ff, $ef, $f9, $9c, $99, $fe, $d3, $32, $24, $72, $33, $40
.byte $8b, $bd, $fe, $fc, $ff, $ef, $c7, $c7, $97, $ce, $d8, $33, $22, $72, $33, $30
.byte $b8, $bd, $ee, $d7, $db, $b8, $2d, $88, $32, $2b, $83, $33, $33, $33, $33, $10
.byte $18, $b8, $bb, $b8, $be, $bb, $3b, $b8, $38, $bb, $b8, $83, $33, $33, $33, $34
.byte $1b, $8b, $bb, $8b, $eb, $83, $3b, $b8, $33, $bb, $88, $33, $33, $33, $33, $33
.byte $8b, $b8, $8b, $88, $be, $88, $38, $88, $38, $8b, $b8, $33, $33, $33, $33, $33
.byte $8b, $88, $88, $8b, $b8, $83, $38, $88, $38, $8b, $88, $33, $33, $33, $33, $33
.byte $88, $83, $88, $88, $88, $83, $38, $83, $38, $8b, $83, $33, $33, $33, $33, $33
.byte $3b, $b8, $88, $88, $bb, $83, $38, $83, $38, $bb, $83, $33, $33, $33, $33, $33
.byte $6b, $bb, $88, $33, $bb, $b3, $38, $33, $33, $8b, $83, $33, $33, $33, $33, $30
.byte $1b, $b3, $73, $37, $78, $83, $27, $92, $42, $75, $83, $11, $33, $33, $33, $30
.byte $0c, $ff, $79, $97, $9f, $f9, $79, $92, $42, $79, $72, $12, $22, $11, $13, $10
.byte $04, $9c, $c9, $97, $9f, $fc, $79, $97, $44, $c7, $72, $12, $12, $12, $22, $00
.byte $00, $9c, $c9, $99, $59, $c9, $97, $92, $42, $7c, $21, $21, $22, $12, $21, $00
.byte $00, $59, $cc, $99, $59, $9c, $79, $97, $22, $75, $21, $41, $22, $14, $10, $00
.byte $00, $19, $cc, $99, $99, $9c, $97, $94, $22, $97, $21, $12, $11, $22, $10, $00
.byte $00, $01, $cc, $c9, $95, $99, $97, $77, $47, $92, $11, $22, $12, $21, $00, $00
.byte $00, $00, $79, $cc, $97, $7c, $c7, $99, $47, $72, $22, $11, $12, $14, $00, $00
.byte $00, $00, $07, $cc, $99, $7c, $fc, $99, $42, $91, $14, $21, $22, $00, $00, $00
.byte $00, $00, $01, $7c, $c9, $97, $cc, $79, $27, $72, $21, $12, $10, $00, $00, $00
.byte $00, $00, $00, $1a, $c5, $95, $fc, $77, $44, $22, $21, $21, $00, $00, $00, $00
.byte $00, $00, $00, $04, $a7, $5c, $fe, $f7, $9c, $55, $52, $20, $00, $00, $00, $00
.byte $00, $00, $00, $00, $01, $57, $fe, $f9, $9c, $c5, $21, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $01, $5e, $c9, $95, $11, $10, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $12, $ff, $f2, $10, $00, $60, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $01, $ff, $f1, $10, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $01, $12, $11, $00, $0a, $40, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $06, $11, $11, $00, $06, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $15, $15, $10, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $5e, $ee, $ee, $e5, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $01, $7d, $de, $dd, $d2, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $cc, $55, $55, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $cc, $cc, $55, $51, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $cc, $cc, $55, $55, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $5c, $cc, $51, $51, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $cc, $c5, $56, $54, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $05, $55, $55, $15, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
}}
moonsprite:
%asm {{
.byte $00, $00, $00, $00, $00, $00, $78, $88, $87, $50, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $ba, $99, $9a, $a9, $88, $76, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $b9, $99, $77, $67, $79, $78, $89, $93, $00, $00, $00, $00
.byte $00, $00, $00, $76, $69, $ca, $bc, $3b, $99, $78, $66, $99, $60, $00, $00, $00
.byte $00, $00, $04, $46, $cb, $64, $67, $77, $cb, $bb, $97, $99, $96, $00, $00, $00
.byte $00, $00, $62, $39, $93, $33, $36, $67, $ac, $cc, $79, $99, $98, $60, $00, $00
.byte $00, $06, $23, $47, $63, $43, $46, $79, $9b, $c6, $97, $96, $aa, $86, $00, $00
.byte $00, $06, $34, $36, $63, $43, $67, $37, $a9, $64, $46, $87, $ba, $98, $30, $00
.byte $00, $62, $46, $47, $76, $63, $66, $b7, $c9, $73, $46, $3a, $bc, $c9, $60, $00
.byte $00, $13, $39, $73, $33, $74, $36, $99, $b9, $34, $43, $67, $cb, $87, $44, $00
.byte $06, $43, $36, $37, $96, $76, $76, $3b, $d7, $34, $63, $48, $9a, $b9, $22, $00
.byte $03, $22, $63, $83, $79, $78, $99, $9a, $77, $77, $96, $33, $62, $9c, $22, $10
.byte $a3, $32, $36, $77, $bb, $ca, $a7, $63, $63, $97, $92, $33, $22, $9c, $22, $20
.byte $a6, $32, $37, $a7, $7b, $eb, $a7, $79, $b7, $7c, $93, $23, $22, $38, $86, $10
.byte $cb, $33, $37, $a7, $9b, $99, $33, $7a, $9d, $dc, $93, $33, $23, $36, $67, $10
.byte $cb, $23, $33, $77, $79, $99, $67, $76, $8e, $ee, $b7, $33, $63, $43, $22, $10
.byte $99, $33, $23, $36, $37, $39, $79, $ca, $bd, $dd, $dd, $a4, $a9, $62, $22, $20
.byte $b6, $72, $73, $37, $a7, $99, $7d, $ce, $de, $dd, $df, $97, $ca, $42, $22, $20
.byte $bb, $93, $33, $33, $b3, $6b, $37, $d9, $dd, $ed, $df, $c9, $bc, $92, $26, $30
.byte $0d, $d7, $39, $33, $73, $77, $77, $9b, $cd, $de, $ed, $ec, $96, $aa, $44, $10
.byte $0c, $cb, $9a, $b3, $39, $67, $76, $bc, $dd, $ee, $dd, $fb, $76, $77, $32, $00
.byte $0b, $dc, $cb, $33, $ca, $a7, $83, $dd, $cd, $dd, $dd, $dd, $a8, $a7, $a3, $00
.byte $00, $de, $dc, $73, $76, $73, $37, $ac, $ed, $ed, $dd, $ec, $bc, $b9, $63, $00
.byte $00, $bd, $ed, $b7, $b9, $c7, $99, $ee, $fd, $ec, $de, $ed, $cc, $cb, $70, $00
.byte $00, $0c, $ce, $d9, $c7, $9e, $ef, $ff, $ff, $ed, $ed, $db, $ca, $db, $30, $00
.byte $00, $0b, $9c, $c7, $cd, $de, $ef, $ff, $fe, $ed, $cc, $bc, $ba, $a7, $00, $00
.byte $00, $00, $bd, $9d, $dd, $de, $ff, $ff, $fe, $ee, $ec, $cc, $c9, $60, $00, $00
.byte $00, $00, $0b, $ca, $ac, $ee, $ff, $ff, $fe, $cc, $cd, $cd, $96, $00, $00, $00
.byte $00, $00, $00, $ba, $9d, $cc, $fe, $ff, $fd, $cc, $cc, $97, $60, $00, $00, $00
.byte $00, $00, $00, $00, $9c, $da, $dd, $dc, $cd, $db, $a9, $83, $00, $00, $00, $00
.byte $00, $00, $00, $00, $08, $aa, $bd, $dc, $ac, $a9, $96, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $59, $7b, $99, $60, $00, $00, $00, $00, $00, $00
}}
}
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff. Show more