added gfx_line function

This commit is contained in:
Irmen de Jong 2018-10-01 01:01:39 +02:00
parent 6d343bd75d
commit b96bb23a54
7 changed files with 157 additions and 9 deletions

View File

@ -0,0 +1,96 @@
%option enable_floats
~ irq {
word global_time
byte time_changed
sub irq() {
global_time++
time_changed = 1
}
}
~ main {
const word width = 320
const word height = 200
float x1 = -1.0
float y1 = 1.0
float x2 = 1.0
float y2 = 1.0
float x3 = 1.0
float y3 = -1.0
float x4 = -1.0
float y4 = -1.0
float rx1
float rx2
float rx3
float rx4
float ry1
float ry2
float ry3
float ry4
sub start() {
float t
_vm_gfx_clearscr(0)
while(1) {
if irq.time_changed {
irq.time_changed = 0
_vm_gfx_clearscr(0)
_vm_gfx_text(130, 80, 5, "Spin !!!")
t = flt(irq.global_time) / 60.0
rotate_all(t)
plot_pixels()
}
}
}
sub rotate_all(t: float) {
rx1 = x1 * cos(t) - y1 * sin(t)
ry1 = x1 * sin(t) + y1 * cos(t)
rx2 = x2 * cos(t) - y2 * sin(t)
ry2 = x2 * sin(t) + y2 * cos(t)
rx3 = x3 * cos(t) - y3 * sin(t)
ry3 = x3 * sin(t) + y3 * cos(t)
rx4 = x4 * cos(t) - y4 * sin(t)
ry4 = x4 * sin(t) + y4 * cos(t)
}
sub plot_pixels() {
word sx1
word sx2
word sx3
word sx4
word sy1
word sy2
word sy3
word sy4
sx1 = floor(rx1 * height/3 + width/2)
sx2 = floor(rx2 * height/3 + width/2)
sx3 = floor(rx3 * height/3 + width/2)
sx4 = floor(rx4 * height/3 + width/2)
sy1 = floor(ry1 * height/3 + height/2)
sy2 = floor(ry2 * height/3 + height/2)
sy3 = floor(ry3 * height/3 + height/2)
sy4 = floor(ry4 * height/3 + height/2)
_vm_gfx_line(sx1, sy1, sx2, sy2, 1)
_vm_gfx_line(sx2, sy2, sx3, sy3, 7)
_vm_gfx_line(sx3, sy3, sx4, sy4, 10)
_vm_gfx_line(sx4, sy4, sx1, sy1, 14)
}
}

View File

@ -0,0 +1,25 @@
%option enable_floats
~ main {
sub start() {
_vm_gfx_clearscr(0)
_vm_gfx_text(5, 5, 7, "Swirl !!!")
const word width = 320
const word height = 200
float x
float y
float t
byte color
while(1) {
x = ((sin(t*1.01) +cos(t*1.1234)) * width/4.1) + width/2
y = ((cos(t)+sin(t*0.03456)) * height/4.1) + height/2
_vm_gfx_pixel(floor(x),floor(y), color//16)
t += 0.01
color++
}
}
}

View File

@ -201,8 +201,12 @@ class AstChecker(private val namespace: INameScope,
.filter { it is InlineAssembly }
.map { (it as InlineAssembly).assembly }
.count { "rts" in it || "\trts" in it || "jmp" in it || "\tjmp" in it }
if (amount == 0 && subroutine.returnvalues.isNotEmpty())
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
if (amount == 0) {
if(subroutine.returnvalues.isNotEmpty())
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
// if there's no return statement, we add the implicit one at the end.
subroutine.statements.add(Return(emptyList(), subroutine.position))
}
}
}
@ -530,7 +534,7 @@ class AstChecker(private val namespace: INameScope,
else {
for (arg in args.withIndex().zip(func.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) !in arg.second.possibleDatatypes)
checkResult.add(SyntaxError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
}
}
} else if(target is Subroutine) {
@ -539,7 +543,7 @@ class AstChecker(private val namespace: INameScope,
else {
for (arg in args.withIndex().zip(target.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) != arg.second.type)
checkResult.add(SyntaxError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
}
}
}

View File

@ -68,6 +68,12 @@ val BuiltinFunctions = mapOf(
BuiltinFunctionParam("x", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("y", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("color", listOf(DataType.BYTE))), null),
"_vm_gfx_line" to FunctionSignature(false, listOf(
BuiltinFunctionParam("x1", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("y1", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("x2", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("y2", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("color", listOf(DataType.BYTE))), null),
"_vm_gfx_text" to FunctionSignature(false, listOf(
BuiltinFunctionParam("x", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("y", listOf(DataType.BYTE, DataType.WORD)),

View File

@ -37,12 +37,17 @@ class BitmapScreenPanel : JPanel() {
fun setPixel(x: Int, y: Int, color: Int) {
image.setRGB(x, y, palette[color and 15].rgb)
}
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Int) {
g2d.color = palette[color and 15]
g2d.drawLine(x1, y1, x2, y2)
}
fun writeText(x: Int, y: Int, text: String, color: Int) {
g2d.font = Font(Font.MONOSPACED, Font.PLAIN, 10)
g2d.color = palette[color and 15]
g2d.drawString(text, x, y + g2d.font.size - 1)
}
companion object {
const val SCREENWIDTH = 320
const val SCREENHEIGHT = 200

View File

@ -131,6 +131,7 @@ enum class Syscall(val callNr: Short) {
GFX_PIXEL(16), // plot a pixel at (x,y,color) pushed on stack in that order
GFX_CLEARSCR(17), // clear the screen with color pushed on stack
GFX_TEXT(18), // write text on screen at (x,y,color,text) pushed on stack in that order
GFX_LINE(19), // draw line on screen at (x1,y1,x2,y2,color) pushed on stack in that order
FUNC_SIN(66),
FUNC_COS(67),
@ -277,9 +278,9 @@ class StackVm(private var traceOutputFile: String?) {
irqStartInstruction = program.labels["irq.irq"]
}
fun step(instructionCount: Int = 10000) {
fun step(instructionCount: Int = 5000) {
// step is invoked every 1/100 sec
// we execute 10k instructions in one go so we end up doing 1 million vm instructions per second
// we execute 5k instructions in one go so we end up doing 0.5 million vm instructions per second
val start = System.currentTimeMillis()
for(i:Int in 1..instructionCount) {
try {
@ -494,6 +495,13 @@ class StackVm(private var traceOutputFile: String?) {
val (y, x) = evalstack.pop2()
canvas?.setPixel(x.integerValue(), y.integerValue(), color.integerValue())
}
Syscall.GFX_LINE -> {
// draw line at (x1, y1, x2, y2, color) from stack
val color = evalstack.pop()
val (y2, x2) = evalstack.pop2()
val (y1, x1) = evalstack.pop2()
canvas?.drawLine(x1.integerValue(), y1.integerValue(), x2.integerValue(), y2.integerValue(), color.integerValue())
}
Syscall.GFX_CLEARSCR -> {
val color = evalstack.pop()
canvas?.clearScreen(color.integerValue())

View File

@ -116,16 +116,20 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
return when(leftDt) {
DataType.BYTE -> {
// BYTE can become WORD if right operand is WORD, or when value is too large for byte
if(result.toDouble() >= 256)
if(result.toDouble() >= 256 && rightDt!=DataType.FLOAT)
return Value(DataType.WORD, result)
when(rightDt) {
DataType.BYTE -> Value(DataType.BYTE, result)
DataType.WORD -> Value(DataType.WORD, result)
DataType.FLOAT -> throw VmExecutionException("floating point loss of precision")
DataType.FLOAT -> throw VmExecutionException("floating point loss of precision on byte")
else -> throw VmExecutionException("$op on non-numeric result type")
}
}
DataType.WORD -> Value(DataType.WORD, result)
DataType.WORD -> {
if(rightDt==DataType.FLOAT)
throw VmExecutionException("floating point loss of precision on word")
Value(DataType.WORD, result)
}
DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("$op on non-numeric type")
}