mirror of
https://github.com/irmen/prog8.git
synced 2025-01-14 01:29:55 +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))
|
||||
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))
|
||||
|
||||
|
@ -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 -> {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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::
|
||||
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user