Difference between revisions of "GeneveOS Device Operation"

From Ninerpedia
Jump to navigation Jump to search
m
 
(8 intermediate revisions by the same user not shown)
Line 74: Line 74:
After the operation, the PAB contains information about the results of the operation.
After the operation, the PAB contains information about the results of the operation.


'''Error code'''
=== Mode ===
 
The mode bits are used to determine the operation direction (in/out/update/append), the encoding (display/internal), the structure (fixed/variable) and the access (sequential/relative).
 
{| class="plainbits" style="width:64%"
! 0
! 1
! 2
! 3
! 4
! 5
! 6
! 7
|-
| style="width:24%" rowspan="4" colspan="3" | Unused (000)
| style="width:8%" rowspan="2" | Fixed=0
| style="width:8%" rowspan="2" | Display=0
| style="width:16%" colspan="2" | Update=00
| style="width:8%" rowspan="2" | Sequential=0
|-
| colspan="2" | Output=01
|-
| rowspan="2" | Variable=1
| rowspan="2" | Internal=1
| colspan="2" | Input=10
| rowspan="2" | Relative=1
|-
| colspan="2" | Append=11
|}
 
 
=== Error code ===


The error code is an eight bit word with the following structure:
The error code is an eight bit word with the following structure:
Line 212: Line 243:
The '''Actual Record Length''' is the length of the records of the existing file. When 0 was passed on the call, this delivers the record length of the file; otherwise this is the value that was passed for the call. The '''True Record Length''' is the record length of the file when it already exists.
The '''Actual Record Length''' is the length of the records of the existing file. When 0 was passed on the call, this delivers the record length of the file; otherwise this is the value that was passed for the call. The '''True Record Length''' is the record length of the file when it already exists.


----
<div style="margin-bottom:6em"></div>


=== CLOSE ===
=== CLOSE ===
Line 294: Line 325:
|}
|}


----
<div style="margin-bottom:6em"></div>


=== READ ===
=== READ ===


----
Reads a record from a record-oriented file. For flat memory image files, [[#LOAD | LOAD]] must be used.
 
'''IN'''
 
{| class="plainc" style="margin-left:1%"
|-
! width="4%" | 00
! width="4%" | 01
! width="4%" | 02
! width="4%" | 03
! width="4%" | 04
! width="4%" | 05
! width="4%" | 06
! width="4%" | 07
! width="4%" | 08
! width="4%" | 09
! width="4%" | 0A
! width="4%" | 0B
! width="4%" | 0C
! width="4%" | 0D
! width="4%" | 0E
! width="4%" | 0F
! width="4%" | 10 ...
|-
| '''02'''
| Mode
| -
| colspan="3" | Buffer address
| colspan="2" | Record number
| colspan="2" | Record length
| Memory
| colspan="3" | -
| -
| Name length
| Name
|-
|}
 
Use the '''Record number''' field to specify the desired record in '''fixed record length''' files. This is not available for variable length record files.
 
The '''Record Length''' must match the length of the records as specified by [[#OPEN | OPEN]].
 
The '''Memory''' flag determines whether the data are read into CPU (0) or VDP (not 0) memory.
 
After the READ operation has completed, the PAB delivers information about the result:
 
'''OUT'''
 
{| class="plainc" style="margin-left:1%"
|-
! width="4%" | 00
! width="4%" | 01
! width="4%" | 02
! width="4%" | 03
! width="4%" | 04
! width="4%" | 05
! width="4%" | 06
! width="4%" | 07
! width="4%" | 08
! width="4%" | 09
! width="4%" | 0A
! width="4%" | 0B
! width="4%" | 0C
! width="4%" | 0D
! width="4%" | 0E
! width="4%" | 0F
! width="4%" | 10 ...
|-
| -
| -
| Error code
| colspan="3" | -
| colspan="2" | Next record number
| colspan="2" | -
| -
| colspan="3" | Number of read bytes
| -
| Name length
| Name
|}
 
'''Next record number''' applies for fixed record length files only.
 
<div style="margin-bottom:6em"></div>


=== WRITE ===
=== WRITE ===


----
Writes a record to a record-oriented file. For flat memory image files, [[#SAVE | SAVE]] must be used.
 
'''IN'''
 
{| class="plainc" style="margin-left:1%"
|-
! width="4%" | 00
! width="4%" | 01
! width="4%" | 02
! width="4%" | 03
! width="4%" | 04
! width="4%" | 05
! width="4%" | 06
! width="4%" | 07
! width="4%" | 08
! width="4%" | 09
! width="4%" | 0A
! width="4%" | 0B
! width="4%" | 0C
! width="4%" | 0D
! width="4%" | 0E
! width="4%" | 0F
! width="4%" | 10 ...
|-
| '''03'''
| Mode
| -
| colspan="3" | Buffer address
| colspan="2" | Record number
| colspan="2" | Record length
| Memory
| colspan="3" | Number of bytes to write
| -
| Name length
| Name
|-
|}
 
Use the '''Record number''' field to specify the desired record in '''fixed record length''' files. This is not available for variable length record files.
 
The '''Record Length''' must match the length of the records as specified by [[#OPEN | OPEN]].
 
The '''Memory''' flag determines whether the data written from CPU (0) or VDP (not 0) memory.
 
After the WRITE operation has completed, the PAB delivers information about the result:
 
'''OUT'''
 
{| class="plainc" style="margin-left:1%"
|-
! width="4%" | 00
! width="4%" | 01
! width="4%" | 02
! width="4%" | 03
! width="4%" | 04
! width="4%" | 05
! width="4%" | 06
! width="4%" | 07
! width="4%" | 08
! width="4%" | 09
! width="4%" | 0A
! width="4%" | 0B
! width="4%" | 0C
! width="4%" | 0D
! width="4%" | 0E
! width="4%" | 0F
! width="4%" | 10 ...
|-
| -
| -
| Error code
| colspan="3" | -
| colspan="2" | Next record number
| colspan="2" | -
| -
| colspan="3" | Number of read bytes
| -
| Name length
| Name
|}
 
'''Next record number''' applies for fixed record length files only.
 
<div style="margin-bottom:6em"></div>


=== RESTORE ===
=== RESTORE ===


----
<div style="margin-bottom:6em"></div>


=== LOAD ===
=== LOAD ===


----
<div style="margin-bottom:6em"></div>


=== SAVE ===
=== SAVE ===


----
<div style="margin-bottom:6em"></div>


=== DELETE ===
=== DELETE ===


----
<div style="margin-bottom:6em"></div>


=== SCRATCH ===
=== SCRATCH ===


----
<div style="margin-bottom:6em"></div>


=== STATUS ===
=== STATUS ===


----
<div style="margin-bottom:6em"></div>


=== BREAD ===
=== BREAD ===


----
Reads a sector from a file or from a device. This is a level-2 operation, that is, it accesses the device based on sector addressing (or sectors of a file). BREAD allows for two operations:
 
* Read sectors from a file.
* Read sectors from a device.
 
'''IN'''
 
{| class="plainc" style="margin-left:1%"
|-
! width="4%" | 00
! width="4%" | 01
! width="4%" | 02
! width="4%" | 03
! width="4%" | 04
! width="4%" | 05
! width="4%" | 06
! width="4%" | 07
! width="4%" | 08
! width="4%" | 09
! width="4%" | 0A
! width="4%" | 0B
! width="4%" | 0C
! width="4%" | 0D
! width="4%" | 0E
! width="4%" | 0F
! width="4%" | 10 ...
|-
| '''0A'''
| -
| -
| colspan="3" | Buffer address
| colspan="2" | Sector offset LSW
| colspan="2" | -
| CPU / VDP
| -
| colspan="2" | Number of sectors
| Sector offset MSB
| Name length
| Name
|-
|}
 
The sector offset is defined by byte 0E as the most significant byte (value*65536) plus the word in bytes 06 and 07.
 
Byte 0A specifies whether the buffer address belongs to the CPU (0) or the VDP (non-zero) address space.
 
* CPU buffer address: ...p pppp.pppx xxxx.xxxx xxxx. The first three bits are ignored; the next 8 bits specify the page number in the user task, and the remaining 13 bits provide the offset in the page.
* VDP buffer address: .... ...x.xxxx xxxx.xxxx xxxx. The last 17 bits indicate the 128K video address.
 
'''Read from file''': When a file is addressed, the operation reads a sequence of sectors from the file. The '''Sector offset''' is the number of the first sector of the file, counting from 0. The physical locations of the sectors are subject to the sector allocation on the device.
 
'''Read from device''': When a device is addressed, the operation reads a sequence of sectors from the device. The '''Sector offset''' is the physical sector number.
 
After the BREAD operation has completed, the PAB delivers information about the result:
 
'''OUT'''
 
{| class="plainc" style="margin-left:1%"
|-
! width="4%" | 00
! width="4%" | 01
! width="4%" | 02
! width="4%" | 03
! width="4%" | 04
! width="4%" | 05
! width="4%" | 06
! width="4%" | 07
! width="4%" | 08
! width="4%" | 09
! width="4%" | 0A
! width="4%" | 0B
! width="4%" | 0C
! width="4%" | 0D
! width="4%" | 0E
! width="4%" | 0F
! width="4%" | 10 ...
|-
| -
| -
| Error code
| colspan="3" | Updated buffer address
| colspan="2" | Updated sector offset LSW
| colspan="2" | -
| -
| -
| colspan="2" | Remaining sectors
| Updated sector offset MSB
| -
| -
|-
|}
 
'''Error codes'''
 
* '''60''': Bad operation; happens when the device is not a block device.
* '''A0''': Read beyond end of file or device.
* '''C0''': Media error. The system was unable to read the sector although it should be readable.
* '''E0''': General error; happens when the device does not contain the specified file.
 
The '''Updated buffer address''' points to the memory address after the sectors were read (e.g. when 4 sectors are read, the pointer is increased by 4*256 = 1024).
 
The '''Updated sector offset''' is the first sector that has not been read due to an error condition.
 
The '''Remaining sectors''' is the number of unread sectors due to an error condition.


=== BWRITE ===
=== BWRITE ===
Line 366: Line 666:
| -
| -
| colspan="3" | Buffer address
| colspan="3" | Buffer address
| colspan="2" | Sector offset
| colspan="2" | Sector offset LSW
| colspan="2" | -
| colspan="2" | -
| CPU / VDP
| -
| -
| colspan="3" | Number of sectors
| colspan="2" | Number of sectors
| -
| Sector offset MSB
| Name length
| Name length
| Name
| Name
Line 410: Line 711:
| Error code
| Error code
| colspan="3" | Updated buffer address
| colspan="3" | Updated buffer address
| colspan="2" | Next unwritten sector
| colspan="2" | Updated sector offset LSW
| colspan="2" | -
| colspan="2" | -
| -
| -
| 0
| colspan="2" | Number of unwritten sectors
| -
| -
| Name length
| colspan="2" | Remaining sectors
| Name
| Updated sector offset MSB
| -
| -
|-
|-
|}
|}
Line 423: Line 724:
The '''Updated buffer address''' points to the memory address after the sectors were written (e.g. when 4 sectors are written, the pointer is increased by 4*256 = 1024).
The '''Updated buffer address''' points to the memory address after the sectors were written (e.g. when 4 sectors are written, the pointer is increased by 4*256 = 1024).


The '''Next unwritten sector''' is the first sector that has not been written due to an error condition.
The '''Updates sector offset''' is the first sector that has not been written due to an error condition.


The '''Number of unwritten sectors''' is the number of unwritten sectors due to an error condition.
The '''Remaining sectors''' is the number of unwritten sectors due to an error condition.


<div class="warn">Unless you want to write directly to the device, make sure that the PAB contains a file name that points to a file, not to a device. For example, when the file name has been created by the program, and for some reason the file name is empty (like "HDS1."), the following write operation will overwrite the volume information block and the allocation tables and '''destroy the target device filesystem'''.</div>
<div class="warn">Unless you want to write directly to the device, make sure that the PAB contains a file name that points to a file, not to a device. For example, when the file name has been created by the program, and for some reason the file name is empty (like "HDS1."), the following write operation will overwrite the volume information block and the allocation tables and '''destroy the target device filesystem'''.</div>
Line 433: Line 734:
(The author lost a complete hard disk by this incident, and was lucky to have a backup.)
(The author lost a complete hard disk by this incident, and was lucky to have a backup.)


----
<div style="margin-bottom:6em"></div>


=== PROTECT ===
=== PROTECT ===


----
<div style="margin-bottom:6em"></div>


=== RENAME ===
=== RENAME ===


----
<div style="margin-bottom:6em"></div>


=== FORMAT ===
=== FORMAT ===

Latest revision as of 19:43, 24 April 2022

Accessing devices (floppy disk, hard disk, serial connector, printer) is possible in GeneveOS via XOP calls.

User-task XOPs

User-task XOPs are available for use in application programs. Here is a typical example:

PABADD EQU  >F180   
FILE   DATA 8
...
       LI   R0,PABADD
       XOP  @FILE,0
       MOVB @PABADD+2,R0
       JNE  ERROR
       ...

Similar as with the TI-99/4A device service routine concept (DSR), a Peripheral Access Block (PAB) must be set up prior to invoking the XOP.

Device Service Routine Call

Input Output
R0 Pointer to PAB -

The actual operation is contained in the Peripheral Access Block (PAB).

Peripheral Access Block

While the TI-99/4A DSRs expect the PAB to be stored in VDP RAM, the Geneve OS DSRs use CPU RAM for the PAB, which means the PAB need not be copied to the video RAM before use. Also, you can choose to have the I/O buffers in VDP or CPU RAM.

The general layout of the PAB is as follows:

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
Opcode Mode Error code Buffer address Record number Record length Memory type Character count Status byte Name length Name

Note that the buffer addresses are 21-bit wide, represented by the virtual address within the calling task. The address for this buffer should be derived from memory allocation operations that were invoked earlier.

After the operation, the PAB contains information about the results of the operation.

Mode

The mode bits are used to determine the operation direction (in/out/update/append), the encoding (display/internal), the structure (fixed/variable) and the access (sequential/relative).

0 1 2 3 4 5 6 7
Unused (000) Fixed=0 Display=0 Update=00 Sequential=0
Output=01
Variable=1 Internal=1 Input=10 Relative=1
Append=11


Error code

The error code is an eight bit word with the following structure:

0 1 2 3 4 5 6 7
Number Detail code for error 7
Number Meaning
0 No such device
1 Write-protected
2 Illegal open attribute
3 Illegal operation
4 Out of buffer space
5 Read beyond EOF
6 Device error
7 File error

Operations

OPEN

Open a record-oriented file. A file must be opened before it can be read from or written to. This operation is not required for flat memory image files.

The PAB must be set up prior to invoking the operation:

IN

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
00 Mode - - Records to reserve Record length - - - Name length Name

Open new file: The Record Length must be set to a value greater than 0. This will become the length of the records of the new file.

Open existing file: The Record Length must match the length of the records. If the length is unknown, 0 may be passed.

After the OPEN operation has completed, the PAB delivers information about the result:

OUT

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
- - Error code - - Actual Record Length - 0 True Record Length - Name length Name

The Actual Record Length is the length of the records of the existing file. When 0 was passed on the call, this delivers the record length of the file; otherwise this is the value that was passed for the call. The True Record Length is the record length of the file when it already exists.

CLOSE

Closes a record-oriented file. A file must be closed after being used. After closing, no further read or write operations may be invoked on the file. This operation is not required for flat memory image files.

The PAB must be set up prior to invoking the operation:

IN

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
01 Mode - - - - - - - Name length Name

After the CLOSE operation has completed, the PAB delivers information about the result:

OUT

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
- - Error code - - - - - - Name length Name

READ

Reads a record from a record-oriented file. For flat memory image files, LOAD must be used.

IN

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
02 Mode - Buffer address Record number Record length Memory - - Name length Name

Use the Record number field to specify the desired record in fixed record length files. This is not available for variable length record files.

The Record Length must match the length of the records as specified by OPEN.

The Memory flag determines whether the data are read into CPU (0) or VDP (not 0) memory.

After the READ operation has completed, the PAB delivers information about the result:

OUT

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
- - Error code - Next record number - - Number of read bytes - Name length Name

Next record number applies for fixed record length files only.

WRITE

Writes a record to a record-oriented file. For flat memory image files, SAVE must be used.

IN

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
03 Mode - Buffer address Record number Record length Memory Number of bytes to write - Name length Name

Use the Record number field to specify the desired record in fixed record length files. This is not available for variable length record files.

The Record Length must match the length of the records as specified by OPEN.

The Memory flag determines whether the data written from CPU (0) or VDP (not 0) memory.

After the WRITE operation has completed, the PAB delivers information about the result:

OUT

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
- - Error code - Next record number - - Number of read bytes - Name length Name

Next record number applies for fixed record length files only.

RESTORE

LOAD

SAVE

DELETE

SCRATCH

STATUS

BREAD

Reads a sector from a file or from a device. This is a level-2 operation, that is, it accesses the device based on sector addressing (or sectors of a file). BREAD allows for two operations:

  • Read sectors from a file.
  • Read sectors from a device.

IN

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
0A - - Buffer address Sector offset LSW - CPU / VDP - Number of sectors Sector offset MSB Name length Name

The sector offset is defined by byte 0E as the most significant byte (value*65536) plus the word in bytes 06 and 07.

Byte 0A specifies whether the buffer address belongs to the CPU (0) or the VDP (non-zero) address space.

  • CPU buffer address: ...p pppp.pppx xxxx.xxxx xxxx. The first three bits are ignored; the next 8 bits specify the page number in the user task, and the remaining 13 bits provide the offset in the page.
  • VDP buffer address: .... ...x.xxxx xxxx.xxxx xxxx. The last 17 bits indicate the 128K video address.

Read from file: When a file is addressed, the operation reads a sequence of sectors from the file. The Sector offset is the number of the first sector of the file, counting from 0. The physical locations of the sectors are subject to the sector allocation on the device.

Read from device: When a device is addressed, the operation reads a sequence of sectors from the device. The Sector offset is the physical sector number.

After the BREAD operation has completed, the PAB delivers information about the result:

OUT

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
- - Error code Updated buffer address Updated sector offset LSW - - - Remaining sectors Updated sector offset MSB - -

Error codes

  • 60: Bad operation; happens when the device is not a block device.
  • A0: Read beyond end of file or device.
  • C0: Media error. The system was unable to read the sector although it should be readable.
  • E0: General error; happens when the device does not contain the specified file.

The Updated buffer address points to the memory address after the sectors were read (e.g. when 4 sectors are read, the pointer is increased by 4*256 = 1024).

The Updated sector offset is the first sector that has not been read due to an error condition.

The Remaining sectors is the number of unread sectors due to an error condition.

BWRITE

Writes a sector to a file or to a device. This is a level-2 operation, that is, it accesses the device based on sector addressing (or sectors of a file). BWRITE allows for three operations:

  • Create a new, empty file.
  • Write sectors to a file.
  • Write sectors to a device.

IN

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
0B - - Buffer address Sector offset LSW - CPU / VDP - Number of sectors Sector offset MSB Name length Name

Create a file: When a file is addressed, and the number of sectors is 0, a new file is created. The contents of the file should be written by BWRITE on the same file with a sector count greater than 0.

Write to file: When a file is addressed, the operation writes a sequence of sectors to the file. The Sector offset is the number of the first sector of the file, counting from 0. The physical locations of the sectors are subject to the sector allocation on the device; in particular, when fragmentation is required, the sectors are written to the new fragment.

Writing to device: When a device is addressed, the operation writes a sequence of sectors to the device. The Sector offset is the physical sector number.

After the BWRITE operation has completed, the PAB delivers information about the result:

OUT

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ...
- - Error code Updated buffer address Updated sector offset LSW - - - Remaining sectors Updated sector offset MSB - -

The Updated buffer address points to the memory address after the sectors were written (e.g. when 4 sectors are written, the pointer is increased by 4*256 = 1024).

The Updates sector offset is the first sector that has not been written due to an error condition.

The Remaining sectors is the number of unwritten sectors due to an error condition.

Unless you want to write directly to the device, make sure that the PAB contains a file name that points to a file, not to a device. For example, when the file name has been created by the program, and for some reason the file name is empty (like "HDS1."), the following write operation will overwrite the volume information block and the allocation tables and destroy the target device filesystem.

Tick here: [ ] Yes, I fully understood the danger of this operation.

(The author lost a complete hard disk by this incident, and was lucky to have a backup.)

PROTECT

RENAME

FORMAT