mirror of
https://github.com/KarolS/millfork.git
synced 2024-12-27 04:29:34 +00:00
Add TRS-80 Model 1 and 3 support
This commit is contained in:
parent
3702002541
commit
3a9be16107
1
.gitignore
vendored
1
.gitignore
vendored
@ -50,6 +50,7 @@ issue*.mfk
|
||||
*.rom
|
||||
*.ssd
|
||||
*.o
|
||||
*.cmd
|
||||
HELLO
|
||||
HELLOCPC
|
||||
FIZZBUZZ
|
||||
|
@ -22,7 +22,7 @@ For build instructions, see [Build instructions](./COMPILING.md).
|
||||
|
||||
* other 6502-based machines: Famicom/NES, Atari Lynx, Atari 8-bit computers, BBC Micro, Apple II+/IIe/Enhanced IIe, Atari 2600 (experimental), Commander X16 (experimental)
|
||||
|
||||
* Z80-based machines: ZX Spectrum 48k, NEC PC-88, Amstrad CPC, MSX
|
||||
* Z80-based machines: ZX Spectrum 48k, NEC PC-88, Amstrad CPC, MSX, TRS-80 Model 1 and 3
|
||||
|
||||
* CP/M
|
||||
|
||||
|
@ -229,6 +229,8 @@ Default: `main,*`
|
||||
* `d88` - a D88 floppy disk image for PC-88
|
||||
|
||||
* `tap` - a tape disk image for ZX Spectrum
|
||||
|
||||
* `trscmd` - a chunked loadable executable for TRS-80 Model 1 or 3 running TRS-DOS, also known as the /CMD format
|
||||
|
||||
* `format_segment_NAME` – if using the `per_segment` style, overrides the format for the given segment
|
||||
|
||||
|
@ -99,6 +99,10 @@ The compiler emits COM files.
|
||||
|
||||
* `cpm_z80` – CP/M on Z80
|
||||
|
||||
* `trs80m1cmd` – TRS-80 Model 1 running TRS-DOS. The compiler emits CMD files.
|
||||
|
||||
* `trs80m3cmd` – TRS-80 Model 3 running TRS-DOS. The compiler emits CMD files.
|
||||
|
||||
* `coco_rsdos` – Tandy Color Computer running RS-DOS. (very experimental)
|
||||
Read [the Color Computer programming guide](./coco-programming-guide.md) for more info.
|
||||
|
||||
|
@ -29,13 +29,13 @@ If you are using a release version of the compiler, consider browsing the older
|
||||
|
||||
* [Echo](crossplatform/echo.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX)– simple text input and output
|
||||
|
||||
* [Calculator](crossplatform/calculator.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) – simple numeric input and output
|
||||
* [Calculator](crossplatform/calculator.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX/TRS-80) – simple numeric input and output
|
||||
|
||||
* [Guessing game](crossplatform/guess.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) – a guess-a-number game
|
||||
* [Guessing game](crossplatform/guess.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX/TRS-80) – a guess-a-number game
|
||||
|
||||
* [Fire effect](crossplatform/fire.mfk) (C64/C16/ZX Spectrum) – a simple fire effect
|
||||
|
||||
* [`readkey` test](crossplatform/readkeytest.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/Armstrad CPC/ZX Spectrum/PC-88) – keyboard reading test
|
||||
* [`readkey` test](crossplatform/readkeytest.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/Armstrad CPC/ZX Spectrum/PC-88/TRS-80) – keyboard reading test
|
||||
|
||||
* [Screen encoding test](crossplatform/screnctest.mfk) (C64/C16) – default-to-screen encoding conversion test
|
||||
|
||||
|
@ -4,7 +4,7 @@ import stdio
|
||||
import c64_basic
|
||||
#elseif CBM_264
|
||||
import c264_basic
|
||||
#elseif ZX_SPECTRUM || NEC_PC_88
|
||||
#elseif ZX_SPECTRUM || NEC_PC_88 || TRS80
|
||||
// no imports needed
|
||||
#else
|
||||
#error Unsupported platform
|
||||
|
@ -1,8 +1,2 @@
|
||||
|
||||
noinline asm byte readkey() {
|
||||
clr $6f
|
||||
jsr [$A000]
|
||||
beq readkey
|
||||
tfr a,b
|
||||
rts
|
||||
}
|
||||
asm byte readkey() @ $49 extern
|
||||
|
13
include/encoding/trs80m1.tbl
Normal file
13
include/encoding/trs80m1.tbl
Normal file
@ -0,0 +1,13 @@
|
||||
NAME=TRS-80-Model-1
|
||||
EOT=00
|
||||
|
||||
20=U+0020
|
||||
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
|
||||
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ↑↓←→_
|
||||
61-7a=abcdefghijklmnopqrstuvwxyz
|
||||
|
||||
{b}=08
|
||||
{t}=09
|
||||
{n}=0d0a
|
||||
{q}=22
|
||||
{apos}=27
|
15
include/encoding/trs80m3.tbl
Normal file
15
include/encoding/trs80m3.tbl
Normal file
@ -0,0 +1,15 @@
|
||||
NAME=TRS-80-Model-3
|
||||
EOT=00
|
||||
|
||||
20=U+0020
|
||||
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
|
||||
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
60-7f=`abcdefghijklmnopqrstuvwxyz{|}~±
|
||||
|
||||
{b}=08
|
||||
{t}=09
|
||||
{n}=0d0a
|
||||
{q}=22
|
||||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
@ -149,6 +149,11 @@ import coco/keyboard
|
||||
#define OK = 1
|
||||
#endif
|
||||
|
||||
#if TRS80
|
||||
import trs80/keyboard
|
||||
#define OK = 1
|
||||
#endif
|
||||
|
||||
#if not(OK)
|
||||
#if KEYBOARD
|
||||
#warn keyboard module is not yet supported
|
||||
|
32
include/platform/trs80m1cmd.ini
Normal file
32
include/platform/trs80m1cmd.ini
Normal file
@ -0,0 +1,32 @@
|
||||
; TRS-80 Model 1 with 48K of RAM running TRS-DOS
|
||||
|
||||
[compilation]
|
||||
arch=z80
|
||||
; TODO:
|
||||
encoding=trs80m1
|
||||
screen_encoding=trs80m1
|
||||
modules=stdlib,trs80/kernal,default_panic
|
||||
|
||||
|
||||
[allocation]
|
||||
segments=default
|
||||
default_code_segment=default
|
||||
; TODO: this is what Z88DK uses:
|
||||
segment_default_start=$5200
|
||||
; assume 48K:
|
||||
segment_default_end=$ffff
|
||||
|
||||
[define]
|
||||
TRS80=1
|
||||
WIDESCREEN=0
|
||||
KEYBOARD=1
|
||||
; TODO:
|
||||
JOYSTICKS=1
|
||||
HAS_BITMAP_MODE=0
|
||||
|
||||
[output]
|
||||
style=single
|
||||
format=trscmd
|
||||
extension=cmd
|
||||
|
||||
|
32
include/platform/trs80m3cmd.ini
Normal file
32
include/platform/trs80m3cmd.ini
Normal file
@ -0,0 +1,32 @@
|
||||
; TRS-80 Model 3 with 48K of RAM running TRS-DOS
|
||||
|
||||
[compilation]
|
||||
arch=z80
|
||||
; TODO:
|
||||
encoding=trs80m3
|
||||
screen_encoding=trs80m3
|
||||
modules=stdlib,trs80/kernal,default_panic
|
||||
|
||||
|
||||
[allocation]
|
||||
segments=default
|
||||
default_code_segment=default
|
||||
; TODO: this is what Z88DK uses:
|
||||
segment_default_start=$5200
|
||||
; assume 48K:
|
||||
segment_default_end=$ffff
|
||||
|
||||
[define]
|
||||
TRS80=1
|
||||
WIDESCREEN=0
|
||||
KEYBOARD=1
|
||||
; TODO:
|
||||
JOYSTICKS=1
|
||||
HAS_BITMAP_MODE=0
|
||||
|
||||
[output]
|
||||
style=single
|
||||
format=trscmd
|
||||
extension=cmd
|
||||
|
||||
|
26
include/trs80/kernal.mfk
Normal file
26
include/trs80/kernal.mfk
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma zilog_syntax
|
||||
|
||||
import default_readword
|
||||
|
||||
asm void putchar(byte register(a) char) @$33 extern
|
||||
|
||||
inline asm void new_line() {
|
||||
? LD A,13
|
||||
? JP putchar
|
||||
}
|
||||
|
||||
array __readline_out[45]
|
||||
const pointer readline_out = __readline_out.addr
|
||||
|
||||
asm pointer readline() {
|
||||
LD HL,readline_out
|
||||
LD B,__readline_out.length-1
|
||||
CALL $40
|
||||
; b contains the input length:
|
||||
LD C,B
|
||||
LD B,0
|
||||
ADD HL,BC
|
||||
LD (HL),0
|
||||
LD HL, readline_out
|
||||
RET
|
||||
}
|
4
include/trs80/keyboard.mfk
Normal file
4
include/trs80/keyboard.mfk
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
#pragma zilog_syntax
|
||||
|
||||
asm byte readkey() @$49 extern
|
@ -284,10 +284,15 @@ object Platform {
|
||||
case "length_be" => AllocatedDataLengthBe(0)
|
||||
case "d88" => D88Output
|
||||
case "tap" => TapOutput
|
||||
case "trscmd" => TrsCmdOutput
|
||||
case n => n.split(":").filter(_.nonEmpty) match {
|
||||
case Array(b, s, e) => BankFragmentOutput(b, parseNumber(s), parseNumber(e))
|
||||
case Array(s, e) => CurrentBankFragmentOutput(parseNumber(s), parseNumber(e))
|
||||
case Array(b) => ConstOutput(parseNumber(b).toByte)
|
||||
case Array(b) => try {
|
||||
ConstOutput(parseNumber(b).toByte)
|
||||
} catch {
|
||||
case _:NumberFormatException => log.fatal(s"Invalid output format: `$b`")
|
||||
}
|
||||
case x => log.fatal(s"Invalid output format: `$x`")
|
||||
}
|
||||
}.toList)
|
||||
|
22
src/main/scala/millfork/output/TrsCmdOutput.scala
Normal file
22
src/main/scala/millfork/output/TrsCmdOutput.scala
Normal file
@ -0,0 +1,22 @@
|
||||
package millfork.output
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object TrsCmdOutput extends OutputPackager {
|
||||
override def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = {
|
||||
val b = mem.banks(bank)
|
||||
val start = b.start
|
||||
b.output.slice(start, b.end + 1).grouped(256).zipWithIndex.flatMap{ case (chunk, index) =>
|
||||
// chunk type 1: data
|
||||
// chunk length: 1 byte, includes the load address, goes 3-258
|
||||
// load address: 2 bytes, little-endian
|
||||
Array[Byte](1, (chunk.length + 2).toByte, start.toByte, start.>>(8).+(index).toByte) ++ chunk
|
||||
}.toArray ++ Array[Byte](
|
||||
// chunk type 2: relocation address
|
||||
// chunk length: for type 2, it's always 2 bytes
|
||||
// relocation address: 2 bytes, little-endian
|
||||
2, 2, b.start.toByte, b.start.>>(8).toByte
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user