Uzebox programming (work in progress)
This text is in development, many things may change before final release.
- 1 Uzebox programming
- 1.1 Intended features
- 1.2 Language
- 1.2.1 Variables
- 1.2.2 Special registers
- 1.2.3 Constants
- 1.2.4 Data types
- 1.2.5 Instructions
Goal of this project is to create programming language and IDE for creating programs and games directly on Uzebox.
- Simple assembler-, basic- or c- -like programming language with hi-level instructions. You can think it as of CISC virtual processor with capabilities of printing characters on screen, playing sounds, reading joypads or keyboard, etc.
- Integrated code editor with autocomplete features for ability to program by joypad or keyboard (when HW will be available).
- Integrated interpreter and debugger capable of looking into virtual registers to see what's happening inside
- Storing program on SD for possibility of very big programs.
User program consists of instructions for virtual processor (machine). Each instruction is simple arithmetical or logical operation on data or complex action with screen, controllers etc.
User program have dedicated part of Uzebox's RAM available for run-time (as registers). Size of this special memory will be decided during implementation according to technical possibilities. Programmer can declare variables in special part of IDE, called variables editor. Variable is defined by it's ID (for inner representation in interpreter), data type, address in memory, and program identifier (few characters for programmer to use in edited code).
(later will be decided if ID will be implementated or address in memory will be used instead).
There some special memory locations, that can be used as source or destination for some operations (see instruction list).
- carry (bool)
- borrow (bool)
- division by zero (bool)
Same structure as variables, but held in program source code, are read-only, can be accessed by instructions. Programmer can set constants in special part of IDE, called strings editor (for long strings), or entered directly into program code - as instruction operand.
- logical (bool) - stores only true/false (boolean) value, constants may be entered as no/yes, 0/1, false/true (later will be decided, if it will be internally stored as byte or will be dedicated some area in RAM for bit-oriented indexing) (later will be decided, if logical type will be used, or integer types will be used instead)
- integer types (int8, uint8, int16, uint16, int32, uint32, int64, uint64) - stores integer values - (signed/unsigned), (8-bit, 16-bit, 32-bit, 64-bit?), constants may be entered in binary, decimal or hexadecimal form (0b00010100, 20, 0x14), or as a character (for printing)
- floating point numbers (float, double) - (according to gcc implementation?)
- character type (char) - each 8-bit integer can be interpreted as index of character to print on screen
- string type (string, char?) - statically-sized array of characters, null-terminated (according to size of available memory for user program's data, this type may be unuseable, it will be decided later, if strings will be available for run-time or only as program constants for printing UI etc.)
- data arrays - same as string for other data types, for lookups in constant table, addresable by index (will be decided later if will be implemented for constants, variables, both or none)
Automatic type juggling
Each instruction can have different implementation depending on type (and size) of variable used, which is decided during interpretation.
In case of integers - if size of target variable is bigger than source, it's left-padded with zeroes (value keeps the same), if bigger number is to be written into small variable, only right part is copied (value keeps the same for numbers, that fits into target variable). When storing integer number into character, ordinal value will be used. In case of floating point numbers, given value is stored in maximal possible precision of target variable. While saving floating point number into integer, decimal part is truncated, and if whole number doesn't fit into target variable, only right part is used. While saving integer number into floating point variable, maximum possible precision is used.
(later will be decided how to deal with multiple arguments of different type - ie. (float) = (int) + (float))
Each instruction consists of opcode (simple name, which characterizes meaning) and optional parameter(s) - operands. Instructions are entered in special part of IDE - program editor. Default format of instruction works directly with memory variables, for loading constants into these registers, load instruction can be used.
- copy - (b) = (a)
- add - (c) = (a) + (b)
- subtract - (c) = (b) - (a)
- multiply - (c) = (a) * (b)
- divide - (c) = (b) / (a)
- division reminder - (c) = (b) % (a)
- and - (c) = (a) & (b)
- or - (c) = (a) | (b)
- exclusive or - (c) = (a) ^ (b)
- not - (b) = !(a)
- shift left - (c) = (a) << (b)
- shift right - (c) = (a) >> (b)
- rotate left
- rotate right
Logical instructions (only for booleans)
- and - (c) = (a) && (b)
- or - (c) = (a) || (b)
- exclusive or - (c) = (a) ^ (b)
- not - (b) = !(a)
Condition instructions (result is boolean)
- equal as - (c) = (a) == (b)
- not equal as - (c) = (a) != (b)
- greater than - (c) = (a) > (b)
- greater than or qual as - (c) = (a) >= (b)
- lesser than - (c) = (a) < (b)
- lesser than or qual as - (c) = (a) <= (b)
Input and output instructions
- load - LOAD (b) = (a)
- load - LOAD (c) = (a)[(b)]
- read - READ (a)
- write character - WRITE CHAR (a)
- write string - WRITE STRING (a)
- write binary - WRITE BINARY (a)
- write decimal - WRITE DECIMAL (a)
- write hexa-decimal - WRITE HEXA-DECIMAL (a)
- set color - SET COLOR (a) ?
- beep - BEEP FREQUENCY (a) DURATION (b)
- pause - PAUSE DURATION (a)
- wait - WAIT
- break - BREAK
Flow control instructions
- define label - LABEL (a)
- go to label - GOTO (a)
- go to label if condition (boolean) is true - IF (b) GOTO (a)