Skip to content

Commit

Permalink
Use metadata files for the load and exec addresses. Use .inf files as…
Browse files Browse the repository at this point in the history
… generated by DiscImageManager
  • Loading branch information
ivanizag committed Aug 26, 2021
1 parent bd98d90 commit aeaee64
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 41 deletions.
26 changes: 11 additions & 15 deletions osCLI.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,20 +162,16 @@ func execOSCLI(env *environment) {
break
}
filename := params[0]
loadAddress := uint16(0x3000) // TODO: retrieve from the metadata
loadAddress := loadAddressNull
if len(params) >= 2 {
i, err := strconv.ParseInt(params[1], 16, 16)
i, err := strconv.ParseInt(params[1], 16, 32)
if err != nil {
env.raiseError(252, "Bad address")
break
}
loadAddress = uint16(i)
}
res, _ := loadFile(env, filename, loadAddress)
if res != osFileFound {
env.raiseError(214, "File not found")
break
loadAddress = uint32(i)
}
loadFile(env, filename, loadAddress)

// case "LINE":
case "MOTOR":
Expand All @@ -191,14 +187,14 @@ func execOSCLI(env *environment) {
break
}
filename := params[0]
loadAddress := uint16(0x3000) // TODO: retrieve from the metadata
execAddress := uint16(0x3100)
res, _ := loadFile(env, filename, loadAddress)
if res != osFileFound {
env.raiseError(214, "File not found")
break
attr := loadFile(env, filename, loadAddressNull)
if attr.fileType == osFileFound {
if attr.hasMetadata {
env.cpu.SetPC(uint16(attr.executionAddress))
} else {
env.raiseError(errorTodo, "Missing metadata file")
}
}
env.cpu.SetPC(execAddress)

case "ROM":
execOSCLIfx(env, 0x8d, strings.Split(args, ","))
Expand Down
140 changes: 114 additions & 26 deletions osFile.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,42 @@ import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)

const (
osNotFound uint8 = 0
osFileFound uint8 = 1
osDirectoryFound uint8 = 2

cbLoadAddress uint16 = 0x2
cbExecutionAddress uint16 = 0x6
cbStartAddressOrSize uint16 = 0xa
cbEndAddressOrAttributes uint16 = 0xe

loadAddressNull uint32 = ^uint32(0)
executionAddressNull uint32 = ^uint32(0)
)

type fileAttributes struct {
fileType uint8
fileSize uint32
hasMetadata bool
loadAddress uint32
executionAddress uint32
}

func execOSFILE(env *environment) {
a, x, y, p := env.cpu.GetAXYP()

// See: http://beebwiki.mdfs.net/OSFILE
controlBlock := uint16(x) + uint16(y)<<8
filenameAddress := env.mem.peekWord(controlBlock)
loadAddress := env.mem.peeknbytes(controlBlock+0x2, 4)
executionAddress := env.mem.peeknbytes(controlBlock+0x6, 4)
startAddress := env.mem.peeknbytes(controlBlock+0xa, 4)
endAddress := env.mem.peeknbytes(controlBlock+0xe, 4)
loadAddress := uint32(env.mem.peeknbytes(controlBlock+cbLoadAddress, 4))
executionAddress := uint32(env.mem.peeknbytes(controlBlock+cbExecutionAddress, 4))
startAddress := uint32(env.mem.peeknbytes(controlBlock+cbStartAddressOrSize, 4))
endAddress := uint32(env.mem.peeknbytes(controlBlock+cbEndAddressOrAttributes, 4))

filename := env.mem.getString(filenameAddress, 0x0d)
filesize := endAddress - startAddress
Expand All @@ -40,25 +58,26 @@ func execOSFILE(env *environment) {
err := ioutil.WriteFile(filename, data, 0644)
if err != nil {
env.raiseError(errorTodo, err.Error())
newA = osNotFound
} else {
newA = osFileFound
}
newA = 1 // File found
case 5:
option = "File info"
/*
Read a file’s catalogue information, with the file
type returned in the accumulator. The information
is written to the parameter block.
*/
info, err := os.Stat(filename)

if err == nil {
filesize = uint64(info.Size())
if info.IsDir() {
newA = 2 // Directory found
} else {
newA = 1 // File found
attr := getFileAttributes(env, filename)
if attr.fileType != osNotFound {
env.mem.pokenbytes(controlBlock+cbStartAddressOrSize, 4, uint64(attr.fileSize))
if attr.hasMetadata {
env.mem.pokenbytes(controlBlock+cbLoadAddress, 4, uint64(attr.loadAddress))
env.mem.pokenbytes(controlBlock+cbExecutionAddress, 4, uint64(attr.executionAddress))
}
}
newA = attr.fileType

case 0xff: // Load file into memory
option = "Load file"
Expand All @@ -72,36 +91,105 @@ func execOSFILE(env *environment) {
*/
useLoadAddress := (executionAddress & 0xff) == 0
if !useLoadAddress {
env.notImplemented("Loading files on their own load address")
loadAddress = loadAddressNull
}
newA, filesize = loadFile(env, filename, uint16(loadAddress))

attr := loadFile(env, filename, loadAddress)
env.mem.pokenbytes(controlBlock+cbStartAddressOrSize, 4, uint64(attr.fileSize))
newA = attr.fileType

default:
env.notImplemented(fmt.Sprintf("OSFILE(A=%02x)", a))
}

env.mem.pokenbytes(controlBlock+0xa, 4, filesize)
env.mem.pokeWord(controlBlock+0x3, 0x00 /*attributes*/)
env.mem.pokeWord(controlBlock+cbEndAddressOrAttributes, 0x00 /*attributes*/)

env.cpu.SetAXYP(newA, x, y, p)
env.log(fmt.Sprintf("OSFILE('%s',A=%02x,FCB=%04x,FILE=%s,SIZE=%v) => (A=%v,SIZE=%v)",
option, a, controlBlock, filename, filesize, newA, filesize))
env.log(fmt.Sprintf("OSFILE('%s',A=%02x,FCB=%04x,FILE=%s) => %v",
option, a, controlBlock, filename, newA))

}

func loadFile(env *environment, filename string, loadAddress uint16) (uint8, uint64) {
func loadFile(env *environment, filename string, loadAddress uint32) fileAttributes {
attr := getFileAttributes(env, filename)
if attr.fileType == osNotFound {
return attr
}
if attr.fileType == osDirectoryFound {
env.raiseError(errorTodo, "Directory found")
return attr
}

if loadAddress == loadAddressNull {
if !attr.hasMetadata {
env.raiseError(errorTodo, "Missing metadata file")
attr.fileType = osNotFound
return attr
}
loadAddress = uint32(attr.loadAddress)
}
data, err := os.ReadFile(filename)
if err != nil {
env.raiseError(errorTodo, err.Error())
attr.fileType = osNotFound
return attr
}

// NOTE: There is no maxLength?
env.mem.storeSlice(uint16(loadAddress), uint16(len(data)), data)
return attr
}

func getFileAttributes(env *environment, filename string) fileAttributes {
var attr fileAttributes

fileInfo, err := os.Stat(filename)
if errors.Is(err, os.ErrNotExist) {
attr.fileType = osNotFound
env.raiseError(214, "File not found")
return osNotFound, 0
return attr
}
if err != nil {
attr.fileType = osNotFound
env.raiseError(errorTodo, err.Error())
return osNotFound, 0
return attr
}

// NOTE: There is no maxLength?
env.mem.storeSlice(uint16(loadAddress), uint16(len(data)), data)
filesize := uint64(len(data))
return osFileFound, filesize
attr.fileSize = uint32(fileInfo.Size())
attr.fileType = osFileFound
if fileInfo.IsDir() {
attr.fileType = osDirectoryFound
}

/*
Search metadata file "{filename}.inf" looking like:
$.BasObj 003000 003100 005000 00 CRC32=614721E1
*/
attr.hasMetadata = false
data, err := os.ReadFile(filename + ".inf")
if errors.Is(err, os.ErrNotExist) {
return attr
}
parts := strings.Fields(string(data))
if len(parts) < 3 {
env.log(fmt.Sprintf("Invalid format for metadata file %s.inf, missing fields", filename))
return attr
}

i, err := strconv.ParseInt(parts[1], 16, 32)
if err != nil {
env.log(fmt.Sprintf("Invalid format for metadata file %s.inf, bad load address", filename))
return attr
}
attr.loadAddress = uint32(i)

i, err = strconv.ParseInt(parts[2], 16, 32)
if err != nil {
env.log(fmt.Sprintf("Invalid format for metadata file %s.inf, bad exec address", filename))
return attr
}
attr.executionAddress = uint32(i)

attr.hasMetadata = true
return attr
}

0 comments on commit aeaee64

Please sign in to comment.