From 6cfbee2e01a9efa620ab43321813bcedbc100747 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Tue, 16 Apr 2024 06:05:06 +0300 Subject: [PATCH] Implement sequential file read This pull-request implements the sequential block-read operation, and closes #22. With this I can restore thes aved-state I created in #23: ``` >restore Load SAVE disk then enter file name. (default file name is ZORK1.SAV). Type to continue > FOO Load Game Disk if it was removed. Type to continue > Ok. >inventory You are carrying: A glass bottle The glass bottle contains: A quantity of water A leaflet >look Kitchen You are in the kitchen of the white house. A table seems to have been used recently for the preparation of food. A passage leads to the west and a dark staircase can be seen leading upward. A dark chimney leads down and to the east is a small window which is open. On the table is an elongated brown sack, smelling of hot peppers. >quit Your score is 10 (total of 350 points), in 20 moves. This gives you the rank of Beginner. Do you wish to leave the game? (Y is affirmative): >y ``` --- cpm/cpm.go | 4 +++ cpm/cpm_syscalls.go | 73 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/cpm/cpm.go b/cpm/cpm.go index 9e68279..8bc6bc2 100644 --- a/cpm/cpm.go +++ b/cpm/cpm.go @@ -149,6 +149,10 @@ func New(filename string, logger *slog.Logger) *CPM { Desc: "F_DELETE", Handler: SysCallDeleteFile, } + sys[20] = CPMHandler{ + Desc: "F_READ", + Handler: SysCallRead, + } sys[21] = CPMHandler{ Desc: "F_WRITE", Handler: SysCallWrite, diff --git a/cpm/cpm_syscalls.go b/cpm/cpm_syscalls.go index 5554082..d7089dd 100644 --- a/cpm/cpm_syscalls.go +++ b/cpm/cpm_syscalls.go @@ -354,6 +354,77 @@ func SysCallDeleteFile(cpm *CPM) error { return err } +// SysCallRead writes a record to the file named in the FCB given in DE +func SysCallRead(cpm *CPM) error { + + // Don't have a file open? That's a bug + if !cpm.fileIsOpen { + cpm.Logger.Error("attempting to write to a file that isn't open") + cpm.CPU.States.AF.Hi = 0xff + return nil + } + + // The pointer to the FCB + ptr := cpm.CPU.States.DE.U16() + // Get the bytes which make up the FCB entry. + xxx := cpm.Memory.GetRange(ptr, 36) + + // Create a structure with the contents + fcbPtr := fcb.FromBytes(xxx) + + // offset + BlkS2 := 4096 + BlkEx := 128 + offset := int(int(fcbPtr.S2)&MaxS2)*BlkS2*blkSize + + int(fcbPtr.Ex)*BlkEx*blkSize + + int(fcbPtr.Cr)*blkSize + + _, err := cpm.file.Seek(int64(offset), io.SeekStart) + if err != nil { + return fmt.Errorf("cannot seek to position %d: %s", offset, err) + } + + // Temporary area to read into + data := make([]byte, blkSize) + + // Fill the area with data + for i := range data { + data[i] = 0x1a + } + + // Read from the file, now we're in the right place + _, err = cpm.file.Read(data) + if err != nil { + return fmt.Errorf("error writing to file %s", err) + } + + // Copy the data to the DMA area + cpm.Memory.PutRange(dma, data[:]...) + + MaxCR := 128 + MaxEX := 31 + + fcbPtr.S2 &= 0x7F // reset unmodified flag + fcbPtr.Cr++ + if int(fcbPtr.Cr) > MaxCR { + fcbPtr.Cr = 1 + fcbPtr.Ex++ + } + if int(fcbPtr.Ex) > MaxEX { + fcbPtr.Ex = 0 + fcbPtr.S2++ + } + fcbPtr.RC++ + + // Update the FCB in memory + cpm.Memory.PutRange(ptr, fcbPtr.AsBytes()...) + + // All done + cpm.CPU.States.AF.Hi = 0x00 + return nil + +} + // SysCallWrite writes a record to the file named in the FCB given in DE func SysCallWrite(cpm *CPM) error { @@ -506,7 +577,7 @@ func SysCallReadRand(cpm *CPM) error { return 1 } - cpm.Memory.PutRange(0x80, data[:]...) + cpm.Memory.PutRange(dma, data[:]...) return 0 }