- BSimple Language Reference
- Core Concepts
- Operations
- Standard Library
- System Functions
- Number Parsers
- File I/O
- Entry Point:
main(argc, argv)ormain() - Creating Your Own Libraries in Assembly for BSimple
BSimple is a mid-level, compiled, typeless programming language with C-like syntax, designed for building system software, games, and low-level utilities.
- Typeless: All variables are 24-bit signed machine words.
- Minimal Syntax: Compact and straightforward C/B-like syntax.
- Compiled to Assembly: Full control over hardware and performance.
- Case-Sensitive Identifiers:
Var,var, andVARare different. - String Literals as Pointers: Strings are stored as global data, and passed as pointers.
- Size: 24-bit signed integer
- Range: -8,388,608 to 8,388,607
- Variable Size: 3 bytes (or N * 3 bytes for arrays)
- Decimal:
123,-456 - Hexadecimal:
$1F4= 500 - Strings:
"Hello"will points to data segment(to NULL-terminated string)
- No mutli-line comments are supported
- Begin with
#and continue to the end of the line
# This is a comment
fun_call(arg1); # Function will be called and this is a comment
Include external assembly routines:
import "../lib/startup.i"
Runtime will be included with your startup code.
Include BSimple source files:
include "utils.bs"
Include binary files as global data labels:
incbin font_data, "font.bin"
Declared outside functions just in body of program.
var score;
var buffer[128]; # 128 * 3 = 384 bytes
Declared inside functions with var. Max: 40 entries (stack-based) per function.
function()
{
var temp, result;
var local_arr[10];
}
- Operators:
+,-,*,/,% - Left-to-right evaluation (no precedence)
a = 3 + 2 * 5; # Interpreted as ((3 + 2) * 5)
|- OR&- AND~- XOR
*ptr- Dereference&var- Address of variable
a = *$40040;
p = &a;
[ arr -> 0 ] = 10;
[ arr -> 1 ] = [ arr -> 0 ] * 2;
Return 0 if false and any another value threaded as true(build-in functions are using value -1 cause it represented as $ffffff value and can be used as mask in evaluations):
a = b > c;
b = a == 0;
- Every string literal is automatically stored in the data segment
- Compiler generates a global variable for each string
- String expressions return a pointer to the string in memory
puts("Hello, world!"); # Pointer to string is passed to function
- String literals can be used anywhere a pointer is expected
- No need to manually define global string buffers for literals
- Internally, the compiler handles storage and pointer passing
hello()
{
printf("Sum: %d\r\n", sum(2, 3)); # Pointer to format string passed to printf
}
if a > 0 {
puts("Positive");
}
while i < 10 {
i = i + 1;
}
var i;
for (i = 0; i < 10; i = i + 1) {
printf("%d", i);
}
repeat {
i = i + 1;
} until i == 10;
label retry;
goto retry;
sum(x, y)
{
return x + y;
}
hello()
{
puts("Hi");
}
This functions are included in lib/startup.i or lib/moslet.i
abs(x)- Absolute valueneg(x)- Negationrand()- Random (full range)rand_range(min, max)- In rangeudiv(a, b)- Unsigned divisionswap(&a, &b)- Swap two memory cells
putc(c)- Prints single character. Can be used for text output or for VDP commandsputs(ptr)- Print string (fast, without formatting). Any ZERO-terminated string can be used for this routine(including VDP commands that doesn't use zeros as value).printf(fmt, ...)- Formatted print%dDecimal%xHex%oOctal%bBinary%cCharacter%sString (pointer)%%Literal%
printn(number, base)- prints number with specified base(used as subroutine in printf but can be used directly)printx(n)- print number as hex. value
Located in lib/stdlib.i
strlen(ptr)- String lengthstrcmp(a, b)- Compare (returns-1if equal)strstarts(a, b)- Prefix checkstrcpy(dst, src)- Copy stringstrcat(dst, src)- Appendstrchr(str, ch)- First occurrencestrstr(str, substr)- Substring search
cls()- Clear screenvdp_mode(mode)- Video modesleep(sec)- Delay in secondssleepf(frames)- Delay in framesgotoxy(x, y)- Move cursorset_cursor_mode(mode)- Show/hide cursoruse_graphics_cursor()/use_text_cursor()- Cursor typebeep()- Make some noiseplay_note(ch, vol, freq, dur)- Sound tonereadline(ptr, size)- reads line using MOS routine. Returns key what was used for finishing(enter or ESC)exec(cmd)- execute MOS commad. Example:
# ... skipped
exec("ls");
# ... skipped
Important note: You cannot execute programs or batch files using exec call from usual application(cause they're using the same memory pages as your application) but You can execute them from MOSlets. As example You can check BSimple native builder sources.
Convert string to numeric value:
x = parse_bin("1010");
y = parse_oct("123");
z = parse_dec("-42");
some_hex = parse_hex("FF");
Located in lib/files.i
Example that covers all operations located here
fopen(path, mode)- opens file with C like file modes("r", "w", "a", "w+" etc)fclose(fp)fputs(fp, str)fputc(fp, ch)fprintf(fp, fmt, ...)fread(fp, ptr, size)fgetc(fp)flseek(fp, offset)feof(fp)frename(old, new)mkdir(name)fcopy(from, to)cwd(path)delete(name)
BSimple supports an enhanced main() function that can receive command-line arguments, similar to C.
main(argc, argv)
argc: Number of arguments (an integer)argv: Pointer to an array of string pointers (i.e.,char**in C terms)
Each argument string is automatically stored as a global string literal and passed as a pointer.
import "../lib/startup.i"
main(argc, argv) {
if argc == 0 {
puts("No arguments\r\n");
exit();
}
printf("Arguments count: %d\r\n\r\n", argc);
var i;
i = 0;
while i < argc {
printf(" [ *argv -> %d ] = `%s`\r\n", i, [ *argv -> i ]);
i = i + 1;
}
}
If your program does not require arguments, you can still use a simple main() without parameters.
BSimple allows seamless integration of external routines written in assembly language. This enables you to write performance-critical, low-level functions—such as device drivers, math routines, or system calls—and call them directly from BSimple code after importing them using the import keyword.
Assembly routines intended for use with BSimple must follow a specific calling convention to ensure compatibility with the runtime environment, particularly the way BSimple handles function arguments and local variables.
BSimple uses the IX register as the base pointer for local variables and function arguments. Therefore, it is critical to preserve the IX register in any custom assembly routine to avoid corrupting the execution environment.
- Always preserve IX: Save and restore it at the beginning and end of your routine.
- Arguments are passed on the stack, and can be accessed using offsets from IX.
- Return values (if any) must be stored in the HL register.
- Function names must begin with a single underscore
_
When a BSimple function calls an external routine, the stack is arranged as follows:
IX + 0 : return address (3 bytes)
IX + 3 : old IX (3 bytes)
IX + 6 : first argument (3 bytes)
IX + 9 : second argument (3 bytes)
... (additional arguments)
This is an example implementation of the readline function, which takes two arguments:
- A pointer to the buffer
- A maximum buffer size
It returns the terminating key code in HL.
_readline:
push ix
ld ix, 0
add ix, sp
;; Loading buffer pointer(first argument)
ld hl, (ix + 6)
;; Loading buffer size(second argument)
ld bc, (ix + 9)
ld e, %101
ld a, __mos_editline
rst.lil $08
;; Cleaning HL
or a
sbc hl, hl
;; HL = A, return value
ld l, a
ld sp, ix
pop ix
ret