Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.

Commit e83a8b5

Browse files
authored
Merge pull request #176 from skx/175-a1
Allow the BDOS and BIOS addresses to be changed
2 parents 41d6383 + ad25431 commit e83a8b5

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

cpm/cpm.go

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"log/slog"
1515
"os"
1616
"path/filepath"
17+
"strconv"
1718
"strings"
1819
"time"
1920

@@ -147,6 +148,16 @@ type CPM struct {
147148
// the programs it launches.
148149
start uint16
149150

151+
// biosAddress contains the address of the BIOS we've faked.
152+
//
153+
// This might need to be moved, in rare situations.
154+
biosAddress uint16
155+
156+
// bdosAddress contains the address of the fake BDOS we've deployed.
157+
//
158+
// This might need to be moved, in rare situations.
159+
bdosAddress uint16
160+
150161
// BDOSSyscalls contains details of the BDOS syscalls we
151162
// know how to emulate, indexed by their ID.
152163
BDOSSyscalls map[uint8]CPMHandler
@@ -536,6 +547,24 @@ func New(options ...cpmoption) (*CPM, error) {
536547
return nil, err
537548
}
538549

550+
// Helper to return a number, if it is present in the environment
551+
envNumber := func(name string, defValue uint16) uint16 {
552+
553+
val := os.Getenv(name)
554+
if val == "" {
555+
return defValue
556+
}
557+
558+
// base is implied, so "0xFEFE" works.
559+
num, err := strconv.ParseInt(val, 00, 32)
560+
if err != nil {
561+
return defValue
562+
}
563+
564+
// Truncate.
565+
return uint16(num & 0xFFFF)
566+
}
567+
539568
// Create the emulator object and return it
540569
tmp := &CPM{
541570
BDOSSyscalls: bdos,
@@ -549,6 +578,8 @@ func New(options ...cpmoption) (*CPM, error) {
549578
prnPath: "printer.log", // default
550579
start: 0x0100,
551580
launchTime: time.Now(),
581+
biosAddress: envNumber("BIOS_ADDRESS", 0xCE00),
582+
bdosAddress: envNumber("BDOS_ADDRESS", 0xC000),
552583
}
553584

554585
// Allow options to override our defaults
@@ -587,6 +618,20 @@ func (cpm *CPM) GetCCPName() string {
587618
return cpm.ccp
588619
}
589620

621+
// GetBIOSAddress returns the address the fake BIOS is deployed at.
622+
//
623+
// This is used for the startup banner.
624+
func (cpm *CPM) GetBIOSAddress() uint16 {
625+
return cpm.biosAddress
626+
}
627+
628+
// GetBDOSAddress returns the address the fake BDOS is deployed at.
629+
//
630+
// This is used for the startup banner.
631+
func (cpm *CPM) GetBDOSAddress() uint16 {
632+
return cpm.bdosAddress
633+
}
634+
590635
// LogNoisy enables logging support for each of the functions which
591636
// would otherwise be disabled
592637
func (cpm *CPM) LogNoisy() {
@@ -646,18 +691,25 @@ func (cpm *CPM) LoadBinary(filename string) error {
646691
}
647692

648693
// fixupRAM is misnamed - but it patches the RAM with Z80 code to
649-
// handle "badly behaved" programs that invoke CP/M functions via RST XX
650-
// instructions, rather than calls to 0x0005
694+
// handle "badly behaved" programs that invoke CP/M functions by working out
695+
// the address of the BIOS/BDOS and jumping there directly.
651696
//
652697
// We put some code to call the handlers via faked OUT 0xFF,N - where N
653698
// is the syscall to run.
654699
//
655700
// The precise region we patch is unimportant, but we want to make sure
656701
// we don't overlap with our CCP, or "large programs" loaded at 0x0100.
702+
//
703+
// We store the addresses we can use in the cpm-structure, and they can
704+
// be changed by the user via the BIOS_ADDRESS and BDOS_ADDRESS environmental
705+
// variables.
657706
func (cpm *CPM) fixupRAM() {
658707
i := 0
659-
BIOS := 0xFE00
660-
BDOS := 0xF000
708+
709+
// The two addresses which are important
710+
BIOS := int(cpm.biosAddress)
711+
BDOS := int(cpm.bdosAddress)
712+
661713
NENTRY := 30
662714

663715
SETMEM := func(a int, v int) {
@@ -808,8 +860,8 @@ func (cpm *CPM) Execute(args []string) error {
808860
// Set the same value in RAM
809861
cpm.Memory.Set(0x0004, cpm.CPU.States.BC.Lo)
810862

811-
BIOS := uint16(0xFE00)
812-
BDOS := uint16(0xF000)
863+
BIOS := cpm.biosAddress
864+
BDOS := cpm.bdosAddress
813865

814866
// Setup our breakpoints.
815867
//

cpm/cpm_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ func TestSimple(t *testing.T) {
5858
t.Fatalf("ccp name mismatch!")
5959
}
6060

61+
// Ensure our BDOS and BIOS don't equal each other
62+
if obj.GetBDOSAddress() == obj.GetBIOSAddress() {
63+
t.Fatalf("BIOS and BDOS should be different!")
64+
}
65+
6166
// Create a temporary file with our "RET" program in it.
6267
var file *os.File
6368
file, err = os.CreateTemp("", "tst-*.com")

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ func main() {
358358
}
359359

360360
// Show a startup-banner.
361-
fmt.Printf("\ncpmulator %s\r\nCCP:%s input driver:%s output driver:%s\n", cpmver.GetVersionString(), obj.GetCCPName(), obj.GetInputDriver().GetName(), obj.GetOutputDriver().GetName())
361+
fmt.Printf("\ncpmulator %s\r\nConsole input:%s Console output:%s BIOS:0x%04X BDOS:0x%04X CCP:%s\n", cpmver.GetVersionString(), obj.GetInputDriver().GetName(), obj.GetOutputDriver().GetName(), obj.GetBIOSAddress(), obj.GetBDOSAddress(), obj.GetCCPName())
362362

363363
// We will load AUTOEXEC.SUB, once, if it exists (*)
364364
//

0 commit comments

Comments
 (0)