mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
fixed C64 ZP addresses to allow disk I/O, introduced diskio library module
This commit is contained in:
parent
bee6c65293
commit
439761cb67
165
compiler/res/prog8lib/diskio.p8
Normal file
165
compiler/res/prog8lib/diskio.p8
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
%import textio
|
||||||
|
%import syslib
|
||||||
|
|
||||||
|
; Note: this code is compatible with C64 and CX16.
|
||||||
|
|
||||||
|
diskio {
|
||||||
|
|
||||||
|
|
||||||
|
sub directory(ubyte drivenumber) -> byte {
|
||||||
|
; -- Shows the directory contents of disk drive 8-11 (provide as argument).
|
||||||
|
|
||||||
|
c64.SETNAM(1, "$")
|
||||||
|
c64.SETLFS(1, drivenumber, 0)
|
||||||
|
void c64.OPEN() ; open 1,8,0,"$"
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
void c64.CHKIN(1) ; use #1 as input channel
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
|
||||||
|
repeat 4 {
|
||||||
|
void c64.CHRIN() ; skip the 4 prologue bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
; while not key pressed / EOF encountered, read data.
|
||||||
|
ubyte status = c64.READST()
|
||||||
|
while not status {
|
||||||
|
txt.print_uw(mkword(c64.CHRIN(), c64.CHRIN()))
|
||||||
|
txt.chrout(' ')
|
||||||
|
ubyte @zp char
|
||||||
|
do {
|
||||||
|
char = c64.CHRIN()
|
||||||
|
txt.chrout(char)
|
||||||
|
} until char==0
|
||||||
|
txt.chrout('\n')
|
||||||
|
void c64.CHRIN() ; skip 2 bytes
|
||||||
|
void c64.CHRIN()
|
||||||
|
status = c64.READST()
|
||||||
|
void c64.STOP()
|
||||||
|
if_nz
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
io_error:
|
||||||
|
status = c64.READST()
|
||||||
|
c64.CLRCHN() ; restore default i/o devices
|
||||||
|
c64.CLOSE(1)
|
||||||
|
|
||||||
|
if status and status != 64 { ; 64=end of file
|
||||||
|
txt.print("\ni/o error, status: ")
|
||||||
|
txt.print_ub(status)
|
||||||
|
txt.chrout('\n')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub status(ubyte drivenumber) {
|
||||||
|
; -- display the disk drive's current status message
|
||||||
|
c64.SETNAM(0, $0000)
|
||||||
|
c64.SETLFS(15, drivenumber, 15)
|
||||||
|
void c64.OPEN() ; open 15,8,15
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
void c64.CHKIN(15) ; use #15 as input channel
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
|
||||||
|
while not c64.READST()
|
||||||
|
txt.chrout(c64.CHRIN())
|
||||||
|
|
||||||
|
io_error:
|
||||||
|
c64.CLRCHN() ; restore default i/o devices
|
||||||
|
c64.CLOSE(15)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
str filename = "0:??????????????????????????????????????"
|
||||||
|
|
||||||
|
sub save(ubyte drivenumber, uword filenameptr, uword address, uword size) -> byte {
|
||||||
|
ubyte flen = strlen(filenameptr)
|
||||||
|
filename[0] = '0'
|
||||||
|
filename[1] = ':'
|
||||||
|
memcopy(filenameptr, &filename+2, flen)
|
||||||
|
memcopy(",s,w", &filename+2+flen, 5)
|
||||||
|
c64.SETNAM(flen+6, filename)
|
||||||
|
c64.SETLFS(1, drivenumber, 1)
|
||||||
|
void c64.OPEN()
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
|
||||||
|
c64.CHKOUT(1)
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
|
||||||
|
repeat size {
|
||||||
|
c64.CHROUT(@(address))
|
||||||
|
address++
|
||||||
|
}
|
||||||
|
|
||||||
|
io_error:
|
||||||
|
c64.CLRCHN()
|
||||||
|
c64.CLOSE(1)
|
||||||
|
return c64.READST()==0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub load(ubyte drivenumber, uword filenameptr, uword address) -> byte {
|
||||||
|
ubyte flen = strlen(filenameptr)
|
||||||
|
filename[0] = '0'
|
||||||
|
filename[1] = ':'
|
||||||
|
memcopy(filenameptr, &filename+2, flen)
|
||||||
|
memcopy(",s,r", &filename+2+flen, 5)
|
||||||
|
c64.SETNAM(flen+6, filename)
|
||||||
|
c64.SETLFS(1, drivenumber, 2)
|
||||||
|
void c64.OPEN()
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
void c64.CHKIN(1)
|
||||||
|
if_cs
|
||||||
|
goto io_error
|
||||||
|
|
||||||
|
do {
|
||||||
|
@(address) = c64.CHRIN()
|
||||||
|
address++
|
||||||
|
} until c64.READST()
|
||||||
|
|
||||||
|
io_error:
|
||||||
|
c64.CLRCHN()
|
||||||
|
c64.CLOSE(1)
|
||||||
|
|
||||||
|
ubyte status = c64.READST()
|
||||||
|
return status==0 or status==64
|
||||||
|
}
|
||||||
|
|
||||||
|
sub delete(ubyte drivenumber, uword filenameptr) {
|
||||||
|
; -- delete a file on the drive
|
||||||
|
ubyte flen = strlen(filenameptr)
|
||||||
|
filename[0] = 's'
|
||||||
|
filename[1] = ':'
|
||||||
|
memcopy(filenameptr, &filename+2, flen+1)
|
||||||
|
c64.SETNAM(flen+2, filename)
|
||||||
|
c64.SETLFS(1, drivenumber, 15)
|
||||||
|
void c64.OPEN()
|
||||||
|
c64.CLRCHN()
|
||||||
|
c64.CLOSE(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub rename(ubyte drivenumber, uword oldfileptr, uword newfileptr) {
|
||||||
|
; -- rename a file on the drive
|
||||||
|
ubyte flen_old = strlen(oldfileptr)
|
||||||
|
ubyte flen_new = strlen(newfileptr)
|
||||||
|
filename[0] = 'r'
|
||||||
|
filename[1] = ':'
|
||||||
|
memcopy(newfileptr, &filename+2, flen_new)
|
||||||
|
filename[flen_new+2] = '='
|
||||||
|
memcopy(oldfileptr, &filename+3+flen_new, flen_old+1)
|
||||||
|
c64.SETNAM(3+flen_new+flen_old, filename)
|
||||||
|
c64.SETLFS(1, drivenumber, 15)
|
||||||
|
void c64.OPEN()
|
||||||
|
c64.CLRCHN()
|
||||||
|
c64.CLOSE(1)
|
||||||
|
}
|
||||||
|
}
|
@ -148,16 +148,16 @@ internal object C64MachineDefinition: IMachineDefinition {
|
|||||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
||||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||||
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
|
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
|
||||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xf
|
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(options.zeropage!=ZeropageType.DONTUSE) {
|
if(options.zeropage!=ZeropageType.DONTUSE) {
|
||||||
// add the other free Zp addresses,
|
// add the free Zp addresses
|
||||||
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
|
// these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
|
||||||
free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e,
|
free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e,
|
||||||
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
|
0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa5, 0xa6,
|
||||||
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
|
0xb0, 0xb1, 0xbe, 0xbf, 0xf9))
|
||||||
} else {
|
} else {
|
||||||
// don't use the zeropage at all
|
// don't use the zeropage at all
|
||||||
free.clear()
|
free.clear()
|
||||||
|
@ -186,11 +186,11 @@ class TestC64Zeropage {
|
|||||||
@Test
|
@Test
|
||||||
fun testFreeSpaces() {
|
fun testFreeSpaces() {
|
||||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
||||||
assertEquals(16, zp1.available())
|
assertEquals(18, zp1.available())
|
||||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false))
|
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false))
|
||||||
assertEquals(89, zp2.available())
|
assertEquals(91, zp2.available())
|
||||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false))
|
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false))
|
||||||
assertEquals(125, zp3.available())
|
assertEquals(127, zp3.available())
|
||||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false))
|
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false))
|
||||||
assertEquals(238, zp4.available())
|
assertEquals(238, zp4.available())
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ class TestC64Zeropage {
|
|||||||
@Test
|
@Test
|
||||||
fun testBasicsafeAllocation() {
|
fun testBasicsafeAllocation() {
|
||||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
||||||
assertEquals(16, zp.available())
|
assertEquals(18, zp.available())
|
||||||
|
|
||||||
assertFailsWith<ZeropageDepletedError> {
|
assertFailsWith<ZeropageDepletedError> {
|
||||||
// in regular zp there aren't 5 sequential bytes free
|
// in regular zp there aren't 5 sequential bytes free
|
||||||
@ -273,16 +273,18 @@ class TestC64Zeropage {
|
|||||||
@Test
|
@Test
|
||||||
fun testEfficientAllocation() {
|
fun testEfficientAllocation() {
|
||||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
||||||
assertEquals(16, zp.available())
|
assertEquals(18, zp.available())
|
||||||
assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors))
|
assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors))
|
||||||
assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors))
|
assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors))
|
||||||
assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null, errors))
|
assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null, errors))
|
||||||
assertEquals(0x94, zp.allocate("", DataType.UWORD, null, errors))
|
assertEquals(0x9b, zp.allocate("", DataType.UWORD, null, errors))
|
||||||
assertEquals(0xa7, zp.allocate("", DataType.UWORD, null, errors))
|
assertEquals(0x9e, zp.allocate("", DataType.UWORD, null, errors))
|
||||||
assertEquals(0xa9, zp.allocate("", DataType.UWORD, null, errors))
|
assertEquals(0xa5, zp.allocate("", DataType.UWORD, null, errors))
|
||||||
assertEquals(0xb5, zp.allocate("", DataType.UWORD, null, errors))
|
assertEquals(0xb0, zp.allocate("", DataType.UWORD, null, errors))
|
||||||
assertEquals(0xf7, zp.allocate("", DataType.UWORD, null, errors))
|
assertEquals(0xbe, zp.allocate("", DataType.UWORD, null, errors))
|
||||||
assertEquals(0x0e, zp.allocate("", DataType.UBYTE, null, errors))
|
assertEquals(0x0e, zp.allocate("", DataType.UBYTE, null, errors))
|
||||||
|
assertEquals(0x92, zp.allocate("", DataType.UBYTE, null, errors))
|
||||||
|
assertEquals(0x96, zp.allocate("", DataType.UBYTE, null, errors))
|
||||||
assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null, errors))
|
assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null, errors))
|
||||||
assertEquals(0, zp.available())
|
assertEquals(0, zp.available())
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
%target c64
|
|
||||||
%import textio
|
|
||||||
%import syslib
|
|
||||||
%zeropage basicsafe
|
|
||||||
%option no_sysinit
|
|
||||||
%launcher none
|
|
||||||
%address 50000
|
|
||||||
|
|
||||||
; This example shows the directory contents of disk drive 8.
|
|
||||||
; You load it with LOAD "diskdir-sys50000",8,1
|
|
||||||
; and then call it with SYS 50000.
|
|
||||||
|
|
||||||
; The only difference with diskdir.p8 is the directives that make this load at 50000.
|
|
||||||
|
|
||||||
%import diskdir
|
|
@ -1,59 +0,0 @@
|
|||||||
%import textio
|
|
||||||
%import syslib
|
|
||||||
%option no_sysinit
|
|
||||||
%zeropage basicsafe
|
|
||||||
|
|
||||||
; This example shows the directory contents of disk drive 8.
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
|
||||||
|
|
||||||
main {
|
|
||||||
sub start() {
|
|
||||||
txt.print("directory of disk drive #8:\n\n")
|
|
||||||
diskdir(8)
|
|
||||||
}
|
|
||||||
|
|
||||||
sub diskdir(ubyte drivenumber) {
|
|
||||||
c64.SETNAM(1, "$")
|
|
||||||
c64.SETLFS(1, drivenumber, 0)
|
|
||||||
void c64.OPEN() ; open 1,8,0,"$"
|
|
||||||
if_cs
|
|
||||||
goto io_error
|
|
||||||
void c64.CHKIN(1) ; use #1 as input channel
|
|
||||||
if_cs
|
|
||||||
goto io_error
|
|
||||||
|
|
||||||
repeat 4 {
|
|
||||||
void c64.CHRIN() ; skip the 4 prologue bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
; while not key pressed / EOF encountered, read data.
|
|
||||||
ubyte status = c64.READST()
|
|
||||||
while not status {
|
|
||||||
txt.print_uw(mkword(c64.CHRIN(), c64.CHRIN()))
|
|
||||||
txt.chrout(' ')
|
|
||||||
ubyte @zp char
|
|
||||||
do {
|
|
||||||
char = c64.CHRIN()
|
|
||||||
txt.chrout(char)
|
|
||||||
} until char==0
|
|
||||||
txt.chrout('\n')
|
|
||||||
void c64.CHRIN() ; skip 2 bytes
|
|
||||||
void c64.CHRIN()
|
|
||||||
status = c64.READST()
|
|
||||||
void c64.STOP()
|
|
||||||
if_nz
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
io_error:
|
|
||||||
status = c64.READST()
|
|
||||||
c64.CLRCHN() ; restore default i/o devices
|
|
||||||
c64.CLOSE(1)
|
|
||||||
|
|
||||||
if status and status != 64 { ; 64=end of file
|
|
||||||
txt.print("\ni/o error, status: ")
|
|
||||||
txt.print_ub(status)
|
|
||||||
txt.chrout('\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +1,42 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import syslib
|
%import diskio
|
||||||
%import floats
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
if diskio.directory(8)
|
||||||
|
txt.print("all good\n")
|
||||||
|
else
|
||||||
|
txt.print("there was an error\n")
|
||||||
|
|
||||||
|
testX()
|
||||||
|
|
||||||
|
if diskio.save(8, "irmen", $0400, 40*25)
|
||||||
|
txt.print("saved ok\n")
|
||||||
|
else
|
||||||
|
txt.print("save error\n")
|
||||||
|
|
||||||
|
diskio.status(8)
|
||||||
|
|
||||||
|
txt.clear_screenchars('?')
|
||||||
|
|
||||||
|
if diskio.load(8, "irmen", $0400)
|
||||||
|
txt.print("load ok\n")
|
||||||
|
else
|
||||||
|
txt.print("load error\n")
|
||||||
|
|
||||||
|
diskio.status(8)
|
||||||
|
|
||||||
|
diskio.rename(8, "irmen", "newirmen")
|
||||||
|
diskio.status(8)
|
||||||
|
diskio.delete(8, "test")
|
||||||
|
diskio.status(8)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
asmsub testX() {
|
asmsub testX() {
|
||||||
%asm {{
|
%asm {{
|
||||||
stx _saveX
|
stx _saveX
|
||||||
@ -24,6 +52,3 @@ _saveX .byte 0
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user