1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-22 16:31:02 +00:00

Add signed16 and unsigned16 types

This commit is contained in:
Karol Stasiak 2020-03-25 23:53:26 +01:00
parent b8e5e71c19
commit 3187ed155e
7 changed files with 165 additions and 26 deletions

View File

@ -12,6 +12,8 @@
* **Potentially breaking change!** Added `min`, `max` and `if` compile-time functions.
* Added experimental `signed16` and `unsigned16` types.
* Added warnings for calling from one segment to another overlapping one.
* 6502: Fixed undocumented mnemonics.

View File

@ -20,11 +20,15 @@ Millfork puts extra limitations on which types can be used in which contexts.
* `long` 4-byte value of undefined signedness, defaulting to unsigned
(alias: `int32`)
* `int40`, `int48`,... `int128` even larger unsigned types
* `int40`, `int48`,... `int128` even larger types of undefined signedness, defaulting to unsigned
* `sbyte` signed 1-byte value
* `sbyte` signed 1-byte value (alias: `signed8`)
* `ubyte` unsigned 1-byte value
* `ubyte` unsigned 1-byte value (alias: `unsigned8`)
* `signed16` signed 2-byte value (experimental)
* `unsigned16` unsigned 2-byte value (experimental)
* `pointer` raw pointers; the same as `word`, but variables of this type default to be zero-page-allocated
and you can index `pointer`-typed expressions.

View File

@ -1,5 +1,6 @@
package millfork.compiler
import millfork.CompilationFlag
import millfork.env._
import millfork.node._
import millfork.error.{ConsoleLogger, Logger}
@ -408,13 +409,28 @@ object AbstractExpressionCompiler {
if (getExpressionTypeImpl(env, log, hi, loosely).size > 1) log.error("Hi byte too large", hi.position)
if (getExpressionTypeImpl(env, log, lo, loosely).size > 1) log.error("Lo byte too large", lo.position)
w
case SumExpression(params, _) => params.map { case (_, e) => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
case 1 => b
case 2 => w
case 3 => env.get[Type]("int24")
case 4 => env.get[Type]("int32")
case _ => log.error("Adding values bigger than longs", expr.position); env.get[Type]("int32")
}
case SumExpression(params, _) =>
val paramTypes = params.map { case (_, e) => getExpressionTypeImpl(env, log, e, loosely) }
val anySigned = paramTypes.exists(_.isSigned)
val anyUnsigned = paramTypes.exists {
case p: DerivedPlainType => !p.isSigned
case _ => false
}
paramTypes.map(_.size).max match {
case 1 =>
params match {
case List((false, LiteralExpression(0, _)), (true, _)) if !anyUnsigned => env.get[Type]("sbyte")
case _ => if (anySigned && !anyUnsigned) env.get[Type]("sbyte") else b
}
case 2 =>
params match {
case List((false, LiteralExpression(0, _)), (true, _)) if !anyUnsigned => env.get[Type]("signed16")
case _ => if (anySigned && !anyUnsigned) env.get[Type]("signed16") else w
}
case 3 => env.get[Type]("int24")
case 4 => env.get[Type]("int32")
case _ => log.error("Adding values bigger than longs", expr.position); env.get[Type]("int32")
}
case FunctionCallExpression("nonet", _) => w
case FunctionCallExpression("not", params) =>
toAllBooleanConstants(params) match {

View File

@ -982,28 +982,51 @@ object BuiltIns {
case ComparisonType.LessSigned =>
val fixup = ctx.nextLabel("co")
cmpTo(LDA, ll) ++
List(AssemblyLine.implied(SEC)) ++
cmpTo(SBC, rl) ++
cmpTo(CMP, rl) ++
cmpTo(LDA, lh) ++
cmpTo(SBC, rh) ++
List(
AssemblyLine.relative(BVC, fixup),
AssemblyLine.immediate(EOR, 0x80),
AssemblyLine.label(fixup))
List(AssemblyLine.relative(BCC, x))
AssemblyLine.label(fixup))++
List(AssemblyLine.relative(BMI, x))
case ComparisonType.GreaterOrEqualSigned =>
val fixup = ctx.nextLabel("co")
cmpTo(LDA, ll) ++
List(AssemblyLine.implied(SEC)) ++
cmpTo(SBC, rl) ++
cmpTo(CMP, rl) ++
cmpTo(LDA, lh) ++
cmpTo(SBC, rh) ++
List(
AssemblyLine.relative(BVC, fixup),
AssemblyLine.immediate(EOR, 0x80),
AssemblyLine.label(fixup))
List(AssemblyLine.relative(BCS, x))
AssemblyLine.label(fixup))++
List(AssemblyLine.relative(BPL, x))
case ComparisonType.GreaterSigned =>
val fixup = ctx.nextLabel("co")
cmpTo(LDA, rl) ++
cmpTo(CMP, ll) ++
cmpTo(LDA, rh) ++
cmpTo(SBC, lh) ++
List(
AssemblyLine.relative(BVC, fixup),
AssemblyLine.immediate(EOR, 0x80),
AssemblyLine.label(fixup))++
List(AssemblyLine.relative(BMI, x))
case ComparisonType.LessOrEqualSigned =>
val fixup = ctx.nextLabel("co")
cmpTo(LDA, rl) ++
cmpTo(CMP, ll) ++
cmpTo(LDA, rh) ++
cmpTo(SBC, lh) ++
List(
AssemblyLine.relative(BVC, fixup),
AssemblyLine.immediate(EOR, 0x80),
AssemblyLine.label(fixup))++
List(AssemblyLine.relative(BPL, x))
case _ => ???
// TODO: signed word comparisons: <=, >
}

View File

@ -431,12 +431,13 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(Alias("unsigned8", "ubyte"), None)
addThing(Alias("signed8", "sbyte"), None)
addThing(DerivedPlainType("unsigned16", w, isSigned = false, isPointy = false), None)
addThing(DerivedPlainType("signed16", w, isSigned = true, isPointy = false), None)
for (bits <- Seq(24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128)) {
addThing(DerivedPlainType("unsigned" + bits, get[BasicPlainType]("int" + bits), isSigned = false, isPointy = false), None)
}
if (options.flag(CompilationFlag.EnableInternalTestSyntax)) {
for (bits <- Seq(16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128)) {
addThing(DerivedPlainType("signed" + bits, get[BasicPlainType]("int" + bits), isSigned = false, isPointy = false), None)
for (bits <- Seq(24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128)) {
addThing(DerivedPlainType("signed" + bits, get[BasicPlainType]("int" + bits), isSigned = true, isPointy = false), None)
}
}
val trueType = ConstantBooleanType("true$", value = true)
@ -2418,9 +2419,10 @@ object Environment {
val invalidNewIdentifiers: Set[String] = Set(
"byte", "sbyte", "word", "pointer", "void", "long", "bool",
"set_carry", "set_zero", "set_overflow", "set_negative",
"clear_carry", "clear_zero", "clear_overflow", "clear_negative",
"int8", "int16", "int24", "int32", "int40", "int48", "int56", "int64", "int72", "int80", "int88", "int96", "int104", "int112", "int120", "int128",
"signed8", "unsigned16") ++ neverValidTypeIdentifiers
"clear_carry", "clear_zero", "clear_overflow", "clear_negative") ++
Seq.iterate(8, 16)(_ + 8).map("int" + _) ++
Seq.iterate(8, 16)(_ + 8).map("unsigned" + _) ++
Seq.iterate(8, 16)(_ + 8).map("signed" + _) ++ neverValidTypeIdentifiers
// built-in special-cased field names; can be considered keywords by some:
val invalidFieldNames: Set[String] = Set("addr", "rawaddr", "pointer", "return")
}

View File

@ -1,13 +1,13 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuSuperOptimizedRun, EmuUltraBenchmarkRun, EmuUnoptimizedCrossPlatformRun}
import org.scalatest.{FunSuite, Matchers}
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuSuperOptimizedRun, EmuUltraBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun}
import org.scalatest.{AppendedClues, FunSuite, Matchers}
/**
* @author Karol Stasiak
*/
class ComparisonSuite extends FunSuite with Matchers {
class ComparisonSuite extends FunSuite with Matchers with AppendedClues {
test("Equality and inequality") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
@ -653,4 +653,48 @@ class ComparisonSuite extends FunSuite with Matchers {
}
}
test("Signed16 comparisons") {
for{
x <- Seq(-30000, -10000, -1, 0, 1, 10000, 30000)
y <- Seq(-30000, -10000, -1, 0, 1, 10000, 30000)
} {
val code =
s"""
| byte output @$$c000
|
| const sbyte convert(bool f) {
| if f { return 1 }
| return -1
| }
|
| noinline void testGE(signed16 x, signed16 y, sbyte f) {
| if x >= y { output += f } else { output -= f }
| }
|
| noinline void testLE(signed16 x, signed16 y, sbyte f) {
| if x <= y { output += f } else { output -= f }
| }
|
| noinline void testL(signed16 x, signed16 y, sbyte f) {
| if x < y { output += f } else { output -= f }
| }
|
| noinline void testG(signed16 x, signed16 y, sbyte f) {
| if x > y { output += f } else { output -= f }
| }
|
| void main() {
| output = 0
| testGE($x, $y, convert(${x >= y}))
| testLE($x, $y, convert(${x <= y}))
| testG($x, $y, convert(${x > y}))
| testL($x, $y, convert(${x < y}))
| }
|""".stripMargin
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code) { m =>
m.readByte(0xc000) should equal (4) withClue s"[$x <=> $y]"
}
}
}
}

View File

@ -124,4 +124,52 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
}
test("The silliest thing") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
|word output @$c000
|word output2 @$c002
|void main() {
| output = -1
| output2 = -30000
|}
|""".stripMargin) { m =>
m.readWord(0xc000) should equal(0xffff)
m.readWord(0xc002).toShort.toInt should equal(-30000)
}
}
test("Signed16 to int32 extension") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
"""
|int32 output @$c000
|
|void main() {
| static volatile signed16 tmp
| tmp = -1
| memory_barrier()
| output = tmp
|}
|""".stripMargin){ m =>
m.readLong(0xc000) should equal(-1)
}
}
test("Signed16 to int32 extension 2") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
"""
|int32 output @$c000
|
|void main() {
| static volatile signed16 tmp
| tmp = -1
| output = 0
| memory_barrier()
| output += tmp
|}
|""".stripMargin){ m =>
m.readLong(0xc000) should equal(-1)
}
}
}