mirror of
https://github.com/zellyn/diskii.git
synced 2024-11-21 08:32:21 +00:00
add nakedos mkhello
command; export more things
This commit is contained in:
parent
2d994dec8d
commit
34a26dd1d6
@ -34,7 +34,7 @@ func init() {
|
||||
// applesoftCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
// ----- applesoft decode commane -------------------------------------------
|
||||
// ----- applesoft decode command -------------------------------------------
|
||||
|
||||
var location uint16 // flag for starting location in memory
|
||||
var rawControlCodes bool // flag for whether to skip escaping control codes
|
||||
|
113
cmd/nakedos.go
113
cmd/nakedos.go
@ -2,7 +2,14 @@
|
||||
|
||||
package cmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/zellyn/diskii/lib/disk"
|
||||
"github.com/zellyn/diskii/lib/supermon"
|
||||
)
|
||||
|
||||
// nakedosCmd represents the nakedos command
|
||||
var nakedosCmd = &cobra.Command{
|
||||
@ -16,3 +23,107 @@ with NakedOS (and Super-Mon) disks`,
|
||||
func init() {
|
||||
RootCmd.AddCommand(nakedosCmd)
|
||||
}
|
||||
|
||||
// ----- mkhello command ----------------------------------------------------
|
||||
|
||||
var address uint16 // flag for address to load at
|
||||
var start uint16 // flag for address to start execution at
|
||||
const helloName = "FHELLO" // filename to use (if Super-Mon)
|
||||
|
||||
// mkhelloCmd represents the mkhello command
|
||||
var mkhelloCmd = &cobra.Command{
|
||||
Use: "mkhello <disk-image> filename",
|
||||
Short: "create an FHELLO program that loads and runs another file",
|
||||
Long: `
|
||||
mkhello creates file DF01:FHELLO that loads and runs another program at a specific address.
|
||||
|
||||
Examples:
|
||||
mkhello test.dsk FDEMO # load and run FDEMO at the default address, then jump to the start of the loaded code.
|
||||
mkhello test.dsk --address 0x2000 --start 0x2100 DF06 # load and run file DF06 at address 0x2000, and jump to 0x2100.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := runMkhello(args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
os.Exit(-1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
nakedosCmd.AddCommand(mkhelloCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
mkhelloCmd.Flags().Uint16VarP(&address, "address", "a", 0x6000, "memory location to load code at")
|
||||
mkhelloCmd.Flags().Uint16VarP(&start, "start", "s", 0x6000, "memory location to jump to")
|
||||
}
|
||||
|
||||
// runMkhello performs the actual mkhello logic.
|
||||
func runMkhello(args []string) error {
|
||||
if len(args) != 2 {
|
||||
return fmt.Errorf("usage: diskii mkhello <disk image> <file-to-load>")
|
||||
}
|
||||
if address%256 != 0 {
|
||||
return fmt.Errorf("address %d (%04X) not on a page boundary", address, address)
|
||||
}
|
||||
if start < address {
|
||||
return fmt.Errorf("start address %d (%04X) < load address %d (%04X)", start, start, address, address)
|
||||
}
|
||||
sd, err := disk.Open(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op, err := disk.OperatorFor(sd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if op.Name() != "nakedos" {
|
||||
return fmt.Errorf("mkhello only works on disks of type %q; got %q", "nakedos", op.Name())
|
||||
}
|
||||
nakOp, ok := op.(supermon.Operator)
|
||||
if !ok {
|
||||
return fmt.Errorf("internal error: cannot cast to expected supermon.Operator type")
|
||||
}
|
||||
addr, symbolAddr, _, err := nakOp.ST.FilesForCompoundName(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if addr == 0 && symbolAddr == 0 {
|
||||
return fmt.Errorf("cannot parse %q as valid filename", args[1])
|
||||
}
|
||||
toLoad := addr
|
||||
if addr == 0 {
|
||||
toLoad = symbolAddr
|
||||
}
|
||||
contents := []byte{
|
||||
0x20, 0x40, 0x03, // JSR NAKEDOS
|
||||
0x6D, 0x01, 0xDC, // ADC NKRDFILE
|
||||
0x2C, toLoad, 0xDF, // BIT ${file number to load}
|
||||
0x2C, 0x00, byte(address >> 8), // BIT ${target page}
|
||||
0xF8, // CLD
|
||||
0x4C, byte(start), byte(start >> 8), // JMP ${target page}
|
||||
}
|
||||
fileInfo := disk.FileInfo{
|
||||
Descriptor: disk.Descriptor{
|
||||
Name: fmt.Sprintf("DF01:%s", helloName),
|
||||
Length: len(contents),
|
||||
Type: disk.FiletypeBinary,
|
||||
},
|
||||
Data: contents,
|
||||
}
|
||||
_, err = op.PutFile(fileInfo, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Create(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sd.Write(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -639,44 +639,44 @@ func (st SymbolTable) FilesForCompoundName(filename string) (numFile byte, named
|
||||
return numFile, namedFile, parts[1], nil
|
||||
}
|
||||
|
||||
// operator is a disk.Operator - an interface for performing
|
||||
// Operator is a disk.Operator - an interface for performing
|
||||
// high-level operations on files and directories.
|
||||
type operator struct {
|
||||
sd disk.SectorDisk
|
||||
sm SectorMap
|
||||
st SymbolTable
|
||||
type Operator struct {
|
||||
SD disk.SectorDisk
|
||||
SM SectorMap
|
||||
ST SymbolTable
|
||||
}
|
||||
|
||||
var _ disk.Operator = operator{}
|
||||
var _ disk.Operator = Operator{}
|
||||
|
||||
// operatorName is the keyword name for the operator that undestands
|
||||
// NakedOS/Super-Mon disks.
|
||||
const operatorName = "nakedos"
|
||||
|
||||
// Name returns the name of the operator.
|
||||
func (o operator) Name() string {
|
||||
// Name returns the name of the Operator.
|
||||
func (o Operator) Name() string {
|
||||
return operatorName
|
||||
}
|
||||
|
||||
// HasSubdirs returns true if the underlying operating system on the
|
||||
// disk allows subdirectories.
|
||||
func (o operator) HasSubdirs() bool {
|
||||
func (o Operator) HasSubdirs() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Catalog returns a catalog of disk entries. subdir should be empty
|
||||
// for operating systems that do not support subdirectories.
|
||||
func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||
func (o Operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||
var descs []disk.Descriptor
|
||||
sectorsByFile := o.sm.SectorsByFile()
|
||||
sectorsByFile := o.SM.SectorsByFile()
|
||||
for file := byte(1); file < FileReserved; file++ {
|
||||
l := len(sectorsByFile[file])
|
||||
if l == 0 {
|
||||
continue
|
||||
}
|
||||
descs = append(descs, disk.Descriptor{
|
||||
Name: NameForFile(file, o.st),
|
||||
Fullname: FullnameForFile(file, o.st),
|
||||
Name: NameForFile(file, o.ST),
|
||||
Fullname: FullnameForFile(file, o.ST),
|
||||
Sectors: l,
|
||||
Length: l * 256,
|
||||
Locked: false,
|
||||
@ -687,12 +687,12 @@ func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||
}
|
||||
|
||||
// GetFile retrieves a file by name.
|
||||
func (o operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
file, err := o.st.FileForName(filename)
|
||||
func (o Operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
file, err := o.ST.FileForName(filename)
|
||||
if err != nil {
|
||||
return disk.FileInfo{}, err
|
||||
}
|
||||
data, err := o.sm.ReadFile(o.sd, file)
|
||||
data, err := o.SM.ReadFile(o.SD, file)
|
||||
if err != nil {
|
||||
return disk.FileInfo{}, fmt.Errorf("error reading file DF%02x: %v", file, err)
|
||||
}
|
||||
@ -700,7 +700,7 @@ func (o operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
return disk.FileInfo{}, fmt.Errorf("file DF%02x not fount", file)
|
||||
}
|
||||
desc := disk.Descriptor{
|
||||
Name: NameForFile(file, o.st),
|
||||
Name: NameForFile(file, o.ST),
|
||||
Sectors: len(data) / 256,
|
||||
Length: len(data),
|
||||
Locked: false,
|
||||
@ -718,20 +718,20 @@ func (o operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
|
||||
// Delete deletes a file by name. It returns true if the file was
|
||||
// deleted, false if it didn't exist.
|
||||
func (o operator) Delete(filename string) (bool, error) {
|
||||
file, err := o.st.FileForName(filename)
|
||||
func (o Operator) Delete(filename string) (bool, error) {
|
||||
file, err := o.ST.FileForName(filename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
existed := len(o.sm.SectorsForFile(file)) > 0
|
||||
o.sm.Delete(file)
|
||||
if err := o.sm.Persist(o.sd); err != nil {
|
||||
existed := len(o.SM.SectorsForFile(file)) > 0
|
||||
o.SM.Delete(file)
|
||||
if err := o.SM.Persist(o.SD); err != nil {
|
||||
return existed, err
|
||||
}
|
||||
if o.st != nil {
|
||||
changed := o.st.DeleteSymbol(filename)
|
||||
if o.ST != nil {
|
||||
changed := o.ST.DeleteSymbol(filename)
|
||||
if changed {
|
||||
if err := o.sm.WriteSymbolTable(o.sd, o.st); err != nil {
|
||||
if err := o.SM.WriteSymbolTable(o.SD, o.ST); err != nil {
|
||||
return existed, err
|
||||
}
|
||||
}
|
||||
@ -742,7 +742,7 @@ func (o operator) Delete(filename string) (bool, error) {
|
||||
// PutFile writes a file by name. If the file exists and overwrite
|
||||
// is false, it returns with an error. Otherwise it returns true if
|
||||
// an existing file was overwritten.
|
||||
func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool, err error) {
|
||||
func (o Operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool, err error) {
|
||||
if fileInfo.Descriptor.Type != disk.FiletypeBinary {
|
||||
return false, fmt.Errorf("%s: only binary file type supported", operatorName)
|
||||
}
|
||||
@ -750,12 +750,12 @@ func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
|
||||
return false, fmt.Errorf("mismatch between FileInfo.Descriptor.Length (%d) and actual length of FileInfo.Data field (%d)", fileInfo.Descriptor.Length, len(fileInfo.Data))
|
||||
}
|
||||
|
||||
numFile, namedFile, symbol, err := o.st.FilesForCompoundName(fileInfo.Descriptor.Name)
|
||||
numFile, namedFile, symbol, err := o.ST.FilesForCompoundName(fileInfo.Descriptor.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if symbol != "" {
|
||||
if o.st == nil {
|
||||
if o.ST == nil {
|
||||
return false, fmt.Errorf("cannot use symbolic names on disks without valid symbol tables in files 0x03 and 0x04")
|
||||
}
|
||||
if _, err := encodeSymbol(symbol); err != nil {
|
||||
@ -763,20 +763,20 @@ func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
|
||||
}
|
||||
}
|
||||
if numFile == 0 {
|
||||
numFile = o.sm.FirstFreeFile()
|
||||
numFile = o.SM.FirstFreeFile()
|
||||
if numFile == 0 {
|
||||
return false, fmt.Errorf("all files already used")
|
||||
}
|
||||
}
|
||||
existed, err = o.sm.WriteFile(o.sd, numFile, fileInfo.Data, overwrite)
|
||||
existed, err = o.SM.WriteFile(o.SD, numFile, fileInfo.Data, overwrite)
|
||||
if err != nil {
|
||||
return existed, err
|
||||
}
|
||||
if namedFile != numFile && symbol != "" {
|
||||
if err := o.st.AddSymbol(symbol, 0xDF00+uint16(numFile)); err != nil {
|
||||
if err := o.ST.AddSymbol(symbol, 0xDF00+uint16(numFile)); err != nil {
|
||||
return existed, err
|
||||
}
|
||||
if err := o.sm.WriteSymbolTable(o.sd, o.st); err != nil {
|
||||
if err := o.SM.WriteSymbolTable(o.SD, o.ST); err != nil {
|
||||
return existed, err
|
||||
}
|
||||
}
|
||||
@ -794,11 +794,11 @@ func operatorFactory(sd disk.SectorDisk) (disk.Operator, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
op := operator{sd: sd, sm: sm}
|
||||
op := Operator{SD: sd, SM: sm}
|
||||
|
||||
st, err := sm.ReadSymbolTable(sd)
|
||||
if err == nil {
|
||||
op.st = st
|
||||
op.ST = st
|
||||
}
|
||||
|
||||
return op, nil
|
||||
|
Loading…
Reference in New Issue
Block a user