mirror of
https://github.com/zellyn/diskii.git
synced 2024-06-07 22:29:34 +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")
|
// 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 location uint16 // flag for starting location in memory
|
||||||
var rawControlCodes bool // flag for whether to skip escaping control codes
|
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
|
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
|
// nakedosCmd represents the nakedos command
|
||||||
var nakedosCmd = &cobra.Command{
|
var nakedosCmd = &cobra.Command{
|
||||||
|
@ -16,3 +23,107 @@ with NakedOS (and Super-Mon) disks`,
|
||||||
func init() {
|
func init() {
|
||||||
RootCmd.AddCommand(nakedosCmd)
|
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
|
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.
|
// high-level operations on files and directories.
|
||||||
type operator struct {
|
type Operator struct {
|
||||||
sd disk.SectorDisk
|
SD disk.SectorDisk
|
||||||
sm SectorMap
|
SM SectorMap
|
||||||
st SymbolTable
|
ST SymbolTable
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ disk.Operator = operator{}
|
var _ disk.Operator = Operator{}
|
||||||
|
|
||||||
// operatorName is the keyword name for the operator that undestands
|
// operatorName is the keyword name for the operator that undestands
|
||||||
// NakedOS/Super-Mon disks.
|
// NakedOS/Super-Mon disks.
|
||||||
const operatorName = "nakedos"
|
const operatorName = "nakedos"
|
||||||
|
|
||||||
// Name returns the name of the operator.
|
// Name returns the name of the Operator.
|
||||||
func (o operator) Name() string {
|
func (o Operator) Name() string {
|
||||||
return operatorName
|
return operatorName
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSubdirs returns true if the underlying operating system on the
|
// HasSubdirs returns true if the underlying operating system on the
|
||||||
// disk allows subdirectories.
|
// disk allows subdirectories.
|
||||||
func (o operator) HasSubdirs() bool {
|
func (o Operator) HasSubdirs() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catalog returns a catalog of disk entries. subdir should be empty
|
// Catalog returns a catalog of disk entries. subdir should be empty
|
||||||
// for operating systems that do not support subdirectories.
|
// 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
|
var descs []disk.Descriptor
|
||||||
sectorsByFile := o.sm.SectorsByFile()
|
sectorsByFile := o.SM.SectorsByFile()
|
||||||
for file := byte(1); file < FileReserved; file++ {
|
for file := byte(1); file < FileReserved; file++ {
|
||||||
l := len(sectorsByFile[file])
|
l := len(sectorsByFile[file])
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
descs = append(descs, disk.Descriptor{
|
descs = append(descs, disk.Descriptor{
|
||||||
Name: NameForFile(file, o.st),
|
Name: NameForFile(file, o.ST),
|
||||||
Fullname: FullnameForFile(file, o.st),
|
Fullname: FullnameForFile(file, o.ST),
|
||||||
Sectors: l,
|
Sectors: l,
|
||||||
Length: l * 256,
|
Length: l * 256,
|
||||||
Locked: false,
|
Locked: false,
|
||||||
|
@ -687,12 +687,12 @@ func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFile retrieves a file by name.
|
// GetFile retrieves a file by name.
|
||||||
func (o operator) GetFile(filename string) (disk.FileInfo, error) {
|
func (o Operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||||
file, err := o.st.FileForName(filename)
|
file, err := o.ST.FileForName(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return disk.FileInfo{}, err
|
return disk.FileInfo{}, err
|
||||||
}
|
}
|
||||||
data, err := o.sm.ReadFile(o.sd, file)
|
data, err := o.SM.ReadFile(o.SD, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return disk.FileInfo{}, fmt.Errorf("error reading file DF%02x: %v", file, err)
|
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)
|
return disk.FileInfo{}, fmt.Errorf("file DF%02x not fount", file)
|
||||||
}
|
}
|
||||||
desc := disk.Descriptor{
|
desc := disk.Descriptor{
|
||||||
Name: NameForFile(file, o.st),
|
Name: NameForFile(file, o.ST),
|
||||||
Sectors: len(data) / 256,
|
Sectors: len(data) / 256,
|
||||||
Length: len(data),
|
Length: len(data),
|
||||||
Locked: false,
|
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
|
// Delete deletes a file by name. It returns true if the file was
|
||||||
// deleted, false if it didn't exist.
|
// deleted, false if it didn't exist.
|
||||||
func (o operator) Delete(filename string) (bool, error) {
|
func (o Operator) Delete(filename string) (bool, error) {
|
||||||
file, err := o.st.FileForName(filename)
|
file, err := o.ST.FileForName(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
existed := len(o.sm.SectorsForFile(file)) > 0
|
existed := len(o.SM.SectorsForFile(file)) > 0
|
||||||
o.sm.Delete(file)
|
o.SM.Delete(file)
|
||||||
if err := o.sm.Persist(o.sd); err != nil {
|
if err := o.SM.Persist(o.SD); err != nil {
|
||||||
return existed, err
|
return existed, err
|
||||||
}
|
}
|
||||||
if o.st != nil {
|
if o.ST != nil {
|
||||||
changed := o.st.DeleteSymbol(filename)
|
changed := o.ST.DeleteSymbol(filename)
|
||||||
if changed {
|
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
|
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
|
// PutFile writes a file by name. If the file exists and overwrite
|
||||||
// is false, it returns with an error. Otherwise it returns true if
|
// is false, it returns with an error. Otherwise it returns true if
|
||||||
// an existing file was overwritten.
|
// 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 {
|
if fileInfo.Descriptor.Type != disk.FiletypeBinary {
|
||||||
return false, fmt.Errorf("%s: only binary file type supported", operatorName)
|
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))
|
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 {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if symbol != "" {
|
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")
|
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 {
|
if _, err := encodeSymbol(symbol); err != nil {
|
||||||
|
@ -763,20 +763,20 @@ func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if numFile == 0 {
|
if numFile == 0 {
|
||||||
numFile = o.sm.FirstFreeFile()
|
numFile = o.SM.FirstFreeFile()
|
||||||
if numFile == 0 {
|
if numFile == 0 {
|
||||||
return false, fmt.Errorf("all files already used")
|
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 {
|
if err != nil {
|
||||||
return existed, err
|
return existed, err
|
||||||
}
|
}
|
||||||
if namedFile != numFile && symbol != "" {
|
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
|
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
|
return existed, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,11 +794,11 @@ func operatorFactory(sd disk.SectorDisk) (disk.Operator, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
op := operator{sd: sd, sm: sm}
|
op := Operator{SD: sd, SM: sm}
|
||||||
|
|
||||||
st, err := sm.ReadSymbolTable(sd)
|
st, err := sm.ReadSymbolTable(sd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
op.st = st
|
op.ST = st
|
||||||
}
|
}
|
||||||
|
|
||||||
return op, nil
|
return op, nil
|
||||||
|
|
Loading…
Reference in New Issue
Block a user