Data-TypesThe most fundamental function of an operating system is to implement data-types which are not implemented in hardware or micro-code. This means we should define types and their operations. We may also want to define what is not core functionality because this is probably library functionality. Unfortunately, the placement of micro-kernel, kernel, privileged driver, ABI or library may be shuffled, compromised or forced to match a historical implementation. This is particularly true if an implementation once fit or continues to fit into a 16 bit address-space or smaller. Anyhow, SheepOS supports an eclectic mix of data types:
- Supported: 16 bit integer, 32 bit integer, 48 bit integer (for time, inode and file offset), 64 bit integer, 32 bit float (unconventional format), 64 bit float (unconventional format), application, application class, stack, buffer (including 40*25 text buffer), window, icon, joypad, keyboard, pointing device, interrupt, event, storage volume, partition, directory, inode and 16 bit virtual color-space.
- Not supported in version 1.0: command line parameters, memory allocator, vector, matrix, cipher, hash, random, PS/2 device, SCSI device, parallel port, serial port, network packet, printer.
- Not supported in any planned version: Unicode string, regular expression, XML, JSON, jumbo frame, TCP socket, bitmap display.
The most fundamental operations include arithmetic: addition, subtraction, multiplication and division. Large systems have usually included multiplication and division opcodes. (ARMv1 is a notable exception to include multiplication but not division. I assumed this was due to the scalability of addition, subtraction and multiplication but it was due to the poor interrupt response of NS32032 division being incompatible with floppy disks formatted with 6502.) Anyhow, multiplication and division has been bit of a fudge on 8 bit computers; especially so with floating point. I've suggested that
squaring should be be counted as a distinct operation. However, I was unaware that there are
many ways to multiply and a large amount of legacy software doesn't use the most efficient method. I would *hope* that an operating system would provide the most efficient primitives. Unfortunately, the most efficient algorithm depends upon the input data. Some algorithms are more efficient if the top 8 bits are zero. Some are more efficient if top bits are sparse. Some are more efficient if bottom bits are sparse. None are the most efficient if both inputs are equal. Since the 1980s, RISC systems with one cycle or two cycle MULS R1,R1,R1 have skipped a large amount detail. Separately, coarse division of 8 bit quality or so is often sufficient for progress bars and similar indicators. No facility for such operation is commonly offered.
Floating point representation is unconventional and is intended to minimize sorting operations. Conversion to and from IEEE-754 may be required, although, unlike IEEE-754, it is in all cases possible to multiply single precision numbers and represent the result as double precision. Use of one's complement or two's complement mantissa is a detailed subject. Two's compliment simplifies addition. One's compliment simplifies multiplication. For Taylor approximation, such as sine calculation, alternating addition and multiplication make either representation moot. However, sort operations are O(n log n) and therefore a representation which minimizes sorting is overwhelmingly important in the general case. Further disregard for convention includes
complex input gamma function,
inverse square root function, a complete lack of hyperbolic functions and CORDIC working in right angles rather than radians. I am strongly considering
base 240 floating point format across BASIC, Forth, C and hardware blitters. Each byte of mantissa allows accurate representation of 1/10 and 1/12. The main impediments are use of float routines for integer division and CORDIC compatibility.
A stack is a fundamental type and I hope to separate call and data stacks in a manner which is compatible with Forth. In particular, this means flag bits returned from the operating system should be a convenience and are not mandatory. I originally hoped to have Z80 compatible stack with 16 bit alignment. Potentially, this allows a processor or virtual machine to switch instruction format. The intention was that legacy applications or libraries could drawn from other processor architectures. In this arrangement, registers are not preserved. Indeed, they may not be visible between switches. Unfortunately, this works really badly with 6502. Instead, I will be following Dr. Jefyll's idea to implement a wider stack across multiple regions of memory. Unfortunately, to satisfy numerous constraints (minimal memory configurations, windowing, legacy ABIs, 6502/65816 compatibility), all of these additional regions are restricted to the range $0000-$01FF. This is not a concern on 65816 outside of bank zero because absolute references to this range never clash with zero page or stack. It is only restricting on other targets. Regardless, it is possible to pass 32 bit, 48 bit and 64 bit parameters to and from the operating system. In particular, the data stack is wide enough and deep enough to perform 64 bit floating point multiplication on 5*5 matrices.
BigDumbDinosaur suggests that time is a fundamental type. While it is preferable to hold time internally as a monotonic integer and use RTC hardware which does same, many battery back-up clocks use the Julian calendar. The implication is that any kernel supporting Julian hardware should perform two way conversion of time formats. Whereas, a kernel which only supports monotonic hardware may delegate conversion to applications. This agnostic arrangement may lead to duplication and error where kernel, library or application have slightly different implementations. 48 bit milliseconds are suitable for 8925 years. 48 bit integers could be upscaled to 64 bit float (16 bit exponent, 48 bit mantissa) and therefore conversion can be performed with floating point MODDIV.
Much effort has been wasted on light mode/dark mode interfaces and this probably began with Apple's transition away from 6502 and to a
Xerox interface. To resolve this matter in a manner which is broadly compatible with SheepOS's 16 bit stack architecture, a virtual 16 bit palette will be implemented in which four nybbles have decreasing influence on the resulting color. The bottom eight values ($0-$7) will be 1 bit per channel colors (fully saturated black, red, green, yellow, blue, purple, cyan, white). The next four values ($8-$B) are likely to be warm colors which improve the definition of useful shades. Specifically, gray, orange, pink and brown. This is inspired by snooker and hexachrome printing. The final four colors ($C-$F) will be defined by the class and privileges of the application. Of these, two are highlight colors, one is a neutral color and should contrast with other colors. Enforcement of contrasting colors allows a portable user interface to be constructed without consideration of light/dark mode. The 16 bit palette entry may be expanded to 24 bit color or contracted to 8 bit color. This operation may be processor intensive and therefore caching may be desirable. The cache must be flushed when the settings are changed.