Skip to content

Commit

Permalink
Merge pull request #57 from stefanschramm/sharp-mz700
Browse files Browse the repository at this point in the history
Add support for Sharp MZ-700
  • Loading branch information
stefanschramm authored Jan 8, 2025
2 parents 9b6ec30 + 3ca9e95 commit e04bfae
Show file tree
Hide file tree
Showing 14 changed files with 439 additions and 2 deletions.
36 changes: 36 additions & 0 deletions MACHINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,42 @@ Run machine language program (with entry point `2700`, hexadecimal):

EXEC &H2700

# Sharp MZ-700

Volume: 70 % (using cassette adapter side B)

Load and run machine language program from monitor:

(PLAY)
L

To load BASIC programs, a BASIC interpreter (like `1Z-013B.mzf`, `927c33ddd4ae916ca2852207abf0be64`) must be loaded first.

Within BASIC, BASIC programs can be loaded and run like this:

(PLAY)
LOAD
RUN

**BASICODE**

There is a BASICODE implementation `S-BASIC/VERTALER BASICODE-2.**` (`s-basicode 2.mzf`, `1d9a2a3258b3233e90ae9b9529ec3f02`) that can be used to load and run BASICODE programs. It seems to be a patched version of the standard BASIC.

First load the BASICODE-BASIC from the monitor:

(PLAY)
L

Then from within BASIC the "library routines" need to be initialized using

LOAD/A

and afterwards you can load and run BASICODE programs using:

(PLAY)
LOAD/B
RUN

# TI-99/4A

Volume: 60 % (using line cable)
Expand Down
12 changes: 12 additions & 0 deletions retroload-lib/examples/formats/sharpmz/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
include ../Makefile.inc

all: rl.bin rl.mzf

%.mzf: %.mzf.asm %.bin
$(Z80_ASM) $< -o $@

%.bin: %.bin.asm
$(Z80_ASM) $< -o $@

clean:
rm -f *.wav *.bin
Binary file added retroload-lib/examples/formats/sharpmz/rl.bin
Binary file not shown.
50 changes: 50 additions & 0 deletions retroload-lib/examples/formats/sharpmz/rl.bin.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; retroload.com
; example program for Sharp MZ-700
; to be built using z80asm
;
; Load: L
; Run: J1200
;

OFFSET: equ 0x1200

; monitor rom routines
BELL: equ 0x003e
PRINTS: equ 0x0012
GETL: equ 0x0003

org OFFSET

; program
ld hl, GREETING
call PRINTSTRING
call BELL
call GETL
jp 0x0000

PRINTSTRING:
; using our own routine because the monitor's MSG routine ignores the carriage returns
; beginning of string in HL
ld a, (hl)
cp 0
ret z
push hl
call PRINTS
pop hl
inc hl
jp PRINTSTRING

GREETING:
dm "\r"
dm "---------------------------------\r"
dm "\r"
dm "RETROLOAD.COM\r"
dm "\r"
dm "EXAMPLE FOR SHARP MZ-700 (BINARY)\r"
dm "\r"
dm "LOADED AND EXECUTED!\r"
dm "\r"
dm "---------------------------------\r"
dm "\r"
dm "PRESS RETURN TO RETURN TO MONITOR\r"
db 0
Binary file added retroload-lib/examples/formats/sharpmz/rl.mzf
Binary file not shown.
24 changes: 24 additions & 0 deletions retroload-lib/examples/formats/sharpmz/rl.mzf.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
; retroload.com
; example program for Sharp MZ-700
; to be built using z80asm
;
; Load: L
; Run: J1200
;

OFFSET: equ 0x1200

db 0x01 ; Type: MZ-700 binary
dm "RL"
db 0x0d ; string delimiter
dm " " ; pad to 17 bytes including delimiter
dw END - START ; file size
dw OFFSET ; load address
dw OFFSET ; entry address
ds 104, 0x00 ; pad header to 128 bytes

START:

incbin "rl.bin"

END:
18 changes: 18 additions & 0 deletions retroload-lib/src/Examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const examples: ExampleDefinition[] = [
'2023-10-31 (KC 85/4 with BASICODE-3C Andreas and Uwe Zierott, R. Wenzel 1.5; BAC854C.SSS: d48116eaeab75f01b31ba3515fd45615)',
'2023-12-10 (C64 C with BASICODE 3 Version D-1 MvD 1988; prg: d7c0990f12499ad2c3d31539e0366712, Basicode 3 Version D-1 (DE).d64: 962b708b1f6b5ac720c25e7848f4d796',
'2023-12-10 (MSX Philips VG-8020 with BASICODE-3 (1987)(NOS)(NL).cas: 36018c4014149a46f600381fc4c4dadf',
// Loads on Sharp MZ-700, but there seem to be some glitches with the example. Possibly BASICODE-2 incompatibility. '2025-01-08 (Sharp MZ-700 with S-BASIC/VERTALER BASICODE-2.**; s-basicode 2.mzf: 1d9a2a3258b3233e90ae9b9529ec3f02',
],
},
// Atari 800 XL
Expand Down Expand Up @@ -276,6 +277,23 @@ const examples: ExampleDefinition[] = [
instructions: 'bload"cas:",r',
tests: ['2023-12-10 OK (Philips VG-8020)'],
},
// Sharp MZ-700
{
dir: 'sharpmz',
file: 'rl.bin',
options: {format: 'sharpmzgeneric', shortpilot: true, name: 'RL', load: '1200', entry: '1200', sharpmznorepeat: true, sharpmztype: '1'},
hash: '08b882304fde8a43bc6c83b84a96d282',
instructions: 'L',
tests: ['2025-01-08 OK (Sharp MZ-700)'],
},
{
dir: 'sharpmz',
file: 'rl.mzf',
options: {shortpilot: true, sharpmznorepeat: true},
hash: '08b882304fde8a43bc6c83b84a96d282',
instructions: 'L',
tests: ['2025-01-08 OK (Sharp MZ-700)'],
},
// TA alphatronic PC
{
dir: 'ta_bas',
Expand Down
4 changes: 4 additions & 0 deletions retroload-lib/src/encoding/Adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {Mo5K7Adapter} from './adapter/mo5/Mo5K7Adapter.js';
import {MsxCasAdapter} from './adapter/msx/MsxCasAdapter.js';
import {MsxGenericAdapter} from './adapter/msx/MsxGenericAdapter.js';
import {MsxTsxAdapter} from './adapter/msx/MsxTsxAdapter.js';
import {SharpMzGenericAdapter} from './adapter/sharpmz/SharpMzGenericAdapter.js';
import {SharpMzMzfAdapter} from './adapter/sharpmz/SharpMzMzfAdapter.js';
import {TaGenericAdapter} from './adapter/ta/TaGenericAdapter.js';
import {TiFiadAdapter} from './adapter/ti/TiFiadAdapter.js';
import {TiGenericAdapter} from './adapter/ti/TiGenericAdapter.js';
Expand Down Expand Up @@ -59,6 +61,8 @@ const adapters: InternalAdapterDefinition[] = [
MsxCasAdapter,
MsxGenericAdapter,
MsxTsxAdapter,
SharpMzGenericAdapter,
SharpMzMzfAdapter,
TaGenericAdapter,
TiFiadAdapter,
TiGenericAdapter,
Expand Down
2 changes: 1 addition & 1 deletion retroload-lib/src/encoding/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export const entryOption: ArgumentOptionDefinition<number | undefined> = {
required: false,
type: 'text',
parse(v) {
if (v === undefined) {
if (v === undefined || v === '') {
return undefined;
}
const address = parseInt(v, 16);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {FlagOptionDefinition} from '../../Options.js';

export const sharpmznorepeatOption: FlagOptionDefinition = {
name: 'sharpmznorepeat',
label: 'Don\'t repeat data',
description: 'Don\'t repeat data and header',
common: true,
type: 'bool',
};
142 changes: 142 additions & 0 deletions retroload-lib/src/encoding/adapter/sharpmz/SharpMzEncoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import {ByteRecorder, recordByteMsbFirst, recordBytes} from '../ByteRecorder.js';
import {BufferAccess} from '../../../common/BufferAccess.js';
import {Oscillator} from '../Oscillator.js';
import {RecorderInterface} from '../../recorder/RecorderInterface.js';

const fLongPulse = 1000;
const fShortPulse = 2000;

/**
* Encoder for Sharp MZ-700 and similar
*
* https://original.sharpmz.org/mz-700/tapeproc.htm
* https://original.sharpmz.org/mz-700/coremain.htm
*
* Note: The "L" mark after checksums in this documentation seems not to be required.
*
* Repeating the data seems to be optional: If the first recording can be loaded, the rest is ignored.
*/
export class SharpMzEncoder implements ByteRecorder {
private readonly oscillator: Oscillator;

public constructor(
private readonly recorder: RecorderInterface,
) {
this.oscillator = new Oscillator(this.recorder);
}

public begin(): void {
this.oscillator.begin();
}

public recordHeader(header: BufferAccess, repeat: boolean = false, shortpilot: boolean = false): void {
const checksum = calculateChecksum(header);
const checksumBuffer = BufferAccess.create(2);
checksumBuffer.writeUint16Be(checksum);

// LGAP
this.oscillator.recordOscillations(fShortPulse, shortpilot ? 5000 : 22000); // "only 10,000 for the MZ-80B"

// LTM
this.oscillator.recordOscillations(fLongPulse, 40);
this.oscillator.recordOscillations(fShortPulse, 40);
this.oscillator.recordOscillations(fLongPulse, 1);

// L
this.oscillator.recordOscillations(fLongPulse, 1);

// HDR
this.recorder.beginAnnotation('Header Data');
this.recordBytes(header);
this.recorder.endAnnotation();

// CHKH
this.recordBytes(checksumBuffer);

if (repeat) {
// 256S
this.oscillator.recordOscillations(fShortPulse, 256);

// HDRC
this.recorder.beginAnnotation('Header Data Repeated');
this.recordBytes(header);
this.recorder.endAnnotation();

// CHKH
this.recordBytes(checksumBuffer);
}
}

public recordData(data: BufferAccess, repeat: boolean = false): void {
const checksum = calculateChecksum(data);
const checksumBuffer = BufferAccess.create(2);
checksumBuffer.writeUint16Be(checksum);

// SGAP
this.oscillator.recordOscillations(fShortPulse, 11000);

// STM
this.oscillator.recordOscillations(fLongPulse, 20);
this.oscillator.recordOscillations(fShortPulse, 20);
this.oscillator.recordOscillations(fLongPulse, 1);

// L
this.oscillator.recordOscillations(fLongPulse, 1);

// FILE
this.recorder.beginAnnotation('File Data');
this.recordBytes(data);
this.recorder.endAnnotation();

// CHKF
this.recordBytes(checksumBuffer);

if (repeat) {
// 256S
this.oscillator.recordOscillations(fShortPulse, 256);

// FILEC
this.recorder.beginAnnotation('File Data Repeated');
this.recordBytes(data);
this.recorder.endAnnotation();

// CHKF
this.recordBytes(checksumBuffer);
}
}

public recordBytes(data: BufferAccess): void {
recordBytes(this, data);
}

public end(): void {
this.oscillator.end();
}

public recordByte(byte: number): void {
recordByteMsbFirst(this, byte);
this.oscillator.recordOscillations(fLongPulse, 1);
}

public recordBit(value: number): void {
if (value) {
this.oscillator.recordOscillations(fLongPulse, 1);
} else {
this.oscillator.recordOscillations(fShortPulse, 1);
}
}
}

/**
* sum of 1-bits in data
*/
function calculateChecksum(data: BufferAccess): number {
let bitSum = 0;
for (const byte of data.bytes()) {
for (let i = 0; i < 8; i++) {
bitSum = (bitSum + ((byte >> i) & 1)) & 0xffff;
}
}

return bitSum;
}
Loading

0 comments on commit e04bfae

Please sign in to comment.