2016-12-09 03:18:09 +00:00
|
|
|
// Copyright © 2016 Zellyn Hunter <zellyn@gmail.com>
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
2016-12-10 04:08:47 +00:00
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
"github.com/zellyn/diskii/disk"
|
|
|
|
"github.com/zellyn/diskii/supermon"
|
|
|
|
"github.com/zellyn/diskii/types"
|
|
|
|
)
|
2016-12-10 04:08:47 +00:00
|
|
|
|
|
|
|
const helloName = "FHELLO" // filename to use (if Super-Mon)
|
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
type NakedOSCmd struct {
|
|
|
|
Mkhello MkHelloCmd `kong:"cmd,help='Create an FHELLO program that loads and runs another file.'"`
|
|
|
|
}
|
2016-12-10 04:08:47 +00:00
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
// Help shows extended help on NakedOS/Super-Mon.
|
|
|
|
func (n NakedOSCmd) Help() string {
|
|
|
|
return `NakedOS and Super-Mon were created by the amazing Martin Haye. For more information see:
|
|
|
|
Source/docs: https://bitbucket.org/martin.haye/super-mon/
|
|
|
|
Presentation: https://www.kansasfest.org/2012/08/2010-haye-nakedos/`
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
type MkHelloCmd struct {
|
|
|
|
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
|
2016-12-10 04:08:47 +00:00
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to modify.'"`
|
|
|
|
Filename string `kong:"arg,required,help='Name of NakedOS file to load.'"`
|
2016-12-10 04:08:47 +00:00
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
Address uint16 `kong:"type='anybaseuint16',default='0x6000',help='Address to load the code at.'"`
|
|
|
|
Start uint16 `kong:"type='anybaseuint16',default='0xFFFF',help='Address to jump to. Defaults to 0xFFFF, which means “same as address flag”'"`
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
|
|
|
|
2021-08-01 02:10:44 +00:00
|
|
|
func (m MkHelloCmd) Help() string {
|
|
|
|
return `This command creates a very short DF01:FHELLO program that simply loads another program of your choice.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
# Load and run FDEMO at the default address, then jump to the start of the loaded code.
|
|
|
|
mkhello test.dsk FDEMO
|
|
|
|
|
|
|
|
# Load and run file DF06 at address 0x2000, and jump to 0x2100.
|
|
|
|
mkhello test.dsk --address 0x2000 --start 0x2100 DF06`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MkHelloCmd) Run(globals *types.Globals) error {
|
|
|
|
if m.Start == 0xFFFF {
|
|
|
|
m.Start = m.Address
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
|
|
|
|
if m.Address%256 != 0 {
|
|
|
|
return fmt.Errorf("address %d (%04X) not on a page boundary", m.Address, m.Address)
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
if m.Start < m.Address {
|
|
|
|
return fmt.Errorf("start address %d (%04X) < load address %d (%04X)", m.Start, m.Start, m.Address, m.Address)
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
|
|
|
|
op, order, err := disk.OpenFilename(m.DiskImage, m.Order, "auto", globals.DiskOperatorFactories, globals.Debug)
|
2016-12-10 04:08:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
|
2016-12-10 04:08:47 +00:00
|
|
|
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 {
|
2021-08-01 02:10:44 +00:00
|
|
|
return fmt.Errorf("internal error: cannot cast to expected supermon.Operator type (got %T)", op)
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
addr, symbolAddr, _, err := nakOp.ST.FilesForCompoundName(m.Filename)
|
2016-12-10 04:08:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if addr == 0 && symbolAddr == 0 {
|
2021-08-01 02:10:44 +00:00
|
|
|
return fmt.Errorf("cannot parse %q as valid filename", m.Filename)
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
|
|
|
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}
|
2021-08-01 02:10:44 +00:00
|
|
|
0x2C, 0x00, byte(m.Address >> 8), // BIT ${target page}
|
|
|
|
0xD8, // CLD
|
|
|
|
0x4C, byte(m.Start), byte(m.Start >> 8), // JMP ${target page}
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
fileInfo := types.FileInfo{
|
|
|
|
Descriptor: types.Descriptor{
|
2016-12-10 04:08:47 +00:00
|
|
|
Name: fmt.Sprintf("DF01:%s", helloName),
|
|
|
|
Length: len(contents),
|
2021-08-01 02:10:44 +00:00
|
|
|
Type: types.FiletypeBinary,
|
2016-12-10 04:08:47 +00:00
|
|
|
},
|
|
|
|
Data: contents,
|
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
_ = fileInfo
|
|
|
|
|
2016-12-10 04:08:47 +00:00
|
|
|
_, err = op.PutFile(fileInfo, true)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-01 02:10:44 +00:00
|
|
|
|
|
|
|
return disk.WriteBack(m.DiskImage, op, order, true)
|
2016-12-10 04:08:47 +00:00
|
|
|
}
|