1
0
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:
Karol Stasiak 2020-09-26 23:52:49 +02:00
parent 3702002541
commit 3a9be16107
16 changed files with 168 additions and 13 deletions

1
.gitignore vendored
View File

@ -50,6 +50,7 @@ issue*.mfk
*.rom
*.ssd
*.o
*.cmd
HELLO
HELLOCPC
FIZZBUZZ

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -1,8 +1,2 @@
noinline asm byte readkey() {
clr $6f
jsr [$A000]
beq readkey
tfr a,b
rts
}
asm byte readkey() @ $49 extern

View 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

View 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

View File

@ -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

View 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

View 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
View 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
}

View File

@ -0,0 +1,4 @@
#pragma zilog_syntax
asm byte readkey() @$49 extern

View File

@ -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)

View 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
)
}
}