moved various miscellaneous builtin functions such as exit() and progend() to sys.*

This commit is contained in:
Irmen de Jong 2021-01-08 16:20:56 +01:00
parent d61420f1c6
commit f61682cdc7
20 changed files with 271 additions and 152 deletions

View File

@ -571,6 +571,82 @@ _longcopy
}}
}
inline asmsub rsave() {
; save cpu status flag and all registers A, X, Y.
; see http://6502.org/tutorials/register_preservation.html
%asm {{
php
sta P8ZP_SCRATCH_REG
pha
txa
pha
tya
pha
lda P8ZP_SCRATCH_REG
}}
}
inline asmsub rrestore() {
; restore all registers and cpu status flag
%asm {{
pla
tay
pla
tax
pla
plp
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php
pla
}}
}
inline asmsub clear_carry() {
%asm {{
clc
}}
}
inline asmsub set_carry() {
%asm {{
sec
}}
}
inline asmsub clear_irqd() {
%asm {{
cli
}}
}
inline asmsub set_irqd() {
%asm {{
sei
}}
}
inline asmsub exit(ubyte returnvalue @A) {
; -- immediately exit the program with a return code in the A register
%asm {{
jsr c64.CLRCHN ; reset i/o channels
ldx prog8_lib.orig_stackpointer
txs
rts ; return to original caller
}}
}
inline asmsub progend() -> uword @AY {
%asm {{
lda #<prog8_program_end
ldy #>prog8_program_end
}}
}
}
cx16 {

View File

@ -19,6 +19,14 @@ sub clear_screen() {
txt.chrout(147)
}
sub nl() {
txt.chrout('\n')
}
sub home() {
txt.chrout(19)
}
asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) {
; ---- fill the character screen with the given fill character and character color.
; (assumes screen and color matrix are at their default addresses)

View File

@ -525,4 +525,72 @@ sys {
}}
}
inline asmsub rsave() {
; save cpu status flag and all registers A, X, Y.
; see http://6502.org/tutorials/register_preservation.html
%asm {{
php
pha
phy
phx
}}
}
inline asmsub rrestore() {
; restore all registers and cpu status flag
%asm {{
plx
ply
pla
plp
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php
pla
}}
}
inline asmsub clear_carry() {
%asm {{
clc
}}
}
inline asmsub set_carry() {
%asm {{
sec
}}
}
inline asmsub clear_irqd() {
%asm {{
cli
}}
}
inline asmsub set_irqd() {
%asm {{
sei
}}
}
inline asmsub exit(ubyte returnvalue @A) {
; -- immediately exit the program with a return code in the A register
%asm {{
jsr c64.CLRCHN ; reset i/o channels
ldx prog8_lib.orig_stackpointer
txs
rts ; return to original caller
}}
}
inline asmsub progend() -> uword @AY {
%asm {{
lda #<prog8_program_end
ldy #>prog8_program_end
}}
}
}

View File

@ -15,10 +15,18 @@ const ubyte DEFAULT_WIDTH = 80
const ubyte DEFAULT_HEIGHT = 60
sub clear_screen() {
sub clear_screen() {
txt.chrout(147)
}
sub nl() {
txt.chrout('\n')
}
sub home() {
txt.chrout(19)
}
asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) {
; ---- fill the character screen with the given fill character and character color.
%asm {{

View File

@ -1078,21 +1078,3 @@ _loop_hi ldy _index_first
.pend
func_exit .proc
; -- immediately exit the program with a return code in the A register
jsr c64.CLRCHN ; reset i/o channels
ldx orig_stackpointer
txs
rts ; return to original caller
.pend
func_read_flags_stack .proc
; -- put the processor status register on the stack
php
pla
sta P8ESTACK_LO,x
dex
rts
.pend

View File

@ -850,7 +850,7 @@ internal class AsmGen(private val program: Program,
}
out("""
tsx
stx prog8_lib.orig_stackpointer ; required for func_exit
stx prog8_lib.orig_stackpointer ; required for sys.exit()
ldx #255 ; init estack ptr
clv
clc""")

View File

@ -59,41 +59,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
"sort" -> funcSort(fcall)
"reverse" -> funcReverse(fcall)
"memory" -> funcMemory(fcall, discardResult, resultToStack)
// TODO move all of the functions below to the sys module as well:
"rsave" -> {
// save cpu status flag and all registers A, X, Y.
// see http://6502.org/tutorials/register_preservation.html
asmgen.out(" php | sta P8ZP_SCRATCH_REG | pha | txa | pha | tya | pha | lda P8ZP_SCRATCH_REG")
}
"rrestore" -> {
// restore all registers and cpu status flag
asmgen.out(" pla | tay | pla | tax | pla | plp")
}
"read_flags" -> {
if(resultToStack)
asmgen.out(" jsr prog8_lib.func_read_flags_stack")
else
asmgen.out(" php | pla")
}
"clear_carry" -> asmgen.out(" clc")
"set_carry" -> asmgen.out(" sec")
"clear_irqd" -> asmgen.out(" cli")
"set_irqd" -> asmgen.out(" sei")
"exit" -> {
translateArguments(fcall.args, func, sscope)
asmgen.out(" jmp prog8_lib.func_exit")
}
"progend" -> {
if(resultToStack)
asmgen.out("""
lda #<prog8_program_end
sta P8ESTACK_LO,x
lda #>prog8_program_end
sta P8ESTACK_HI,x
dex""")
else
asmgen.out(" lda #<prog8_program_end | ldy #>prog8_program_end")
}
else -> TODO("missing asmgen for builtin func ${func.name}")
}
}

View File

@ -133,15 +133,6 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
FSignature("rndw" , false, emptyList(), DataType.UWORD),
FSignature("rndf" , false, emptyList(), DataType.FLOAT),
FSignature("exit" , false, listOf(FParam("returnvalue", setOf(DataType.UBYTE))), null),
FSignature("rsave" , false, emptyList(), null),
FSignature("rrestore" , false, emptyList(), null),
FSignature("set_carry" , false, emptyList(), null),
FSignature("clear_carry" , false, emptyList(), null),
FSignature("set_irqd" , false, emptyList(), null),
FSignature("clear_irqd" , false, emptyList(), null),
FSignature("read_flags" , true, emptyList(), DataType.UBYTE),
FSignature("progend" , true, emptyList(), DataType.UWORD),
FSignature("memory" , true, listOf(FParam("name", setOf(DataType.STR)), FParam("size", setOf(DataType.UWORD))), DataType.UWORD),
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),

View File

@ -45,6 +45,10 @@ sys (part of syslib)
- 16 = compiled for CommanderX16 with 65C02 CPU
- 64 = compiled for Commodore-64 with 6502/6510 CPU
``exit(returncode)``
Immediately stops the program and exits it, with the returncode in the A register.
Note: custom interrupt handlers remain active unless manually cleared first!
``memcopy(from, to, numbytes)``
Efficiently copy a number of bytes from a memory location to another.
NOTE: 'to' must NOT overlap with 'from', unless it is *before* 'from'.
@ -63,6 +67,38 @@ sys (part of syslib)
Efficiently set a part of memory to the given (u)word value.
But the most efficient will always be to write a specialized fill routine in assembly yourself!
``rsave()``
Saves the CPU registers and the status flags.
You can now more or less 'safely' use the registers directly, until you
restore them again so the generated code can carry on normally.
Note: it's not needed to rsave() before an asm subroutine that clobbers the X register
(which is used as the internal evaluation stack pointer).
The compiler will take care of this situation automatically.
Note: the 16 bit 'virtual' registers of the Commander X16 are *not* saved.
``rrestore()``
Restores the CPU registers and the status flags from previously saved values.
Note: the 16 bit 'virtual' registers of the Commander X16 are *not* restored.
``read_flags() -> ubyte``
Returns the current value of the CPU status register.
``set_carry()``
Sets the CPU status register Carry flag.
``clear_carry()``
Clears the CPU status register Carry flag.
``set_irqd()``
Sets the CPU status register Interrupt Disable flag.
``clear_irqd()``
Clears the CPU status register Interrupt Disable flag.
``progend()``
Returns the last address of the program in memory + 1.
Can be used to load dynamic data after the program, instead of hardcoding something.
conv
----

View File

@ -781,10 +781,6 @@ sort(array)
Miscellaneous
^^^^^^^^^^^^^
exit(returncode)
Immediately stops the program and exits it, with the returncode in the A register.
Note: custom interrupt handlers remain active unless manually cleared first!
lsb(x)
Get the least significant byte of the word x. Equivalent to the cast "x as ubyte".
@ -834,36 +830,12 @@ ror2(x)
It uses some extra logic to not consider the carry flag as extra rotation bit.
Modifies in-place, doesn't return a value (so can't be used in an expression).
rsave()
Saves the CPU registers and the status flags.
You can now more or less 'safely' use the registers directly, until you
restore them again so the generated code can carry on normally.
Note: it's not needed to rsave() before an asm subroutine that clobbers the X register
(which is used as the internal evaluation stack pointer).
The compiler will take care of this situation automatically.
Note: the 16 bit 'virtual' registers of the Commander X16 are not saved.
rrestore()
Restores the CPU registers and the status flags from previously saved values.
Note: the 16 bit 'virtual' registers of the Commander X16 are not restored.
read_flags()
Returns the current value of the CPU status register.
sizeof(name)
Number of bytes that the object 'name' occupies in memory. This is a constant determined by the data type of
the object. For instance, for a variable of type uword, the sizeof is 2.
For an 10 element array of floats, it is 50 (on the C-64, where a float is 5 bytes).
Note: usually you will be interested in the number of elements in an array, use len() for that.
set_carry() / clear_carry()
Set (or clear) the CPU status register Carry flag. No result value.
(translated into ``SEC`` or ``CLC`` cpu instruction)
set_irqd() / clear_irqd()
Set (or clear) the CPU status register Interrupt Disable flag. No result value.
(translated into ``SEI`` or ``CLI`` cpu instruction)
swap(x, y)
Swap the values of numerical variables (or memory locations) x and y in a fast way.
@ -875,10 +847,6 @@ memory(name, size)
with fixed memory addresses for buffers.
The portion of memory cannot be used as an array, you only have the address of the first byte.
progend()
Returns the last address of the program in memory + 1.
Can be used to load dynamic data after the program, instead of hardcoding something.
Library routines
----------------

View File

@ -2,10 +2,8 @@
TODO
====
- move the other marked functions in builtinfunctionsasmgen to the sys module as well. update docs.
- use (zp) addressing mode on 65c02 specific code rather than ldy#0 / lda (zp),y
- optimize pointer access code @(pointer)? use a subroutine? macro? 65c02 vs 6502?
- allow byte return type with single register for asmsubs, for instance string.compare
- can we get rid of the --longOptionName command line options and only keep the short versions? https://github.com/Kotlin/kotlinx-cli/issues/50
- optimizer: detect variables that are written but never read - mark those as unused too and remove them, such as uword unused = memory("unused222", 20) - also remove the memory slab allocation
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)

View File

@ -25,19 +25,19 @@ main {
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
@ -47,25 +47,25 @@ main {
ror(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(uwarr[0])
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
txt.chrout('\n')
clear_carry()
sys.clear_carry()
txt.print_uwbin(uwarr[0], true)
txt.chrout('\n')
rol2(uwarr[0])
@ -100,41 +100,41 @@ main {
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(ubarr[0])
txt.print_ubbin(ubarr[0], true)
txt.chrout('\n')
@ -179,19 +179,19 @@ main {
@(addr) = %10110101
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
rol(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
@ -200,19 +200,19 @@ main {
@(addr) = %10110101
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
set_carry()
sys.set_carry()
ror(@(addr))
txt.print_ubbin(@(addr), true)
txt.chrout('\n')
@ -273,10 +273,10 @@ main {
txt.chrout('\n')
}
ub = read_flags()
ub = sys.read_flags()
txt.print_ub(ub)
txt.chrout('\n')
ub = zero+read_flags()*1+zero
ub = zero+sys.read_flags()*1+zero
txt.print_ub(ub)
txt.chrout('\n')

View File

@ -30,13 +30,13 @@ charset {
sub copy_rom_charset() {
; copies the charset from ROM to RAM so we can modify it
set_irqd()
sys.set_irqd()
ubyte bank = @($0001)
@($0001) = bank & %11111011 ; enable CHAREN, so the character rom accessible at $d000
sys.memcopy($d000, CHARSET, 256*8*2) ; copy the charset to RAM
@($0001) = bank ; reset previous memory banking
clear_irqd()
sys.clear_irqd()
}
sub make_custom_charset() {

View File

@ -145,7 +145,7 @@ main {
txt.print(" <= ")
txt.print_uw(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
@ -172,7 +172,7 @@ main {
txt.print(" not <= ")
txt.print_uw(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
}
@ -328,7 +328,7 @@ main {
txt.print(" > ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
@ -362,7 +362,7 @@ main {
txt.print(" not > ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
}
@ -518,7 +518,7 @@ main {
txt.print(" >= ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
@ -552,7 +552,7 @@ main {
txt.print(" not >= ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
}
@ -702,7 +702,7 @@ main {
txt.print(" <= ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
@ -729,7 +729,7 @@ main {
txt.print(" not <= ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
}
@ -878,7 +878,7 @@ main {
txt.print(" < ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
@ -905,7 +905,7 @@ main {
txt.print(" not < ")
txt.print_w(w2)
txt.chrout('\n')
exit(1)
sys.exit(1)
}
}
}

View File

@ -170,13 +170,13 @@ textparse {
txt.chrout('\n')
}
sub lowercase(uword string) {
sub lowercase(uword st) {
; TODO optimize in asm
ubyte char = @(string)
ubyte char = @(st)
while char {
@(string) = char & 127
string++
char = @(string)
@(st) = char & 127
st++
char = @(st)
}
}

View File

@ -51,7 +51,7 @@ ci_module {
sub show_image(uword filename) -> ubyte {
uword buffer = memory("buffer", 620*2) ; enough to store two scanlines of 640 bytes
ubyte read_success = false
uword bitmap_load_address = progend()
uword bitmap_load_address = sys.progend()
; uword max_bitmap_size = $9eff - bitmap_load_address
if(diskio.f_open(8, filename)) {

View File

@ -21,7 +21,7 @@ iff_module {
str chunk_id = "????"
uword chunk_size_hi
uword chunk_size_lo
uword scanline_data_ptr = progend()
uword scanline_data_ptr = sys.progend()
uword width
uword height

View File

@ -113,7 +113,7 @@ main {
gfx2.screen_mode(255) ; back to default text mode and palette
txt.print(filenameptr)
txt.print(": load error\n")
exit(1)
sys.exit(1)
}
sub extension_equals(uword stringptr, uword extensionptr) -> ubyte {

View File

@ -38,7 +38,7 @@ pcx_module {
load_ok = c64.CHRIN()
if load_ok == 12 {
; there is 256 colors of palette data at the end
uword palette_mem = progend()
uword palette_mem = sys.progend()
load_ok = false
size = diskio.f_read(palette_mem, 3*256)
if size==3*256 {

View File

@ -7,11 +7,30 @@
main {
sub start() {
sys.memset($0400+5*40, 40*20-1, '*')
sys.memsetw($0400+40*10, 40*10/2, $2299)
sys.memcopy($a000, $0400, 1000-3)
sys.memset($0400+10*40, 14*40, 'a')
sys.memcopy($0400+10*40, $0400, 3*40)
ubyte zero=0
ubyte ub
sys.clear_carry()
sys.clear_irqd()
ub = sys.read_flags()
txt.print_ubbin(ub,1)
txt.chrout('\n')
sys.clear_carry()
ub = zero+sys.read_flags()+zero
txt.print_ubbin(ub,1)
txt.chrout('\n')
sys.set_carry()
sys.set_irqd()
ub = sys.read_flags()
txt.print_ubbin(ub,1)
txt.chrout('\n')
sys.set_carry()
ub = zero+sys.read_flags()+zero
txt.print_ubbin(ub,1)
txt.chrout('\n')
test_stack.test()
}
sub start2 () {