Skip to content

Commit 71ffbe2

Browse files
committed
document the long type
1 parent e639210 commit 71ffbe2

File tree

8 files changed

+73
-45
lines changed

8 files changed

+73
-45
lines changed

docs/source/comparing.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ No linker
3434

3535
Data types
3636
----------
37-
- There are byte, word (16 bits) and float datatypes for numbers. There are no bigger integer types natively available.
38-
- There is no automatic type enlargement: calculations remain within the data type of the operands. Any overflow silently wraps or truncates.
37+
- There are byte, word (16 bits), long (32 bits) and float datatypes for numbers.
38+
- floats are available as native data type on systems that have a supported floating point library in ROM.
39+
- **There is no automatic type enlargement:** all calculations remain within the data type of the operands. Any overflow silently wraps or truncates.
3940
You'll have to add explicit casts to increase the size of the value if required.
4041
For example when adding two byte variables having values 100 and 200, the result won't be 300, because that doesn't fit in a byte. It will be 44.
4142
You'll have to cast one or both of the *operands* to a word type first if you want to accomodate the actual result value of 300.
43+
Similarly, ``long v = w1 * w2`` doesn't automatically give you the full 32 bits multiplication result, instead it is still constrained in the word range.
44+
If you need the full 32 bits result you'll have to call a specialized routine such as ``math.mul32`` or ``math.mul16_last_upper()``.
4245
- strings and arrays are allocated once, statically, and never resized.
4346
- strings and arrays are mutable: you can change their contents, but always keep the original storage size in mind to avoid overwriting memory outside of the buffer.
4447
- maximum string length is 255 characters + a trailing 0 byte.

docs/source/compiling.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Mac OS (and Linux, and WSL2 on Windows):
4141

4242
**Or, use the Gradle build system to build it yourself from source:**
4343

44-
The Gradle build system is used to build the compiler.
44+
The Gradle build system is used to build the compiler. You will also need at least Java version 17 or higher to build it.
4545
The most interesting gradle commands to run are probably the ones listed below.
4646
(Note: if you have a recent gradle installed on your system already, you can probably replace the ``./gradlew`` wrapper commands with just the regular ``gradle`` command.)
4747

@@ -68,7 +68,7 @@ For normal use, the ``installDist`` task should suffice and after succesful comp
6868

6969
.. hint::
7070
Development and testing is done on Linux using the IntelliJ IDEA IDE,
71-
but the actual prog8 compiler should run on all operating systems that provide a java runtime (version 11 or newer).
71+
but the actual prog8 compiler should run on all operating systems that provide a Java runtime (version 11 or newer).
7272
If you do have trouble building or running the compiler on your operating system, please let me know!
7373

7474
To successfully build and debug in IDEA, you have to do two things manually first:
@@ -99,7 +99,8 @@ It's easy to compile yourself, but a recent precompiled .exe (only for Windows)
9999
*You need at least version 1.58.0 of this assembler.*
100100
If you are on Linux, there's probably a "64tass" package in the repositories, but check if it is a recent enough version.
101101

102-
A **Java runtime (jre or jdk), version 11 or newer** is required to run the prog8 compiler itself.
102+
A **Java runtime (jre or jdk), version 11 or newer** is required to run the prog8 compiler itself. Version 17 or higher if you want to
103+
build the compiler from source.
103104
If you're scared of Oracle's licensing terms, get one of the versions of another vendor. Even Microsoft provides their own version.
104105
Other OpenJDK builds can be found at `Adoptium <https://adoptium.net/temurin/releases/?version=11>`_ .
105106
For MacOS you can also use the Homebrew system to install a recent version of OpenJDK.

docs/source/libraries.rst

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,28 @@ mkword (msb, lsb)
114114
So mkword($80, $22) results in $8022.
115115

116116
.. note::
117-
The arguments to the mkword() function are in 'natural' order that is first the msb then the lsb.
117+
The arguments are in 'natural' left to right reading order that is first the msb then the lsb.
118118
Don't get confused by how the system actually stores this 16-bit word value in memory (which is
119119
in little-endian format, so lsb first then msb)
120120

121+
mklong (msb, b2, b1, lsb)
122+
Efficiently create a long value from four bytes (the msb, second, first and finally the lsb). Avoids multiplication and shifting.
123+
So mklong($12, $34, $56, $78) results in $12345678.
124+
125+
.. note::
126+
The arguments are in 'natural' left to right reading order that is first the msb then the lsb.
127+
Don't get confused by how the system actually stores this 32-bit word value in memory (which is
128+
in little-endian format, so lsb first then b1, b2 and finally the msb)
129+
130+
mklong2 (msw, lsw)
131+
Efficiently create a long value from two words (the msw, and the lsw). Avoids multiplication and shifting.
132+
So mklong2($1234, $abcd) results in $1234abcd.
133+
134+
.. note::
135+
The arguments are in 'natural' left to right reading order that is first the msw then the lsw.
136+
Don't get confused by how the system actually stores this 32-bit word value in memory (which is
137+
in little-endian format, so lsw first then the msw)
138+
121139
offsetof (Struct.field)
122140
The offset in bytes of the given field in the struct. The first field will always have offset 0.
123141
Usually you just reference the fields directly but in some cases it might be useful to know how many
@@ -135,6 +153,9 @@ peekw (address)
135153
Caution: when using peekw to get words out of an array pointer, make sure the array is *not* a split word array
136154
(peekw requires the LSB and MSB of the word value to be consecutive in memory).
137155

156+
peekl (address)
157+
reads the signed long value at the given address in memory. Long is read as usual little-endian lsb/msb byte order.
158+
138159
peekf (address)
139160
reads the float value at the given address in memory. On CBM machines, this reads 5 bytes.
140161

@@ -148,6 +169,9 @@ pokebool (address, value)
148169
pokew (address, value)
149170
writes the word value at the given address in memory, in usual little-endian lsb/msb byte order.
150171

172+
pokel (address, value)
173+
writes the signed long value at the given address in memory, in usual little-endian lsb/msb byte order.
174+
151175
pokef (address, value)
152176
writes the float value at the given address in memory. On CBM machines, this writes 5 bytes.
153177

@@ -792,6 +816,9 @@ but perhaps the provided ones can be of service too.
792816
Returns the absolute difference, or distance, between the two word values.
793817
(This routine is more efficient than doing a compare and a subtract separately, or using abs)
794818

819+
``mul32 (woord w1, word w2) -> long``
820+
Returns the 32 bits signed long result of w1 * w2
821+
795822
``mul16_last_upper () -> uword``
796823
Fetches the upper 16 bits of the previous 16*16 bit multiplication.
797824
To avoid corrupting the result, it is best performed immediately after the multiplication.

docs/source/programming.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,13 @@ so pay attention to any jumps and rts instructions in the inlined code!
11501150
You can use them directly but their name isn't very descriptive, so it may be useful to define
11511151
an alias for them when using them regularly.
11521152

1153+
.. note::
1154+
Dealing with **long** arguments and return values:
1155+
A long takes 4 bytes (or 2 words, if you will). *There is no register definition specific to long types*.
1156+
The way you specify the 'register' for a long argument or return value for an asmsub is by using a *virtual register pair*.
1157+
For example, you can use R0+R1, R2+R3, R4+R5 and so on to take a long value instead.
1158+
The syntax to use as a 'register' name for those pairs is ``R0R1_32``, ``R2R3_32``, ``R4R5_32`` and so on.
1159+
11531160

11541161
External subroutines
11551162
^^^^^^^^^^^^^^^^^^^^

docs/source/structpointers.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ dealing with all of them separately. You first define the struct type like so::
130130
bool elite
131131
}
132132

133-
You can use boolean fields, numeric fields (byte, word, float), and pointer fields (including str, which is translated into ^^ubyte).
133+
You can use boolean fields, numeric fields (byte, word, long, float), and pointer fields (including str, which is translated into ^^ubyte).
134134
You cannot nest struct types nor put arrays in them as a field.
135135
Fields in a struct are 'packed' (meaning the values are placed back-to-back in memory), and placed in memory in order of declaration. This guarantees exact size and place of the fields.
136136
``sizeof()`` knows how to calculate the combined size of a struct, and ``offsetof()`` can be used to get the byte offset of a given field in the struct.

docs/source/todo.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ TODO
33

44
LONG TYPE
55
---------
6-
- document the new long type! and mklong(a,b,c,d) and mklong2(w1,w2) , print_l , print_ulhex (& conv.str_l) and pokel, peekl, cbm.SETTIML/RDTIML, math.mul32, verafx.muls/muls16, and the use of R0:R1 when doing LONG calculations, asmsub call convention: @R0R1_32 to specify a 32 bits long combined register R0:R1
7-
- how hard is it to also implement the other comparison operators (<,>,<=,>=) on longs?
6+
- implement the other comparison operators (<,>,<=,>=) on longs
87
- implement LONG testcases in testmemory
98

109

11-
1210
STRUCTS and TYPED POINTERS
1311
--------------------------
1412

docs/source/variables.rst

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Various examples::
3939
byte counter = len([1, 2, 3]) * 20
4040
byte age = 2018 - 1974
4141
float wallet = 55.25
42+
long large = 998877
4243
ubyte x,y,z ; declare three ubyte variables x y and z
4344
str name = "my name is Alice"
4445
uword address = &counter
@@ -173,8 +174,8 @@ type identifier type storage size example var declara
173174
``bool`` boolean 1 byte = 8 bits ``bool myvar = true`` or ``bool myvar == false``
174175
``word`` signed word 2 bytes = 16 bits ``word myvar = -12345``
175176
``uword`` unsigned word 2 bytes = 16 bits ``uword myvar = $8fee``
176-
``long`` signed 32 bits integer n/a ``const long LARGE = $12345678``
177-
(only for consts)
177+
``long`` signed 32 bits integer 4 bytes ``long large = $12345678``
178+
there is no unsigned long type at the moment.
178179
``float`` floating-point 5 bytes = 40 bits ``float myvar = 1.2345``
179180
stored in 5-byte cbm MFLPT format
180181
``byte[x]`` signed byte array x bytes ``byte[4] myvar``
@@ -195,10 +196,10 @@ type identifier type storage size example var declara
195196
``^^type`` typed pointer 2 bytes pointer types are explained in their own chapter :ref:`pointers`
196197
=============== ======================= ================= =========================================
197198

198-
Integers (bytes, words)
199-
^^^^^^^^^^^^^^^^^^^^^^^
199+
Integers (bytes, words, longs)
200+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
200201

201-
Integers are 8 or 16 bit numbers and can be written in normal decimal notation,
202+
Integers are 8, 16 or 32 bit numbers and can be written in normal decimal notation,
202203
in hexadecimal and in binary notation. There is no octal notation. Hexadecimal has the '$' prefix,
203204
binary has the '%' prefix. Note that ``%`` is also the remainder operator so be careful: if you want to take the remainder
204205
of something with an operand starting with 1 or 0, you'll have to add a space in between, otherwise
@@ -210,7 +211,9 @@ For instance ``3_000_000`` is a valid decimal number and so is ``%1001_0001`` a
210211
A single character in single quotes such as ``'a'`` is translated into a byte integer,
211212
which is the PETSCII value for that character. You can prefix it with the desired encoding, like with strings, see :ref:`encodings`.
212213

213-
**bytes versus words:**
214+
*Endianness:* all integers are stored in *little endian* byte order, so the Least significant byte first and the Most significant byte last.
215+
216+
**bytes versus words versus longs:**
214217

215218
Prog8 tries to determine the data type of integer values according to the table below,
216219
and sometimes the context in which they are used.
@@ -222,7 +225,7 @@ value datatype
222225
0 .. 255 ubyte
223226
-32768 .. 32767 word
224227
0 .. 65535 uword
225-
-2147483647 .. 2147483647 long (only for const)
228+
-2147483647 .. 2147483647 long (there is no unsigned long right now)
226229
========================= =================
227230

228231
If the number fits in a byte but you really require it as a word value, you'll have to explicitly cast it: ``60 as uword``
@@ -233,15 +236,21 @@ to be done on word values, and don't want to explicitly have to cast everything
233236
uword offset = column * 64 ; does (column * 64) as uword, wrong result?
234237
uword offset = column * $0040 ; does (column as uword) * 64 , a word calculation
235238

236-
Only for ``const`` numbers, you can use larger values (32 bits signed integers). The compiler can handle those
237-
internally in expressions. As soon as you have to actually store it into a variable,
238-
you have to make sure the resulting value fits into the byte or word size of the variable.
239-
240239
.. attention::
241240
Doing math on signed integers can result in code that is a lot larger and slower than
242241
when using unsigned integers. Make sure you really need the signed numbers, otherwise
243242
stick to unsigned integers for efficiency.
244243

244+
.. attention::
245+
Not all operations on Long integers are supported at the moment, although most common
246+
operations should work fine.
247+
There is no unsigned long type at the moment, but you can sometimes simply treat the signed
248+
long value as an unsigned 32 bits value just fine.
249+
Operations on long integers take a lot of instructions on 8 bit cpu's so code that uses them
250+
a lot will be much slower than when you restrict yourself to 8 or 16 bit values. Use long values sparingly.
251+
**Several operations on long values require the use of the R0 and R1 virtual register as temporary storage**
252+
so if you are working with long values, you should assume that the contents of R0 and R1 are destroyed.
253+
245254

246255
Booleans
247256
^^^^^^^^
@@ -538,7 +547,7 @@ Constants
538547
When using ``const``, the value of the 'variable' cannot be changed; it has become a compile-time constant value instead.
539548
You'll have to specify the initial value expression. This value is then used
540549
by the compiler everywhere you refer to the constant (and no memory is allocated
541-
for the constant itself). Onlythe simple numeric types (byte, word, float) can be defined as a constant.
550+
for the constant itself). Onlythe simple numeric types (byte, word, long, float) can be defined as a constant.
542551
If something is defined as a constant, very efficient code can usually be generated from it.
543552
Variables on the other hand can't be optimized as much, need memory, and more code to manipulate them.
544553
Note that a subset of the library routines in the ``math``, ``strings`` and ``floats`` modules are recognised in

examples/test.p8

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,15 @@
11
%import textio
2-
%import math
3-
%import verafx
42
%zeropage basicsafe
53

64
main {
7-
%option verafxmuls
8-
95
sub start() {
6+
&long ll = 5000
107

11-
cx16.r5s = 22
12-
cx16.r6s = -999
13-
14-
cx16.r0s = cx16.r5s * cx16.r6s
15-
txt.print_w(cx16.r0s)
16-
txt.nl()
17-
18-
long lv = cx16.r5s * cx16.r6s
19-
txt.print_l(lv)
20-
txt.nl()
21-
8+
ll = $9988776655
229

23-
cx16.r5s = 5555
24-
cx16.r6s = -9999
25-
lv = cx16.r5s * cx16.r6s
26-
txt.print_l(lv)
27-
txt.nl()
28-
lv = verafx.muls(cx16.r5s, cx16.r6s)
29-
txt.print_l(lv)
30-
txt.nl()
10+
txt.print_ubhex(@(5000), false)
11+
txt.print_ubhex(@(5001), false)
12+
txt.print_ubhex(@(5002), false)
13+
txt.print_ubhex(@(5003), false)
3114
}
3215
}

0 commit comments

Comments
 (0)