mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +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,
|
||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||
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) {
|
||||
// add the other free Zp addresses,
|
||||
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
|
||||
// add the free Zp addresses
|
||||
// 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,
|
||||
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
|
||||
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
|
||||
0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa5, 0xa6,
|
||||
0xb0, 0xb1, 0xbe, 0xbf, 0xf9))
|
||||
} else {
|
||||
// don't use the zeropage at all
|
||||
free.clear()
|
||||
|
@ -186,11 +186,11 @@ class TestC64Zeropage {
|
||||
@Test
|
||||
fun testFreeSpaces() {
|
||||
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))
|
||||
assertEquals(89, zp2.available())
|
||||
assertEquals(91, zp2.available())
|
||||
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))
|
||||
assertEquals(238, zp4.available())
|
||||
}
|
||||
@ -220,7 +220,7 @@ class TestC64Zeropage {
|
||||
@Test
|
||||
fun testBasicsafeAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false))
|
||||
assertEquals(16, zp.available())
|
||||
assertEquals(18, zp.available())
|
||||
|
||||
assertFailsWith<ZeropageDepletedError> {
|
||||
// in regular zp there aren't 5 sequential bytes free
|
||||
@ -273,16 +273,18 @@ class TestC64Zeropage {
|
||||
@Test
|
||||
fun testEfficientAllocation() {
|
||||
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(0x06, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
assertEquals(0x94, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xa7, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xa9, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xb5, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xf7, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0x9b, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0x9e, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xa5, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xb0, zp.allocate("", DataType.UWORD, null, errors))
|
||||
assertEquals(0xbe, zp.allocate("", DataType.UWORD, 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(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 syslib
|
||||
%import floats
|
||||
%import diskio
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
|
||||
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() {
|
||||
%asm {{
|
||||
stx _saveX
|
||||
@ -24,6 +52,3 @@ _saveX .byte 0
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user