This commit is contained in:
Irmen de Jong 2018-10-12 18:01:40 +02:00
parent 7aec14524e
commit 987915a77a
7 changed files with 44 additions and 59 deletions

View File

@ -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))

View File

@ -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 -> {

View File

@ -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() {

View File

@ -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

View File

@ -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::

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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.