diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index c134de706..07f4ce704 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -912,7 +912,7 @@ class AstChecker(private val namespace: INameScope, 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)) 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 checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position)) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index d11ac2d51..cd5645867 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -740,7 +740,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, // word + word -> word // 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) { DataType.UBYTE -> { diff --git a/compiler/src/prog8/stackvm/ScreenDialog.kt b/compiler/src/prog8/stackvm/ScreenDialog.kt index 92b9f4bd1..51b93c228 100644 --- a/compiler/src/prog8/stackvm/ScreenDialog.kt +++ b/compiler/src/prog8/stackvm/ScreenDialog.kt @@ -3,14 +3,15 @@ package prog8.stackvm import prog8.compiler.target.c64.Charset import prog8.compiler.target.c64.Petscii import java.awt.* +import java.awt.event.KeyEvent +import java.awt.event.KeyListener import java.awt.image.BufferedImage -import javax.swing.JButton import javax.swing.JFrame import javax.swing.JPanel import javax.swing.Timer -class BitmapScreenPanel : JPanel() { +class BitmapScreenPanel : KeyListener, JPanel() { private val image = BufferedImage(SCREENWIDTH, SCREENHEIGHT, BufferedImage.TYPE_INT_ARGB) private val g2d = image.graphics as Graphics2D @@ -21,6 +22,19 @@ class BitmapScreenPanel : JPanel() { maximumSize = size preferredSize = size 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?) { @@ -90,7 +104,6 @@ class BitmapScreenPanel : JPanel() { class ScreenDialog : JFrame() { val canvas = BitmapScreenPanel() - private val buttonQuit = JButton("Quit") init { val borderWidth = 16 @@ -99,17 +112,6 @@ class ScreenDialog : JFrame() { defaultCloseOperation = JFrame.EXIT_ON_CLOSE 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) val borderTop = JPanel().apply { 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) background = BitmapScreenPanel.palette[14] } - c = GridBagConstraints() + var c = GridBagConstraints() c.gridx=0; c.gridy=1; c.gridwidth=3 add(borderTop, c) c = GridBagConstraints() @@ -144,9 +146,7 @@ class ScreenDialog : JFrame() { c.gridx = 1; c.gridy = 2 add(canvas, c) - getRootPane().defaultButton = buttonQuit - buttonQuit.addActionListener { _ -> onOK() } - + canvas.requestFocusInWindow() } fun start() { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 9d07c38c6..597a76592 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -383,6 +383,7 @@ class StackVm(private var traceOutputFile: String?) { this.program = program.program this.heap = program.heap this.canvas = canvas + canvas?.requestFocusInWindow() variables.clear() for(variable in program.variables.flatMap { e->e.value.entries }) variables[variable.key] = variable.value diff --git a/docs/source/programming.rst b/docs/source/programming.rst index e3c6f8e54..08c7f8c3b 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -216,8 +216,6 @@ for instance. There must be a way to tell the compiler which variables you require to be in Zeropage: ``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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -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, which is the Petscii value for that character. -.. todo:: - Right now only unsinged integers are supported (0-255 for byte types, 0-65535 for word types) - @todo maybe signed integers (-128..127 and -32768..32767) will be added later +Unsigned integers are in the range 0-255 for unsigned byte types, and 0-65535 for unsigned word types. +The signed integers integers are in the range -128..127 for bytes, +and -32768..32767 for words. 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. 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. -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. .. caution:: diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 63221f181..e4dcc4612 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -232,17 +232,22 @@ Prog8 supports the following data types: =============== ======================= ================= ========================================= 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`` The true and false are actually just aliases 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`` stored in 5-byte cbm MFLPT format -``byte[x]`` unsigned 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]`` +``byte[x]`` signed byte array x bytes ``byte[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]`` -``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."`` implicitly terminated by a 0-byte ``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:** -- When an integer value ranges from 0..255 the compiler sees it as a ``byte``. -- When an integer value ranges from 256..65535 the compiler sees it as a ``word``. +- 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 ``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 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``. @@ -276,8 +281,6 @@ type identifier type storage size example var declara **@todo pointers/addresses? (as opposed to normal WORDs)** - **@todo signed integers (byte and word)?** - Memory mapped variables ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/targetsystem.rst b/docs/source/targetsystem.rst index 79f7edb1b..348b198c1 100644 --- a/docs/source/targetsystem.rst +++ b/docs/source/targetsystem.rst @@ -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 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 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). -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. -This means the code that calls a subroutine that clobbers certain -registers (``A``, ``X`` or ``Y``), is responsible for storing and restoring the original values if -those values are needed by the rest of the code. +**Normal user defined subroutines:** +Arguments and result values are passed via global variables stored in memory. +*These are not allocated on a stack* so it is not possible to create recursive calls. -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.