mirror of
https://github.com/irmen/prog8.git
synced 2026-10-24 18:02:40 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dd1c17ff4 | ||
|
|
fa5479ee5f | ||
|
|
03412cacba | ||
|
|
01a38a0b11 | ||
|
|
f43c14bd78 | ||
|
|
fb23452383 | ||
|
|
ab7dde1450 | ||
|
|
8d9bc2f5ff | ||
|
|
7651ccc84e | ||
|
|
1a6b95b388 | ||
|
|
78ec1e7512 | ||
|
|
7e38d26c33 | ||
|
|
ed09dd4e9e | ||
|
|
5731b79554 | ||
|
|
eaa22a9d13 | ||
|
|
b2bdfe8482 | ||
|
|
fea531be9a | ||
|
|
7c69d38588 | ||
|
|
a088ee56b0 | ||
|
|
ae669af904 | ||
|
|
d1ddf05e38 | ||
|
|
51279a98b3 | ||
|
|
bf33a4f82d | ||
|
|
fff0d741c3 | ||
|
|
e83d0ee820 | ||
|
|
09f3eecf56 | ||
|
|
2bd4326ff6 | ||
|
|
c13168b60c | ||
|
|
ea3871d0c4 | ||
|
|
70a2b11271 | ||
|
|
3cf39e072e | ||
|
|
413b86cc4a | ||
|
|
a6107fcfdf | ||
|
|
a064ade1e0 | ||
|
|
df35aa7942 | ||
|
|
cd49c5f88d | ||
|
|
1541ad2160 | ||
|
|
c78b7b1a24 | ||
|
|
9c7a645e18 | ||
|
|
4acf38031a | ||
|
|
4cd7271e30 | ||
|
|
3f630ab1b0 | ||
|
|
04cb684fd4 | ||
|
|
4c843571ea | ||
|
|
1326498802 | ||
|
|
b7ebd8c4a6 | ||
|
|
24e0a69480 | ||
|
|
4bcb2bdede | ||
|
|
d27f3eb8a4 | ||
|
|
d3e4481112 | ||
|
|
1d1d6b3d98 | ||
|
|
90b8a22a71 |
No files matched your search
@@ -1,5 +1,6 @@
|
||||
.idea/workspace.xml
|
||||
.idea/discord.xml
|
||||
.idea/developer-tools.xml
|
||||
build/
|
||||
dist/
|
||||
output/
|
||||
|
||||
+10
-2
@@ -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>
|
||||
Generated
+2
-1
@@ -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>
|
||||
@@ -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:*
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
; experimental buffer data structures
|
||||
; **experimental** buffer data structures, API subject to change!!
|
||||
|
||||
%option no_symbol_prefixing, ignore_unused
|
||||
|
||||
|
||||
@@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
***/
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}}
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {{
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
@@ -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 {
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
+34
-11
@@ -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,
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
; all library modules for the atari compiler target
|
||||
|
||||
%import anyall
|
||||
%import buffers
|
||||
%import compression
|
||||
%import conv
|
||||
%import cx16logo
|
||||
%import diskio
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
; all library modules for the c128 compiler target
|
||||
|
||||
%import anyall
|
||||
%import buffers
|
||||
%import compression
|
||||
%import conv
|
||||
%import cx16logo
|
||||
%import diskio
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
; all library modules for the c64 compiler target
|
||||
|
||||
%import anyall
|
||||
%import buffers
|
||||
%import compression
|
||||
%import conv
|
||||
%import cx16logo
|
||||
%import diskio
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
; all library modules for the pet32 compiler target
|
||||
|
||||
%import anyall
|
||||
%import buffers
|
||||
%import compression
|
||||
%import conv
|
||||
%import cx16logo
|
||||
%import diskio
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
===================================
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
Reference in new issue
Block a user