mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 19:16:13 +00:00
Add clear_screen and set_screen_mode to gfx_lores. Fix boolean draw vs color param in some monogfx routines. Elaborate some docs.
This commit is contained in:
@@ -82,7 +82,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
|||||||
is PtAddressOf -> false
|
is PtAddressOf -> false
|
||||||
is PtIdentifier -> false
|
is PtIdentifier -> false
|
||||||
is PtIrRegister -> false
|
is PtIrRegister -> false
|
||||||
is PtMemoryByte -> true // TODO might not actually need extra registers if the value has to end up in A
|
is PtMemoryByte -> arg.address !is PtNumber && arg.address !is PtIdentifier
|
||||||
is PtNumber -> false
|
is PtNumber -> false
|
||||||
is PtBool -> false
|
is PtBool -> false
|
||||||
else -> true
|
else -> true
|
||||||
|
|||||||
@@ -1,10 +1,31 @@
|
|||||||
; optimized graphics routines for just a single screen mode: lores 320*240, 256c (8bpp)
|
; optimized graphics routines for just the single screen mode: lores 320*240, 256c (8bpp)
|
||||||
; bitmap image needs to start at VRAM addres $00000.
|
; 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))
|
; This is compatible with the CX16's screen mode 128. (void cx16.set_screen_mode(128))
|
||||||
|
|
||||||
|
|
||||||
gfx_lores {
|
gfx_lores {
|
||||||
|
|
||||||
|
sub set_screen_mode() {
|
||||||
|
cx16.VERA_CTRL=0
|
||||||
|
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1
|
||||||
|
cx16.VERA_DC_HSCALE = 64
|
||||||
|
cx16.VERA_DC_VSCALE = 64
|
||||||
|
cx16.VERA_L1_CONFIG = %00000111
|
||||||
|
cx16.VERA_L1_MAPBASE = 0
|
||||||
|
cx16.VERA_L1_TILEBASE = 0
|
||||||
|
clear_screen(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub clear_screen(ubyte color) {
|
||||||
|
cx16.VERA_CTRL=0
|
||||||
|
cx16.VERA_ADDR=0
|
||||||
|
cx16.VERA_ADDR_H = 1<<4 ; 1 pixel auto increment
|
||||||
|
repeat 240
|
||||||
|
cs_innerloop320(color)
|
||||||
|
cx16.VERA_ADDR=0
|
||||||
|
cx16.VERA_ADDR_H = 0
|
||||||
|
}
|
||||||
|
|
||||||
sub line(uword x1, ubyte y1, uword x2, ubyte y2, ubyte color) {
|
sub line(uword x1, ubyte y1, uword x2, ubyte y2, ubyte color) {
|
||||||
; Bresenham algorithm.
|
; Bresenham algorithm.
|
||||||
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
|
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
|
||||||
@@ -141,7 +162,6 @@ times320_hi .byte `times320
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub horizontal_line(uword xx, ubyte yy, uword length, ubyte color) {
|
sub horizontal_line(uword xx, ubyte yy, uword length, ubyte color) {
|
||||||
if length==0
|
if length==0
|
||||||
return
|
return
|
||||||
@@ -183,6 +203,26 @@ times320_hi .byte `times320
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
inline asmsub vera_setaddr(uword xx @R0, ubyte yy @R1) {
|
inline asmsub vera_setaddr(uword xx @R0, ubyte yy @R1) {
|
||||||
; set the correct vera start address (no auto increment yet!)
|
; set the correct vera start address (no auto increment yet!)
|
||||||
%asm {{
|
%asm {{
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ monogfx {
|
|||||||
width = 320
|
width = 320
|
||||||
height = 240
|
height = 240
|
||||||
mode = MODE_NORMAL
|
mode = MODE_NORMAL
|
||||||
clear_screen(0)
|
clear_screen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hires() {
|
sub hires() {
|
||||||
@@ -47,7 +47,7 @@ monogfx {
|
|||||||
width = 640
|
width = 640
|
||||||
height = 480
|
height = 480
|
||||||
mode = MODE_NORMAL
|
mode = MODE_NORMAL
|
||||||
clear_screen(0)
|
clear_screen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub textmode() {
|
sub textmode() {
|
||||||
@@ -61,16 +61,16 @@ monogfx {
|
|||||||
mode = dm
|
mode = dm
|
||||||
}
|
}
|
||||||
|
|
||||||
sub clear_screen(ubyte color) {
|
sub clear_screen(bool draw) {
|
||||||
position(0, 0)
|
position(0, 0)
|
||||||
when width {
|
when width {
|
||||||
320 -> {
|
320 -> {
|
||||||
repeat 240/2/8
|
repeat 240/2/8
|
||||||
cs_innerloop640(color)
|
cs_innerloop640(draw)
|
||||||
}
|
}
|
||||||
640 -> {
|
640 -> {
|
||||||
repeat 480/8
|
repeat 480/8
|
||||||
cs_innerloop640(color)
|
cs_innerloop640(draw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
position(0, 0)
|
position(0, 0)
|
||||||
@@ -90,8 +90,8 @@ monogfx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub fillrect(uword xx, uword yy, uword rwidth, uword rheight, bool draw) {
|
sub fillrect(uword xx, uword yy, uword rwidth, uword rheight, bool draw) {
|
||||||
; Draw a filled rectangle of the given size and color.
|
; Draw a filled rectangle of the given size.
|
||||||
; To fill the whole screen, use clear_screen(color) instead - it is much faster.
|
; To fill the whole screen, use clear_screen(draw) instead - it is much faster.
|
||||||
if rwidth==0
|
if rwidth==0
|
||||||
return
|
return
|
||||||
repeat rheight {
|
repeat rheight {
|
||||||
@@ -1000,7 +1000,7 @@ cdraw_mod2 ora cx16.VERA_DATA1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub cs_innerloop640(ubyte color @A) clobbers(Y) {
|
asmsub cs_innerloop640(bool draw @A) clobbers(Y) {
|
||||||
; using verafx 32 bits writes here would make this faster but it's safer to
|
; 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.
|
; use verafx only explicitly when you know what you're doing.
|
||||||
%asm {{
|
%asm {{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ monogfx {
|
|||||||
width = 320
|
width = 320
|
||||||
height = 240
|
height = 240
|
||||||
mode = MODE_NORMAL
|
mode = MODE_NORMAL
|
||||||
clear_screen(0)
|
clear_screen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hires() {
|
sub hires() {
|
||||||
@@ -32,7 +32,7 @@ monogfx {
|
|||||||
width = 640
|
width = 640
|
||||||
height = 480
|
height = 480
|
||||||
mode = MODE_NORMAL
|
mode = MODE_NORMAL
|
||||||
clear_screen(0)
|
clear_screen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub textmode() {
|
sub textmode() {
|
||||||
@@ -43,9 +43,10 @@ monogfx {
|
|||||||
mode = dm
|
mode = dm
|
||||||
}
|
}
|
||||||
|
|
||||||
sub clear_screen(ubyte color) {
|
sub clear_screen(bool draw) {
|
||||||
if color!=0
|
ubyte color = 0
|
||||||
color=255
|
if draw
|
||||||
|
color = 255
|
||||||
sys.gfx_clear(color)
|
sys.gfx_clear(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ monogfx {
|
|||||||
|
|
||||||
sub fillrect(uword xx, uword yy, uword rwidth, uword rheight, bool draw) {
|
sub fillrect(uword xx, uword yy, uword rwidth, uword rheight, bool draw) {
|
||||||
; Draw a filled rectangle of the given size and color.
|
; Draw a filled rectangle of the given size and color.
|
||||||
; To fill the whole screen, use clear_screen(color) instead - it is much faster.
|
; To fill the whole screen, use clear_screen(draw) instead - it is much faster.
|
||||||
if rwidth==0
|
if rwidth==0
|
||||||
return
|
return
|
||||||
repeat rheight {
|
repeat rheight {
|
||||||
|
|||||||
@@ -903,7 +903,7 @@ to see what's in there.
|
|||||||
gfx2 (cx16 only)
|
gfx2 (cx16 only)
|
||||||
-----------------
|
-----------------
|
||||||
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
|
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
|
||||||
Same interface as monogfx, but for color screens. For 1 bpp monochrome screens, use monogfx.
|
Same interface as monogfx, but for color screens. For 1 bpp monochrome screens: use monogfx.
|
||||||
|
|
||||||
- multiple full-screen bitmap color resolutions
|
- multiple full-screen bitmap color resolutions
|
||||||
- clearing screen, switching screen mode, also back to text mode
|
- clearing screen, switching screen mode, also back to text mode
|
||||||
@@ -916,6 +916,15 @@ Read the `gfx2 source code <https://github.com/irmen/prog8/tree/master/compiler/
|
|||||||
to see what's in there.
|
to see what's in there.
|
||||||
|
|
||||||
|
|
||||||
|
gfx_lores (cx16 only)
|
||||||
|
----------------------
|
||||||
|
Heavily optimized graphics routines for just the single screen mode: lores 320*240, 256c (8bpp)
|
||||||
|
This is screen mode 1 from the gfx2 module (and also compatible with X16's basic screen mode 128).
|
||||||
|
|
||||||
|
Read the `gfx_lores source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_lores.p8>`_
|
||||||
|
to see what's in there.
|
||||||
|
|
||||||
|
|
||||||
palette (cx16 only)
|
palette (cx16 only)
|
||||||
--------------------
|
--------------------
|
||||||
Available for the Cx16 target. Various routines to set the display color palette.
|
Available for the Cx16 target. Various routines to set the display color palette.
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
|
Regenerate skeletons in doc.
|
||||||
|
|
||||||
|
|
||||||
Improve register load order in subroutine call args assignments:
|
Improve register load order in subroutine call args assignments:
|
||||||
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
|
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
|
||||||
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
|
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
|
||||||
Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEvaluating() and argumentsViaRegisters().
|
Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEvaluating() and argumentsViaRegisters().
|
||||||
|
|
||||||
|
|
||||||
Regenerate skeletons in doc.
|
|
||||||
|
|
||||||
|
|
||||||
Future Things and Ideas
|
Future Things and Ideas
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
|
|
||||||
- Some facility to use add-with-carry and sub-with-carry (so we can chain additions/subtractions without clc/sec inserted every time)
|
- Some facility to use add-with-carry and sub-with-carry (so we can chain additions/subtractions without clc/sec inserted every time)
|
||||||
|
Note: +/- 0 can't be optimized away anymore in this case!
|
||||||
|
Note2: may need to preserve carry flag during evaluation of the operands!
|
||||||
|
Note3: only available for bytes? (or does it work on words automatically?), and perhaps restrict operand to a simple expression?
|
||||||
- Can we support signed % (remainder) somehow?
|
- 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?)
|
- 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?)
|
||||||
- IR: implement missing operators in AssignmentGen (array shifts etc)
|
- IR: implement missing operators in AssignmentGen (array shifts etc)
|
||||||
- IR: CMPI+BSTEQ --> new BEQ reg,value,label instruction (like BGT etc)
|
- IR: CMPI+BSTEQ --> new BEQ reg,value,label instruction (like BGT etc)
|
||||||
- expand the kata encoding to somehow translate normal katana to half-widths? (see comment in KatakanaEncoding)
|
|
||||||
- instead of copy-pasting inline asmsubs, make them into a 64tass macro and use that instead.
|
- 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.
|
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.
|
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays.
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ adpcm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub decode_nibble(ubyte @zp nibble) {
|
sub decode_nibble(ubyte @zp nibble) {
|
||||||
; Decoder for nibbles for the first channel.
|
; 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!
|
; This is the hotspot of the decoder algorithm!
|
||||||
; Note that the generated assembly from this is pretty efficient,
|
; Note that the generated assembly from this is pretty efficient,
|
||||||
; rewriting it by hand in asm seems to improve it only 5-10%
|
; rewriting it by hand in asm seems to improve it only ~10%.
|
||||||
cx16.r0s = 0 ; difference
|
cx16.r0s = 0 ; difference
|
||||||
if nibble & %0100 !=0
|
if nibble & %0100 !=0
|
||||||
cx16.r0s += pstep
|
cx16.r0s += pstep
|
||||||
|
|||||||
@@ -153,10 +153,10 @@ mono {
|
|||||||
repeat 252/2 {
|
repeat 252/2 {
|
||||||
unroll 2 {
|
unroll 2 {
|
||||||
nibble = @(main.nibblesptr)
|
nibble = @(main.nibblesptr)
|
||||||
adpcm.decode_nibble(nibble & 15) ; first word
|
adpcm.decode_nibble(nibble & 15) ; first word (note: upper nibble needs to be zero!)
|
||||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||||
adpcm.decode_nibble(nibble>>4) ; second word
|
adpcm.decode_nibble(nibble>>4) ; second word (note: upper nibble is zero, after the shifts.)
|
||||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||||
main.nibblesptr++
|
main.nibblesptr++
|
||||||
@@ -219,6 +219,7 @@ stereo {
|
|||||||
|
|
||||||
sub decode_nibbles_unrolled() {
|
sub decode_nibbles_unrolled() {
|
||||||
; decode 4 left channel nibbles
|
; decode 4 left channel nibbles
|
||||||
|
; note: when calling decode_nibble(), the upper nibble in the argument needs to be zero
|
||||||
uword[8] left
|
uword[8] left
|
||||||
uword[8] right
|
uword[8] right
|
||||||
ubyte @requirezp nibble = @(main.nibblesptr)
|
ubyte @requirezp nibble = @(main.nibblesptr)
|
||||||
|
|||||||
@@ -304,6 +304,7 @@ _lp2 lda $ffff,y
|
|||||||
repeat 252/2 {
|
repeat 252/2 {
|
||||||
unroll 2 {
|
unroll 2 {
|
||||||
nibble = @(nibblesptr)
|
nibble = @(nibblesptr)
|
||||||
|
; note: when calling decode_nibble(), the upper nibble in the argument needs to be zero
|
||||||
adpcm.decode_nibble(nibble & 15) ; first word
|
adpcm.decode_nibble(nibble & 15) ; first word
|
||||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||||
@@ -330,6 +331,7 @@ _lp2 lda $ffff,y
|
|||||||
|
|
||||||
sub decode_nibbles_unrolled() {
|
sub decode_nibbles_unrolled() {
|
||||||
; decode 4 left channel nibbles
|
; decode 4 left channel nibbles
|
||||||
|
; note: when calling decode_nibble(), the upper nibble in the argument needs to be zero
|
||||||
uword[8] left
|
uword[8] left
|
||||||
uword[8] right
|
uword[8] right
|
||||||
ubyte @requirezp nibble = @(nibblesptr)
|
ubyte @requirezp nibble = @(nibblesptr)
|
||||||
|
|||||||
@@ -195,8 +195,8 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sys.wait(60)
|
sys.wait(60)
|
||||||
monogfx.clear_screen(1)
|
monogfx.clear_screen(true)
|
||||||
monogfx.clear_screen(0)
|
monogfx.clear_screen(false)
|
||||||
|
|
||||||
ubyte radius
|
ubyte radius
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,11 @@
|
|||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
%import gfx_lores
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
; nothing!
|
gfx_lores.set_screen_mode()
|
||||||
}
|
gfx_lores.clear_screen(0)
|
||||||
}
|
gfx_lores.line(0,0,319,239,5)
|
||||||
|
|
||||||
|
|
||||||
derp {
|
|
||||||
asmsub f_tell() -> uword @R0, uword @R1, uword @R2, uword @R3 {
|
|
||||||
%asm {{
|
|
||||||
jmp p8s_internal_f_tell
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub internal_f_tell() {
|
|
||||||
cx16.r1 = read4hex()
|
|
||||||
|
|
||||||
sub read4hex() -> uword {
|
|
||||||
str @shared hex = "0000000000000000000000000000000000000000000"
|
|
||||||
cx16.r0++
|
|
||||||
return cx16.r0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,22 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
"""
|
program_description = """
|
||||||
This is a simple run-time profiler tool for X16 assembly programs.
|
This is a simple run-time profiler tool for X16 assembly programs.
|
||||||
It takes an assembly list file (as produced by 64tass/turbo assembler) and
|
It takes an assembly list file (as produced by 64tass/turbo assembler) and
|
||||||
a memory access statistics dump file (produced by the emulator's -memorystats option)
|
a memory access statistics dump file (produced by the X16 emulator's -memorystats option)
|
||||||
and prints out what assembly lines and variables were read from and written to the most.
|
and prints out what assembly lines and variables were read from and written to the most.
|
||||||
These may indicate hot paths or even bottlenecks in your program,
|
These may indicate hot paths or even bottlenecks in your program,
|
||||||
and what variables in system ram might be better placed in Zeropage.
|
and what variables in system ram might be better placed in Zeropage.
|
||||||
|
|
||||||
The -memorystats option in the emulator is work in progress at the time of writing.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import argparse
|
import argparse
|
||||||
import operator
|
import operator
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
class AsmList:
|
class AsmList:
|
||||||
"""parses a l64tass Turbo Assembler Macro listing file"""
|
"""parses a 64tass Turbo Assembler Macro listing file"""
|
||||||
|
|
||||||
def __init__(self, filename: str) -> None:
|
def __init__(self, filename: str) -> None:
|
||||||
self.lines = []
|
self.lines = []
|
||||||
@@ -170,7 +167,7 @@ def profile(number_of_lines: int, asmlist: str, memstats: str) -> None:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="simple X16 assembly run time profiler")
|
parser = argparse.ArgumentParser(description=program_description)
|
||||||
parser.add_argument("-n", dest="number", type=int, default=20, help="amount of reads and writes to print (default 20)")
|
parser.add_argument("-n", dest="number", type=int, default=20, help="amount of reads and writes to print (default 20)")
|
||||||
parser.add_argument("asmlistfile", type=str, help="the 64tass/turbo assembler listing file to read")
|
parser.add_argument("asmlistfile", type=str, help="the 64tass/turbo assembler listing file to read")
|
||||||
parser.add_argument("memorystatsfile", type=str, help="the X16 emulator memstats dump file to read")
|
parser.add_argument("memorystatsfile", type=str, help="the X16 emulator memstats dump file to read")
|
||||||
|
|||||||
Reference in New Issue
Block a user