mirror of
https://github.com/irmen/prog8.git
synced 2024-10-18 01:24:51 +00:00
doc
This commit is contained in:
parent
7aec14524e
commit
987915a77a
@ -912,7 +912,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
if((sourceDatatype==DataType.UWORD || sourceDatatype==DataType.WORD) && (targetDatatype==DataType.UBYTE || targetDatatype==DataType.BYTE))
|
if((sourceDatatype==DataType.UWORD || sourceDatatype==DataType.WORD) && (targetDatatype==DataType.UBYTE || targetDatatype==DataType.BYTE))
|
||||||
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
|
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
|
||||||
else if(sourceDatatype==DataType.FLOAT && targetDatatype in IntegerDatatypes)
|
else if(sourceDatatype==DataType.FLOAT && targetDatatype in IntegerDatatypes)
|
||||||
checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.toString().toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to byte/word arithmetic", position))
|
checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.toString().toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position))
|
||||||
else
|
else
|
||||||
checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position))
|
checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position))
|
||||||
|
|
||||||
|
@ -740,7 +740,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
// word + word -> word
|
// word + word -> word
|
||||||
// a combination with a float will be float (but give a warning about this!)
|
// a combination with a float will be float (but give a warning about this!)
|
||||||
|
|
||||||
val floatWarning = "byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion, a float number, or revert to byte/word arithmetic"
|
val floatWarning = "byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion, a float number, or revert to integer arithmetic"
|
||||||
|
|
||||||
return when(leftDt) {
|
return when(leftDt) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
|
@ -3,14 +3,15 @@ package prog8.stackvm
|
|||||||
import prog8.compiler.target.c64.Charset
|
import prog8.compiler.target.c64.Charset
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
import java.awt.event.KeyListener
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import javax.swing.JButton
|
|
||||||
import javax.swing.JFrame
|
import javax.swing.JFrame
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
import javax.swing.Timer
|
import javax.swing.Timer
|
||||||
|
|
||||||
|
|
||||||
class BitmapScreenPanel : JPanel() {
|
class BitmapScreenPanel : KeyListener, JPanel() {
|
||||||
|
|
||||||
private val image = BufferedImage(SCREENWIDTH, SCREENHEIGHT, BufferedImage.TYPE_INT_ARGB)
|
private val image = BufferedImage(SCREENWIDTH, SCREENHEIGHT, BufferedImage.TYPE_INT_ARGB)
|
||||||
private val g2d = image.graphics as Graphics2D
|
private val g2d = image.graphics as Graphics2D
|
||||||
@ -21,6 +22,19 @@ class BitmapScreenPanel : JPanel() {
|
|||||||
maximumSize = size
|
maximumSize = size
|
||||||
preferredSize = size
|
preferredSize = size
|
||||||
clearScreen(6)
|
clearScreen(6)
|
||||||
|
isFocusable = true
|
||||||
|
requestFocusInWindow()
|
||||||
|
addKeyListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyTyped(p0: KeyEvent?) {}
|
||||||
|
|
||||||
|
override fun keyPressed(p0: KeyEvent?) {
|
||||||
|
println("pressed: $p0.k")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyReleased(p0: KeyEvent?) {
|
||||||
|
println("released: $p0")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun paint(graphics: Graphics?) {
|
override fun paint(graphics: Graphics?) {
|
||||||
@ -90,7 +104,6 @@ class BitmapScreenPanel : JPanel() {
|
|||||||
|
|
||||||
class ScreenDialog : JFrame() {
|
class ScreenDialog : JFrame() {
|
||||||
val canvas = BitmapScreenPanel()
|
val canvas = BitmapScreenPanel()
|
||||||
private val buttonQuit = JButton("Quit")
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val borderWidth = 16
|
val borderWidth = 16
|
||||||
@ -99,17 +112,6 @@ class ScreenDialog : JFrame() {
|
|||||||
defaultCloseOperation = JFrame.EXIT_ON_CLOSE
|
defaultCloseOperation = JFrame.EXIT_ON_CLOSE
|
||||||
isResizable = false
|
isResizable = false
|
||||||
|
|
||||||
val buttonBar = JPanel()
|
|
||||||
buttonBar.add(buttonQuit)
|
|
||||||
|
|
||||||
var c = GridBagConstraints()
|
|
||||||
// the button bar
|
|
||||||
c.gridx = 0
|
|
||||||
c.gridy = 0
|
|
||||||
c.gridwidth = 3
|
|
||||||
c.anchor = GridBagConstraints.LINE_END
|
|
||||||
add(buttonBar, c)
|
|
||||||
|
|
||||||
// the borders (top, left, right, bottom)
|
// the borders (top, left, right, bottom)
|
||||||
val borderTop = JPanel().apply {
|
val borderTop = JPanel().apply {
|
||||||
preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
|
preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
|
||||||
@ -127,7 +129,7 @@ class ScreenDialog : JFrame() {
|
|||||||
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
|
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
|
||||||
background = BitmapScreenPanel.palette[14]
|
background = BitmapScreenPanel.palette[14]
|
||||||
}
|
}
|
||||||
c = GridBagConstraints()
|
var c = GridBagConstraints()
|
||||||
c.gridx=0; c.gridy=1; c.gridwidth=3
|
c.gridx=0; c.gridy=1; c.gridwidth=3
|
||||||
add(borderTop, c)
|
add(borderTop, c)
|
||||||
c = GridBagConstraints()
|
c = GridBagConstraints()
|
||||||
@ -144,9 +146,7 @@ class ScreenDialog : JFrame() {
|
|||||||
c.gridx = 1; c.gridy = 2
|
c.gridx = 1; c.gridy = 2
|
||||||
add(canvas, c)
|
add(canvas, c)
|
||||||
|
|
||||||
getRootPane().defaultButton = buttonQuit
|
canvas.requestFocusInWindow()
|
||||||
buttonQuit.addActionListener { _ -> onOK() }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
|
@ -383,6 +383,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
this.program = program.program
|
this.program = program.program
|
||||||
this.heap = program.heap
|
this.heap = program.heap
|
||||||
this.canvas = canvas
|
this.canvas = canvas
|
||||||
|
canvas?.requestFocusInWindow()
|
||||||
variables.clear()
|
variables.clear()
|
||||||
for(variable in program.variables.flatMap { e->e.value.entries })
|
for(variable in program.variables.flatMap { e->e.value.entries })
|
||||||
variables[variable.key] = variable.value
|
variables[variable.key] = variable.value
|
||||||
|
@ -216,8 +216,6 @@ for instance.
|
|||||||
There must be a way to tell the compiler which variables you require to be in Zeropage:
|
There must be a way to tell the compiler which variables you require to be in Zeropage:
|
||||||
``zeropage`` modifier keyword on vardecl perhaps?
|
``zeropage`` modifier keyword on vardecl perhaps?
|
||||||
|
|
||||||
option to omit the array size on the vardecl if an initialization array value is given?
|
|
||||||
|
|
||||||
|
|
||||||
Variables that represent CPU hardware registers
|
Variables that represent CPU hardware registers
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -259,9 +257,9 @@ in hexadecimal and in binary notation.
|
|||||||
A single character in single quotes such as ``'a'`` is translated into a byte integer,
|
A single character in single quotes such as ``'a'`` is translated into a byte integer,
|
||||||
which is the Petscii value for that character.
|
which is the Petscii value for that character.
|
||||||
|
|
||||||
.. todo::
|
Unsigned integers are in the range 0-255 for unsigned byte types, and 0-65535 for unsigned word types.
|
||||||
Right now only unsinged integers are supported (0-255 for byte types, 0-65535 for word types)
|
The signed integers integers are in the range -128..127 for bytes,
|
||||||
@todo maybe signed integers (-128..127 and -32768..32767) will be added later
|
and -32768..32767 for words.
|
||||||
|
|
||||||
|
|
||||||
Strings
|
Strings
|
||||||
@ -273,7 +271,7 @@ but they have some special properties because they are considered to be *text*.
|
|||||||
Strings in your source code files will be encoded (translated from ASCII/UTF-8) into either CBM PETSCII or C-64 screencodes.
|
Strings in your source code files will be encoded (translated from ASCII/UTF-8) into either CBM PETSCII or C-64 screencodes.
|
||||||
PETSCII is the default choice. If you need screencodes (also called 'poke' codes) instead,
|
PETSCII is the default choice. If you need screencodes (also called 'poke' codes) instead,
|
||||||
you have to use the ``str_s`` variants of the string type identifier.
|
you have to use the ``str_s`` variants of the string type identifier.
|
||||||
If you assign a string literal of length 1 to a non-string variable, it is treated as a *byte* value instead
|
If you assign a string literal of length 1 to a non-string variable, it is treated as an *unsigned byte* value instead
|
||||||
with has the PETSCII value of that single character.
|
with has the PETSCII value of that single character.
|
||||||
|
|
||||||
.. caution::
|
.. caution::
|
||||||
|
@ -232,17 +232,22 @@ Prog8 supports the following data types:
|
|||||||
=============== ======================= ================= =========================================
|
=============== ======================= ================= =========================================
|
||||||
type identifier type storage size example var declaration and literal value
|
type identifier type storage size example var declaration and literal value
|
||||||
=============== ======================= ================= =========================================
|
=============== ======================= ================= =========================================
|
||||||
``byte`` unsigned byte 1 byte = 8 bits ``byte myvar = $8f``
|
``byte`` signed byte 1 byte = 8 bits ``byte myvar = -22``
|
||||||
|
``ubyte`` unsigned byte 1 byte = 8 bits ``ubyte myvar = $8f``
|
||||||
-- boolean 1 byte = 8 bits ``byte myvar = true`` or ``byte myvar == false``
|
-- boolean 1 byte = 8 bits ``byte myvar = true`` or ``byte myvar == false``
|
||||||
The true and false are actually just aliases
|
The true and false are actually just aliases
|
||||||
for the byte values 1 and 0.
|
for the byte values 1 and 0.
|
||||||
``word`` unsigned word 2 bytes = 16 bits ``word myvar = $8fee``
|
``word`` signed word 2 bytes = 16 bits ``word myvar = -12345``
|
||||||
|
``uword`` unsigned word 2 bytes = 16 bits ``uword myvar = $8fee``
|
||||||
``float`` floating-point 5 bytes = 40 bits ``float myvar = 1.2345``
|
``float`` floating-point 5 bytes = 40 bits ``float myvar = 1.2345``
|
||||||
stored in 5-byte cbm MFLPT format
|
stored in 5-byte cbm MFLPT format
|
||||||
``byte[x]`` unsigned byte array x bytes ``byte[4] myvar = [1, 2, 3, 4]``
|
``byte[x]`` signed byte array x bytes ``byte[4] myvar = [1, 2, 3, 4]``
|
||||||
``word[x]`` unsigned word array 2*x bytes ``word[4] myvar = [1, 2, 3, 4]``
|
``ubyte[x]`` unsigned byte array x bytes ``ubyte[4] myvar = [1, 2, 3, 4]``
|
||||||
|
``word[x]`` signed word array 2*x bytes ``word[4] myvar = [1, 2, 3, 4]``
|
||||||
|
``uword[x]`` unsigned word array 2*x bytes ``uword[4] myvar = [1, 2, 3, 4]``
|
||||||
``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]``
|
``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]``
|
||||||
``byte[x,y]`` unsigned byte matrix x*y bytes ``byte[40,25] myvar = 255``
|
``byte[x,y]`` signed byte matrix x*y bytes ``byte[40,25] myvar = 100``
|
||||||
|
``ubyte[x,y]`` unsigned byte matrix x*y bytes ``ubyte[40,25] myvar = 255``
|
||||||
``str`` string (petscii) varies ``str myvar = "hello."``
|
``str`` string (petscii) varies ``str myvar = "hello."``
|
||||||
implicitly terminated by a 0-byte
|
implicitly terminated by a 0-byte
|
||||||
``str_p`` pascal-string (petscii) varies ``str_p myvar = "hello."``
|
``str_p`` pascal-string (petscii) varies ``str_p myvar = "hello."``
|
||||||
@ -263,8 +268,8 @@ type identifier type storage size example var declara
|
|||||||
|
|
||||||
**``byte`` versus ``word`` values:**
|
**``byte`` versus ``word`` values:**
|
||||||
|
|
||||||
- When an integer value ranges from 0..255 the compiler sees it as a ``byte``.
|
- When an integer value ranges from 0..255 the compiler sees it as a ``ubyte``. For -128..127 it's a ``byte``.
|
||||||
- When an integer value ranges from 256..65535 the compiler sees it as a ``word``.
|
- When an integer value ranges from 256..65535 the compiler sees it as a ``uword``. For -32768..32767 it's a ``word``.
|
||||||
- When a hex number has 3 or 4 digits, for example ``$0004``, it is seen as a ``word`` otherwise as a ``byte``.
|
- When a hex number has 3 or 4 digits, for example ``$0004``, it is seen as a ``word`` otherwise as a ``byte``.
|
||||||
- When a binary number has 9 to 16 digits, for example ``%1100110011``, it is seen as a ``word`` otherwise as a ``byte``.
|
- When a binary number has 9 to 16 digits, for example ``%1100110011``, it is seen as a ``word`` otherwise as a ``byte``.
|
||||||
- You can force a byte value into a word value by adding the ``.w`` datatype suffix to the number: ``$2a.w`` is equivalent to ``$002a``.
|
- You can force a byte value into a word value by adding the ``.w`` datatype suffix to the number: ``$2a.w`` is equivalent to ``$002a``.
|
||||||
@ -276,8 +281,6 @@ type identifier type storage size example var declara
|
|||||||
|
|
||||||
**@todo pointers/addresses? (as opposed to normal WORDs)**
|
**@todo pointers/addresses? (as opposed to normal WORDs)**
|
||||||
|
|
||||||
**@todo signed integers (byte and word)?**
|
|
||||||
|
|
||||||
|
|
||||||
Memory mapped variables
|
Memory mapped variables
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -124,35 +124,18 @@ The following 6502 CPU hardware registers are directly usable in program code (a
|
|||||||
- the status register (P) carry flag and interrupt disable flag can be written via a couple of special
|
- the status register (P) carry flag and interrupt disable flag can be written via a couple of special
|
||||||
builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``)
|
builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``)
|
||||||
|
|
||||||
|
However, you must assume that the 3 hardware registers ``A``, ``X`` and ``Y``
|
||||||
|
are volatile. Their values cannot be depended upon, the compiler will use them as required.
|
||||||
|
|
||||||
|
|
||||||
Subroutine Calling Conventions
|
Subroutine Calling Conventions
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
Subroutine arguments and results are passed via registers.
|
**Kernel/asm subroutines:**
|
||||||
|
Arguments and results are passed via registers.
|
||||||
Sometimes the status register's Carry flag is used as well (as a boolean flag).
|
Sometimes the status register's Carry flag is used as well (as a boolean flag).
|
||||||
Additional arguments can be passed via memory locations as well ofcourse.
|
|
||||||
But you'll have to be careful when dealing with chained or even recursive calls then,
|
|
||||||
because there's a big risk of overwriting those memory locations.
|
|
||||||
|
|
||||||
In Prog8 the "caller saves" principle applies to calling subroutines.
|
**Normal user defined subroutines:**
|
||||||
This means the code that calls a subroutine that clobbers certain
|
Arguments and result values are passed via global variables stored in memory.
|
||||||
registers (``A``, ``X`` or ``Y``), is responsible for storing and restoring the original values if
|
*These are not allocated on a stack* so it is not possible to create recursive calls.
|
||||||
those values are needed by the rest of the code.
|
|
||||||
|
|
||||||
Normally, registers are *not* preserved when calling a subroutine or when a certian
|
|
||||||
operations are performed. Most calls will be simply a few instructions to load the
|
|
||||||
values in the registers and then a ``JSR`` or ``JMP``.
|
|
||||||
|
|
||||||
By using the ``%saveregisters`` directive in a block, you can tell the
|
|
||||||
compiler to preserve all registers. This does generate a lot of extra code that puts
|
|
||||||
original values on the stack and gets them off the stack again once the subroutine is done.
|
|
||||||
In this case however you don't have to worry about ``A``, ``X`` and ``Y`` losing their original values
|
|
||||||
and you can essentially treat them as three local variables instead of scratch data.
|
|
||||||
|
|
||||||
You can also use a ``!`` on a single subroutine call to preserve register values, instead of
|
|
||||||
setting this behavior for the entire block.
|
|
||||||
|
|
||||||
.. important::
|
|
||||||
Basically, you should assume that the 3 hardware registers ``A``, ``X`` and ``Y``
|
|
||||||
are volatile. Their values cannot be depended upon, unless you explicitly make sure otherwise.
|
|
||||||
|
Loading…
Reference in New Issue
Block a user