tape training

This commit is contained in:
Joppe Blondel
2026-10-03 17:30:43 +02:00
parent 5897e55094
commit 9823a05ffe
8 changed files with 1085 additions and 43 deletions
+15 -10
View File
@@ -41,6 +41,9 @@ mode, or UART/CTC setup must restore it before returning.
prints the low 16 bits of the sum as four hexadecimal digits. The end address
must be greater than or equal to the start address.
`D` prints 16 bytes per row followed by an ASCII column. Bytes outside the
printable ASCII range are shown as `.`.
Build the ROM and programmer-format images with:
```sh
@@ -84,15 +87,15 @@ The outputs are:
- `build/tinybasic/tinybasic.bin`: standalone relocated Tiny BASIC payload
- `build/casette/tape_loader.bin`: standalone relocated tape-loader payload
The current compact image is 12,318 bytes. Its ROM layout is:
The current compact image is 12,967 bytes. Its ROM layout is:
- `0000-007F`: reset/copy bootstrap
- `0080-1201`: packed BIOS+monitor image copied to RAM at `C000-D181`
- `1202-13FF`: unused space reserved for the resident image to grow
- `0080-12DD`: packed BIOS+monitor image copied to RAM at `C000-D25D`
- `12DE-13FF`: unused space reserved for the resident image to grow
- `1400-1C0C`: Tiny BASIC, executed directly from ROM
- `1C0D-2FFF`: unused ROM
- `3000-301D`: tape loader, executed directly from ROM
- `301E-7FFF`: unused space available for additional ROM content
- `3000-32A6`: tape loader, executed directly from ROM
- `32A7-7FFF`: unused space available for additional ROM content
The resident image starts at `C000`, its IM 2 vector table is at `C040`, and
linked code starts at `C080`. The bootstrap obtains the resident copy length
@@ -103,8 +106,8 @@ The resulting RAM layout is:
- `8000-AFFF`: Tiny BASIC workspace and BASIC program text
- `B000-B077`: Tiny BASIC variables and input buffer
- `B078-BFFF`: Tiny BASIC stack space
- `C000-D181`: resident BIOS, vectors, services, and monitor
- `D182-EFFF`: free space for resident-image growth
- `C000-D25D`: resident BIOS, vectors, services, and monitor
- `D25E-EFFF`: free space for resident-image growth
- `F000-FFFF`: BIOS globals, UART buffers, and monitor stack
The BIOS and monitor continue to work if low ROM is disabled. ROM-resident
@@ -197,12 +200,14 @@ returns to the Tiny BASIC prompt.
Tiny BASIC resets the stack pointer when it starts, so it does not currently
return through the monitor's `G` call. Reset the machine to return to the
monitor. The tape loader occupies the later ROM slot at `3000-301D`; the first
unused byte after it is `301E`.
monitor. The tape loader occupies the later ROM slot at `3000-32A6`; the first
unused byte after it is `32A7`.
## Tape loader
The tape-loader image is built from `apps/casette/tape_loader.asm`, linked at
`3000`, and included in both ROM images. Start it with `T`, `TAPE`, or `G 3000`.
The current image polls the comparator input and prints its state through the
resident BIOS console service.
resident BIOS console service. Signal acquisition is bounded; a missing,
unstable, or permanently high signal reports `TAPE SIGNAL TIMEOUT` and returns
to the monitor instead of waiting forever with interrupts disabled.
+2 -2
View File
@@ -9,8 +9,8 @@ The current allocation is:
- `1400-1C0C`: Tiny BASIC
- `1C0D-2FFF`: available
- `3000-301D`: tape loader
- `301E-7FFF`: available for more applications (`3100` is the next convenient
- `3000-32A6`: tape loader
- `32A7-7FFF`: available for more applications (`3300` is the next convenient
aligned origin)
The resident BIOS and monitor own high RAM at `C000-FFFF`. Tiny BASIC owns
+1 -1
View File
@@ -163,7 +163,7 @@ def main() -> None:
parser.add_argument("--low", type=float, default=2000.0, help="low tone in Hz")
parser.add_argument("--high", type=float, default=4000.0, help="high tone in Hz")
parser.add_argument("--sample-rate", type=int, default=48000)
parser.add_argument("--leader", type=float, default=1.0, help="leader seconds")
parser.add_argument("--leader", type=float, default=4.0, help="leader seconds")
parser.add_argument("--preamble", type=int, default=64, help="number of 0x55 preamble bytes")
parser.add_argument("--block-size", type=int, default=64)
parser.add_argument("--amplitude", type=float, default=0.75)
File diff suppressed because it is too large Load Diff
+12 -1
View File
@@ -5,6 +5,8 @@
#define UART_CTC_CARD_BASE 0x20
#define CTC_BASE (UART_CTC_CARD_BASE + 0x00)
#define CTC_CHANNEL_0 (CTC_BASE + 0)
#define CTC_CHANNEL_1 (CTC_BASE + 1)
#define CTC_CHANNEL_2 (CTC_BASE + 2)
#define CTC_CHANNEL_3 (CTC_BASE + 3)
#define UART_BASE (UART_CTC_CARD_BASE + 0x04)
#define UART_CONTROL (UART_BASE + 0)
@@ -76,6 +78,16 @@ void bios_init(void)
buffer_init(&rx_buf);
buffer_init(&tx_buf);
/* A CPU-only reset does not necessarily reset the external CTC. Stop and
disable every channel before rebuilding the UART clock/IRQ path. */
io_out(CTC_CHANNEL_0, 0x03);
io_out(CTC_CHANNEL_1, 0x03);
io_out(CTC_CHANNEL_2, 0x03);
io_out(CTC_CHANNEL_3, 0x03);
/* The 6850 has no reset input; CR1:CR0 = 11 is its master reset. */
io_out(UART_CONTROL, 0b00000011);
io_out(CTC_CHANNEL_0, 0x57);
io_out(CTC_CHANNEL_0, 13);
io_out(CTC_CHANNEL_3, 0b11001111);
@@ -84,7 +96,6 @@ void bios_init(void)
io_out(CTC_CHANNEL_0, 0x40);
uart_tx_busy = 0;
io_out(UART_CONTROL, 0b00000011);
io_out(UART_CONTROL, 0b10010101);
enable_interrupts();
}
+12
View File
@@ -113,6 +113,15 @@ init:
di
ld sp, #STACK_TOP
; A reset may have interrupted a CTC service routine without executing
; RETI. Release any stale daisy-chain in-service latches before the
; channels are reinitialized. RETI acts as RET for each CALL while
; also signalling end-of-interrupt to daisy-chained peripherals.
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call gsinit
; Setup interrupt mode 2
@@ -125,6 +134,9 @@ init:
hang:
jr hang
release_daisy_chain:
reti
.area _GSINIT
gsinit:
ld bc, #l__INITIALIZER
+9
View File
@@ -131,6 +131,15 @@ static void command_dump(uint8_t argc, char **argv)
print_hex8(*(volatile uint8_t *)(address + offset + column));
bios_putc(' ');
}
for (; column < 16; ++column) {
bios_puts(" ");
}
bios_putc('|');
for (column = 0; column < row_length; ++column) {
uint8_t value = *(volatile uint8_t *)(address + offset + column);
bios_putc(value >= ' ' && value <= '~' ? (char)value : '.');
}
bios_putc('|');
bios_puts("\r\n");
offset += row_length;
}
BIN
View File
Binary file not shown.