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:
parent
b8e5e71c19
commit
3187ed155e
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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: <=, >
|
||||
}
|
||||
|
12
src/main/scala/millfork/env/Environment.scala
vendored
12
src/main/scala/millfork/env/Environment.scala
vendored
@ -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")
|
||||
}
|
||||
|
@ -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]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user