You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+55-10Lines changed: 55 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,25 +12,27 @@ Targeting compatibility with [Lazy wspace](https://github.com/thaliaarchi/lazy-w
12
12
13
13
- Each memory position can store up to a u128 number
14
14
- Memory is addressable within 32 bit, from 0 to 4_294_967_294
15
+
- Mod operation works as the original implementation in haskell (5%-3 = -1, -5%3 = 1)
16
+
- Supports up to whitespace 0.3 instructions (copy, slide)
15
17
16
18
## Memory layout convention
17
19
18
20
The stdlib defined by this repo sets a couple of conventions to perform calls and manage the heap.
19
21
20
-
To start off, the default convention for calls is pass arguments through the stack, pushing them in the original order. The call will consume all of the arguments, removing them from the stack, and optionally it will push a value for the return value.
22
+
To start off, the default convention for calls is pass arguments through the stack, pushing them in the original order. The call will consume all of the arguments, removing them from the stack, and it will push as many return values as defined for that function (0-infinite).
21
23
22
24
Strings, vectors, etc. Must be allocated in the heap, and are always passed by reference.
23
25
24
26
The heap is split in 2 pieces: A stack, used to store local variables, and a heap, where blocks can be allocated or freed.
25
27
26
28
The heap stack helps storing temporary values. Usually, the native stack will suffice, but it has a few disadvantages:
27
29
28
-
- It can only peek past values.
29
-
- It can't reorganise values.
30
-
- It's the only way of performing any operation.
30
+
- It can only peek values below the stack pointer.
31
+
- It can't rearrange values.
32
+
- It's the only way of performing any operation (i.e. there are no registers).
31
33
- This makes the offset for peeking also not stable.
32
34
33
-
With the heap stack, each function can assume that their stack is empty, and then use as much space as they need with something that the offsets will remain stable while performing operations.
35
+
With the heap stack, each function can assume that their stack is empty, and then use as much space as they need with something that the offsets will remain stable while performing operations. There's a tradeoff with a small performance hit though, since reading and writing from the heap stack requires multiple operations.
34
36
35
37
The memory layout is as follows:
36
38
@@ -44,10 +46,12 @@ The standard library on memory provides a few methods to deal with heap stack:
44
46
45
47
-`stack_freeze(n)`: Removes `n` from the native stack and pushes them onto the native stack, in the same order.
46
48
-`stack_restore(n)`: Removes `n` from the heap stack and pushes them onto the native stack, in the same order.
49
+
-`stack_reserve(n)`: Moves the stack pointer `n` positions to the front.
47
50
-`stack_discard(n)`: Removes `n` from the heap stack.
48
51
-`stack_get(offset)`: Gets the nth element from the stack (starting at 0).
49
52
-`stack_get_head()`: Sugar for `stack_get(0)`.
50
53
-`stack_set(offset, value)`: Sets the nth element of the stack (starting at 0) to `value`.
54
+
-`stack_set_head(value)`: Sugar for `stack_get(0, value)`.
51
55
52
56
### Heap
53
57
@@ -61,34 +65,75 @@ The standard library on memory provides few methods to deal with heap:
61
65
62
66
- malloc(size): Creates a new block.
63
67
- It will try to put it as close to the end of the memory as possible.
64
-
- If no gaps are found, it will put it as the new first element.
68
+
- If no gaps are found, it will put it as the last block of the list.
65
69
- If gaps are found, then it will get in between.
66
70
- Returns pointer to start of data.
67
71
- mfree(data_pointer): Frees up a block.
68
72
- It will update the linked list accordingly.
69
-
-No need for the blocks to be double-linked, I can always search from the start.
73
+
-It will find the neighbouring blocks by traversing the block list from the start.
70
74
- realloc(data_pointer, size): Reallocates a block.
71
75
- Shrinking will not move it.
72
76
- Expanding will try to not move it if possible.
73
77
- If not, it will allocate a new block, move everything, and delete.
74
78
- Returns pointer to start of data.
75
79
- memcpy(source, dest, size): Copies data from one side to the other.
76
-
- Doesn't handle overlaps
80
+
- Doesn't handle overlaps (so it is the same behaviour as C's lib memcpy as opposed to memmove)
77
81
- memset(dest, value, size): Sets all the values of block to `value`.
78
82
79
83
## Assembly language
80
84
81
-
It reuses[Burghard's WSA](https://github.com/wspace/burghard-wsa) as assembly language, but with a few modifications:
85
+
It's based on[Burghard's WSA](https://github.com/wspace/burghard-wsa) as assembly language, but with a few modifications:
-`copy n`: Copy the nth element from the stack to the top of the stack (operation added in whitespace v0.3)
86
90
-`slide n`: Slide n items off the stack, keeping the top one (operation added in whitespace v0.3)
87
91
-`storestr str`: Stores `str` in the heap using the address defined in the top of the stack (and consuming it).
88
-
-`debugger`: Signals the interpreter to pause execution at that point.
89
92
- Modifies:
90
93
- Strings (labels, string literals) don't need to be wrapped between ""
91
94
-`retrive` renamed to `retrieve`.
92
95
-`doub` renamed to `dup`.
93
96
-`inc` renamed to `readc`.
94
97
-`inn` renamed to `readn`.
98
+
99
+
## Extensions
100
+
101
+
While on debug mode, this interpreter adds some language extensions to debug or increase performance. For this, a few more operations are added, both to the assembler and the whitespace code ops:
102
+
103
+
-`debugger`: "LLS" Signals the interpreter to pause execution at that point.
104
+
-`and`: "TSLL" Performs the bitwise and operation of the top 2 values of the stack.
105
+
-`or`: "TSLS" Performs the bitwise or operation of the top 2 values of the stack.
106
+
-`not`: "TSLT" Performs the bitwise not operation to the top value of the stack.
107
+
108
+
As these are not whitespace standard, the assembler will omit the `debugger` instruction if the extension is not enabled, and throw an Error for the bitwise operations.
109
+
110
+
## STD lib
111
+
112
+
This assembler has a few (WIP) std libraries with common operations. The ones dealing with the memory convention explained above can be imported with `include memory`.
113
+
114
+
The source of these libraries can be found in `src/wsa/lib`
115
+
116
+
### Memory
117
+
118
+
See [Memory layout convention](#memory-layout-convention)
119
+
120
+
### Bitwise
121
+
122
+
-`bitwise_and(a,b)`
123
+
-`bitwise_or(a,b)`
124
+
-`bitwise_not(a)`
125
+
-`bitwise_not_mod(a, m)`: Performs a bitwise not operation but only for the low `m` bytes.
126
+
-`bitwise_mask(m)`: Creates a mask with `m` 1s (essentially 2^m-1)
127
+
128
+
This library uses the language extensions if they are enabled, otherwise uses the standard 0.3 WS opcodes.
129
+
130
+
### IO
131
+
132
+
-`prints(&s)`: Outputs the null-terminated string at address `s`.
133
+
-`printsln(&s)`: Outputs the null-terminated string at address `s`, with a `\n` at the end.
134
+
-`print_byte_hex(v)`: Prints the 8-bit value `v` as hex.
135
+
-`print_char_hex(v)`: Prints the 4-bit value `v` as hex.
0 commit comments