diff --git a/.gitignore b/.gitignore
index eec12562..52131f9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ atari800d.atr
atari800hd.atr
atari800xlhd.atr
bbcmicro.ssd
+bbcmicro2.ssd
bin
c64.d64
pet.d64
diff --git a/build.py b/build.py
index f481283c..44a0272d 100644
--- a/build.py
+++ b/build.py
@@ -17,6 +17,7 @@
"bin/pint.com": "third_party/pascal-m+pint",
"bin/loader.com": "third_party/pascal-m+loader",
"bbcmicro.ssd": "src/arch/bbcmicro+diskimage",
+ "bbcmicro2.ssd": "src/arch/bbcmicro+diskimage2",
"oric.dsk": "src/arch/oric+diskimage",
"apple2e.po": "src/arch/apple2e+diskimage",
"atari800.atr": "src/arch/atari800+atari800_diskimage",
diff --git a/src/arch/atari800/atari800.S b/src/arch/atari800/atari800.S
index 6d88cd04..80dd2b0b 100644
--- a/src/arch/atari800/atari800.S
+++ b/src/arch/atari800/atari800.S
@@ -753,7 +753,11 @@ zproc tty_conout
sta cursorx
rts
zendif
- cmp #127
+ cmp #127 ; DEL
+ zif_eq
+ lda #8 ; DEL is BS
+ zendif
+ cmp #8 ; proper ^H BS
zif_eq
dec cursorx
zif_mi
diff --git a/src/arch/atari800/build.py b/src/arch/atari800/build.py
index 1110c3bc..9fab3768 100644
--- a/src/arch/atari800/build.py
+++ b/src/arch/atari800/build.py
@@ -165,6 +165,18 @@
"1:olivetti.fnt": "third_party/fonts/atari/olivetti.fnt",
"1:phoenix.fnt": "third_party/fonts/atari/phoenix.fnt",
"1:toshiba.fnt": "third_party/fonts/atari/toshiba.fnt",
+ "2:8080.com": "src/arch/atari800/utils+8080_ovl_loader",
+ "2:8080.ovl": "third_party/atari8080/8080.ovl",
+ "2:halt.com": "third_party/atari8080/HALT.COM",
+ "2:stat.com": "third_party/atari8080/STAT.COM",
+ "2:dump.com": "third_party/atari8080/DUMP.COM",
+ "2:pip.com": "third_party/atari8080/PIP.COM",
+ "2:zork1.com": "third_party/atari8080/ZORK1.COM",
+ "2:zork1.dat": "third_party/atari8080/ZORK1.DAT",
+ "2:tst8080.com": "third_party/atari8080/TST8080.COM",
+ "2:8080pre.com": "third_party/atari8080/8080PRE.COM",
+ "2:8080exm.com": "third_party/atari8080/8080EXM.COM",
+ "2:cputest.com": "third_party/atari8080/CPUTEST.COM",
}
| MINIMAL_APPS
| MINIMAL_APPS_SRCS
diff --git a/src/arch/atari800/utils/8080_ovl_loader.S b/src/arch/atari800/utils/8080_ovl_loader.S
new file mode 100644
index 00000000..4609117f
--- /dev/null
+++ b/src/arch/atari800/utils/8080_ovl_loader.S
@@ -0,0 +1,447 @@
+; -------------------------------------------------------------------------
+;
+; 8080 Overlay Loader
+;
+; Copyright © 2024 Ivo van poorten
+; This file is licensed under the terms of the 2-clause BSD license. Please
+; see the COPYING file in the root project directory for the full text.
+;
+; -------------------------------------------------------------------------
+
+; This program is intended for Atari's equiped with at least 128kB of RAM,
+; or a BBC Master 128 or 512 with 128kB of sideways RAM at banks 4-7.
+; It first checks if the required memory is free, i.e. not too many resident
+; drivers in either low or high memory, and then proceeds to load the file
+; 8080.OVL. The structure of the file is similar to regular binary executables
+; used by Atari DOS, with a few restrictions.
+;
+; 8080.OVL file consists of several blocks. Each block looks like this:
+;
+; FF FF Header marker (optional, except for the first block)
+; lb hb Start address $hblb
+; lb hb End address $hblb
+; xx ... End-Start+1 bytes of data
+;
+; Two special blocks are recognized.
+;
+; e2 02 e3 02 lb hb Init. JSR to $hblb, continue loading after RTS.
+; e0 02 e1 02 lb hb Run. JMP to $hblb.
+;
+; The loader does no sanity checks on loaded blocks, so be sure it only
+; defines blocks between the end of the loader and the end of TPA memory.
+; The file _MUST_ end with a Run block. A "Run" is executed immediately,
+; unlike Atari DOS which waits until EOF.
+
+; -------------------------------------------------------------------------
+
+#include "zif.inc"
+#include "cpm65.inc"
+#ifdef MASTER128
+#else
+#include "atari800.inc"
+#endif
+
+ZEROPAGE
+
+ZP_START:
+
+ptr: .fill 2
+end: .fill 2
+tmp: .fill 1
+bufidx: .fill 1
+
+ZP_END:
+
+; Add this to GETZP's low to see if we extend into $e0-$ff
+; ZP and TPA are not automatically adjusted before the (this) program is called.
+
+ZP_WE_USE = ZP_END-ZP_START
+
+#ifdef MASTER128
+ TEST_TPA_TOP = $66
+ TEST_TPA_BOTTOM = $30
+ TEST_ZP_BOTTOM = $70
+ TEST_ZP_TOP = $8f
+#else
+ TEST_TPA_TOP = $b6
+ TEST_TPA_BOTTOM = $40
+ TEST_ZP_BOTTOM = $e0
+ TEST_ZP_TOP = $ff
+#endif
+
+; -------------------------------------------------------------------------
+
+zproc main
+ ldy #BDOS_WRITE_STRING
+ lda #
title
+ jsr BDOS
+
+; check end of TPA
+
+ ldy #BIOS_GETTPA
+ jsr BIOS
+ cpx #TEST_TPA_TOP
+
+ zif_cc
+ lda #top_error
+error_out:
+ ldy #BDOS_WRITE_STRING
+ jmp BDOS
+ zendif
+
+; check end of loader program, i.e. bottom of TPA
+
+ lda #>bottom_check
+ clc
+ adc #1
+ cmp #TEST_TPA_BOTTOM
+
+ zif_cs
+ lda #bottom_error
+ jmp error_out
+ zendif
+
+; check if $e0-$ff is free
+
+ ldy #BIOS_GETZP
+ jsr BIOS
+
+ cmp #TEST_ZP_BOTTOM-ZP_WE_USE
+
+ zif_cs
+print_zp_error:
+ lda #zp_error
+ jmp error_out
+ zendif
+
+ cpx #TEST_ZP_TOP
+ bcc print_zp_error
+
+; check if we have banked memory
+
+#ifdef MASTER128
+ ldx $f4
+ lda #4
+ sta $f4
+ sta $fe30
+ sta $8000
+ cmp $8000
+
+ zif_ne
+ stx $f4
+
+ lda #extmem_error
+ jmp error_out
+ zendif
+
+ stx $f4
+ stx $fe30
+
+#else
+ lda PORTB
+ sta $4000 ; "random" value to $4000
+ eor #$10 ; enable CPU banking
+ sta PORTB
+ eor #$10
+ cmp $4000
+
+ zif_eq
+ sta PORTB
+
+ lda #extmem_error
+ jmp error_out
+ zendif
+
+ sta PORTB
+#endif
+
+; setup FCB
+
+ ldx #$24
+ lda #0
+ zrepeat
+ sta my_fcb,x
+ dex
+ zuntil_mi
+
+ ldx #10
+ zrepeat
+ lda filename,x
+ sta my_fcb+1,x
+ dex
+ zuntil_mi
+
+; open '8080.OVL'
+
+ ldy #BDOS_OPEN_FILE
+ lda #my_fcb
+ jsr BDOS
+
+ zif_cs
+ lda #open_error
+ jmp error_out
+ zendif
+
+ lda #$80
+ sta bufidx
+
+ jsr getbyte
+ sta tmp
+ jsr getbyte
+ cmp #$ff
+
+ zif_ne
+invalid_file:
+ lda #FF_error
+ jmp error_out
+ zendif
+
+ lda tmp
+ cmp #$ff
+ bne invalid_file
+
+read_blocks_loop:
+
+skip_FF:
+ jsr getbyte
+ sta ptr
+ jsr getbyte
+ sta ptr+1
+ lda ptr
+ cmp #$ff
+ bne read_end_addr
+ lda ptr+1
+ cmp #$ff
+ beq skip_FF
+
+read_end_addr:
+ jsr getbyte
+ sta end
+ jsr getbyte
+ sta end+1
+
+ lda #'.'
+ ldy #BIOS_CONOUT
+ jsr BIOS
+
+ lda #0
+ sta do_init
+ sta do_run
+
+ jsr check_02e0
+ jsr check_02e2
+
+next_byte:
+ jsr getbyte
+ ldy #0
+ sta (ptr),y
+
+ lda ptr
+ cmp end
+
+ zif_ne
+not_end:
+ inc ptr
+ zif_eq
+ inc ptr+1
+ zendif
+ jmp next_byte
+ zendif
+
+ lda ptr+1
+ cmp end+1
+ bne not_end
+
+ lda do_init
+ zif_ne
+ jsr jsr_init
+ zendif
+
+ lda do_run
+ zif_ne
+ lda #13
+ ldy #BIOS_CONOUT
+ jsr BIOS
+ lda #10
+ ldy #BIOS_CONOUT
+ jsr BIOS
+
+ lda #BIOS
+ jsr jsr_run
+
+ lda #0 ; be sure we can read CCP.SYS
+ ldy #BDOS_GET_SET_USER_NUMBER
+ jsr BDOS
+
+ ldy #BDOS_EXIT_PROGRAM ; wboot, i8080 CP/M might have written to disk
+ jmp BDOS
+ zendif
+
+ jmp read_blocks_loop
+zendproc
+
+zproc check_02e0
+ lda ptr+1
+ cmp #$02
+ zif_eq
+ lda ptr
+ cmp #$e0
+ zif_eq
+ inc do_run
+ lda #>run_address
+ sta ptr+1
+ sta end+1
+ ldx #init_address
+ sta ptr+1
+ sta end+1
+ ldx #sector_buffer
+ ldy #BDOS_SET_DMA_ADDRESS
+ jsr BDOS
+
+ lda #my_fcb
+ ldy #BDOS_READ_SEQUENTIAL
+ jsr BDOS
+
+ zif_cc
+ lda #0
+ sta bufidx
+ rts
+ zendif
+
+ lda #eof_error
+ ldy #BDOS_WRITE_STRING
+ jsr BDOS
+
+ ldy #BDOS_EXIT_PROGRAM
+ jmp BDOS
+zendproc
+
+; -------------------------------------------------------------------------
+
+ .data
+
+title:
+#ifdef MASTER128
+ .ascii "BBC Master 128 - 8080 Overlay Loader"
+#else
+ .ascii "Atari 130XE - 8080 Overlay Loader"
+#endif
+ .byte 13,10,0
+
+top_error:
+ .ascii "Error: top of TPA is too low"
+ .byte 13,10,0
+
+bottom_error:
+ .ascii "Error: bottom of TPA is too high"
+ .byte 13,10,0
+
+zp_error:
+#ifdef MASTER128
+ .ascii "Error: ZP 70-8F must be free"
+#else
+ .ascii "Error: ZP E0-FF must be free"
+#endif
+ .byte 13,10,0
+
+extmem_error:
+ .ascii "Error: no extended memory detected"
+ .byte 13,10,0
+
+open_error:
+ .ascii "Error: unable to open 8080.OVL"
+ .byte 13,10,0
+
+eof_error:
+ .ascii "Error: premature EOF encountered"
+ .byte 13,10,0
+
+FF_error:
+ .ascii "Error: invalid OVL file"
+ .byte 13,10,0
+
+filename:
+ .ascii "8080 OVL"
+
+; -------------------------------------------------------------------------
+
+ .bss
+
+my_fcb: .fill 37
+
+sector_buffer: .fill 128
+
+do_init: .fill 1
+do_run: .fill 1
+
+ .align 2 ; avoid page crossing jmp (abs)
+
+init_address: .fill 2
+run_address: .fill 2
+
+bottom_check:
+
+; -------------------------------------------------------------------------
+
+; vim: filetype=asm sw=4 ts=4 et
diff --git a/src/arch/atari800/utils/build.py b/src/arch/atari800/utils/build.py
index 610441cc..f78e2bb2 100644
--- a/src/arch/atari800/utils/build.py
+++ b/src/arch/atari800/utils/build.py
@@ -11,3 +11,12 @@
"third_party/fonts/atari+ivo3x6",
],
)
+
+llvmprogram(
+ name="8080_ovl_loader",
+ srcs=["./8080_ovl_loader.S"],
+ deps=[
+ "include",
+ "src/arch/atari800+headers",
+ ],
+)
diff --git a/src/arch/atari800/utils/tty80drv.S b/src/arch/atari800/utils/tty80drv.S
index 08a9dc24..1ebe9488 100644
--- a/src/arch/atari800/utils/tty80drv.S
+++ b/src/arch/atari800/utils/tty80drv.S
@@ -680,7 +680,11 @@ zproc tty80_conout
sta cursorx
rts
zendif
- cmp #127 ; Backspace
+ cmp #127 ; DEL
+ zif_eq
+ lda #8 ; DEL = BS
+ zendif
+ cmp #8 ; ^H BS
zif_eq
dec cursorx
zif_mi
diff --git a/src/arch/bbcmicro/build.py b/src/arch/bbcmicro/build.py
index 9b2bf536..02b4198a 100644
--- a/src/arch/bbcmicro/build.py
+++ b/src/arch/bbcmicro/build.py
@@ -30,6 +30,28 @@
| PASCAL_APPS,
)
+mkcpmfs(
+ name="cpmfs2",
+ format="bbc192",
+ items={
+ "0:ccp.sys@sr": "src+ccp",
+ "2:8080.com": "src/arch/bbcmicro/utils+8080_ovl_loader",
+ "2:8080.ovl": "third_party/atari8080/8080-bbc.ovl",
+ "2:halt.com": "third_party/atari8080/HALT.COM",
+ "2:stat.com": "third_party/atari8080/STAT.COM",
+ "2:dump.com": "third_party/atari8080/DUMP.COM",
+ "2:pip.com": "third_party/atari8080/PIP.COM",
+ "2:zork1.com": "third_party/atari8080/ZORK1.COM",
+ "2:zork1.dat": "third_party/atari8080/ZORK1.DAT",
+ "2:tst8080.com": "third_party/atari8080/TST8080.COM",
+ "2:8080pre.com": "third_party/atari8080/8080PRE.COM",
+ "2:8080exm.com": "third_party/atari8080/8080EXM.COM",
+ "2:cputest.com": "third_party/atari8080/CPUTEST.COM",
+
+ }
+ | SCREEN_APPS
+)
+
mkdfs(
name="diskimage",
title="CP/M-65",
@@ -41,6 +63,17 @@
},
)
+mkdfs(
+ name="diskimage2",
+ title="CP/M-65",
+ opt=2,
+ items={
+ "!boot@0x0400": ".+bios",
+ "bdos": "src/bdos",
+ "cpmfs": ".+cpmfs2",
+ },
+)
+
mametest(
name="mametest",
target="bbcm",
diff --git a/src/arch/bbcmicro/utils/8080_ovl_loader.S b/src/arch/bbcmicro/utils/8080_ovl_loader.S
new file mode 120000
index 00000000..ddb55c8f
--- /dev/null
+++ b/src/arch/bbcmicro/utils/8080_ovl_loader.S
@@ -0,0 +1 @@
+../../atari800/utils/8080_ovl_loader.S
\ No newline at end of file
diff --git a/src/arch/bbcmicro/utils/build.py b/src/arch/bbcmicro/utils/build.py
new file mode 100644
index 00000000..1b50ae61
--- /dev/null
+++ b/src/arch/bbcmicro/utils/build.py
@@ -0,0 +1,10 @@
+from build.llvm import llvmprogram
+
+llvmprogram(
+ name="8080_ovl_loader",
+ srcs=["./8080_ovl_loader.S"],
+ deps=[
+ "include",
+ ],
+ cflags=["-DMASTER128"],
+)
diff --git a/third_party/atari8080/8080-bbc.ovl b/third_party/atari8080/8080-bbc.ovl
new file mode 100644
index 00000000..f5c0e2f9
Binary files /dev/null and b/third_party/atari8080/8080-bbc.ovl differ
diff --git a/third_party/atari8080/8080.ovl b/third_party/atari8080/8080.ovl
new file mode 100644
index 00000000..84d64083
Binary files /dev/null and b/third_party/atari8080/8080.ovl differ
diff --git a/third_party/atari8080/8080EXM.COM b/third_party/atari8080/8080EXM.COM
new file mode 100644
index 00000000..76c1a347
Binary files /dev/null and b/third_party/atari8080/8080EXM.COM differ
diff --git a/third_party/atari8080/8080PRE.COM b/third_party/atari8080/8080PRE.COM
new file mode 100644
index 00000000..a1803ceb
Binary files /dev/null and b/third_party/atari8080/8080PRE.COM differ
diff --git a/third_party/atari8080/CPUTEST.COM b/third_party/atari8080/CPUTEST.COM
new file mode 100644
index 00000000..dd535a47
Binary files /dev/null and b/third_party/atari8080/CPUTEST.COM differ
diff --git a/third_party/atari8080/DUMP.COM b/third_party/atari8080/DUMP.COM
new file mode 100644
index 00000000..03a77c3c
Binary files /dev/null and b/third_party/atari8080/DUMP.COM differ
diff --git a/third_party/atari8080/HALT.COM b/third_party/atari8080/HALT.COM
new file mode 100644
index 00000000..37ccf793
--- /dev/null
+++ b/third_party/atari8080/HALT.COM
@@ -0,0 +1 @@
+vÉ
\ No newline at end of file
diff --git a/third_party/atari8080/PIP.COM b/third_party/atari8080/PIP.COM
new file mode 100644
index 00000000..4b2ce4b6
Binary files /dev/null and b/third_party/atari8080/PIP.COM differ
diff --git a/third_party/atari8080/STAT.COM b/third_party/atari8080/STAT.COM
new file mode 100644
index 00000000..60c54849
Binary files /dev/null and b/third_party/atari8080/STAT.COM differ
diff --git a/third_party/atari8080/TST8080.COM b/third_party/atari8080/TST8080.COM
new file mode 100644
index 00000000..d16eeb83
Binary files /dev/null and b/third_party/atari8080/TST8080.COM differ
diff --git a/third_party/atari8080/ZORK1.COM b/third_party/atari8080/ZORK1.COM
new file mode 100644
index 00000000..8a7bec1c
Binary files /dev/null and b/third_party/atari8080/ZORK1.COM differ
diff --git a/third_party/atari8080/ZORK1.DAT b/third_party/atari8080/ZORK1.DAT
new file mode 100644
index 00000000..b2eb461f
Binary files /dev/null and b/third_party/atari8080/ZORK1.DAT differ