Simple Smartport (#31)

* Simple Smartport

* Block device support

* turn off verbose debugging

* rom cleanup

* Turn off debugging, again

* Turn off debugging, again, again
This commit is contained in:
Will Scullin 2020-09-12 19:42:18 -07:00 committed by GitHub
parent 7f9ad9b9a1
commit ab05e99d81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 209 additions and 83 deletions

View File

@ -13,6 +13,10 @@ indent_size = 4
[*.md]
trim_trailing_whitespace = true
[*.s]
indent_size = 8
indent_style = tab
[Makefile]
indent_style = tab
indent_size = 8

83
asm/smartport.s Normal file
View File

@ -0,0 +1,83 @@
ORG $C700
; Slot scan ZP addresses
SCAN_LO EQU $00
SCAN_HI EQU $01
; ProDOS
COMMAND EQU $42
UNIT EQU $43
ADDRESS_LO EQU $44
ADDRESS_HI EQU $45
BLOCK_LO EQU $46
BLOCK_HI EQU $47
MSLOT EQU $7F8
; Slot I/O addresses
STATUS EQU $C080
; ROM addresses
BASIC EQU $E000
SLOOP EQU $FABA ; Resume boot scan
ROMRTS EQU $FF58
BOOT EQU $0801
LDX #$20 ; $20 $00 $03 $00 - Smartport signature
LDX #$00 ; $20 $00 $03 $3C - Vanilla disk signature
LDX #$03
LDX #$00 ; Override with $3C for DumbPort
; Determine our slot
JSR ROMRTS
TSX
LDA $0100,X
STA MSLOT ; $Cn
ASL
ASL
ASL
ASL
TAY ; $n0
; Load the disk status bits
LDA STATUS,Y
LSR ; Check for Disk 1
BCS DISKREADY ; Boot from Disk 1
LDA SCAN_LO
BNE GO_BASIC
LDA SCAN_HI
CMP MSLOT
BNE GO_BASIC
JMP SLOOP ; Go back to scanning
GO_BASIC JMP BASIC ; Go to basic
; Boot routine
DISKREADY LDX #$01 ; Read
STX COMMAND
DEX
STX BLOCK_LO ; Block 0
STX BLOCK_HI
STX ADDRESS_LO ; Into $800
LDX #$08
STX ADDRESS_HI
LDA MSLOT
PHA ; Save slot address
PHA ; RTS address hi byte
LDA #REENTRY - 1
PHA ; RTS address lo byte
CLV
BVC BLOCK_ENT
REENTRY PLA ; Restore slot address
ASL ; Make I/O register index
ASL
ASL
ASL
TAX
JMP BOOT
DS 2
BLOCK_ENT RTS
DS 2
SMARTPOINT_ENT RTS
PADDING DS $C7FE - PADDING
ORG $C7FE
FLAGS DFB $D7
ENTRY_LO DFB BLOCK_ENT
END

View File

@ -27,6 +27,7 @@ export const DISK_TYPES = [
'd13',
'do',
'dsk',
'hdv',
'po',
'nib',
'woz'

View File

@ -11,40 +11,28 @@
import { base64_decode } from '../base64';
import { debug, toHex } from '../util';
import { rom } from '../roms/cards/smartport';
export default function SmartPort(io, cpu) {
export default function SmartPort(io, cpu, options ) {
var COMMAND = 0x42;
var UNIT = 0x43;
var ADDRESS_LO = 0x44;
// var ADDRESS_HI = 0x45;
var BLOCK_LO = 0x46;
// var BLOCK_HI = 0x47;
/*
$Cn01=$20
$Cn03=$00
$Cn05=$03
$Cn07=$00
*/
var ROM = [
0xA2, 0x20, 0xA0, 0x00, 0xA2, 0x03, 0xA0, 0x3C, 0x20, 0x58, 0xFF, 0xBA, 0xBD, 0x00, 0x01, 0x0A,
0x0A, 0x0A, 0x0A, 0xAA, 0x4C, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x20
];
var disks = [];
function _init() {
if (options && options.block) {
rom[0x07] = 0x3C;
debug('DumbPort card');
} else {
debug('SmartPort card');
}
}
function decodeDisk(unit, disk) {
disks[unit] = [];
for (var idx = 0; idx < disk.blocks.length; idx++) {
@ -52,6 +40,10 @@ export default function SmartPort(io, cpu) {
}
}
function _debug() {
// debug.apply(this, arguments);
}
function Address() {
var lo;
var hi;
@ -173,9 +165,9 @@ export default function SmartPort(io, cpu) {
*/
function readBlock(state, drive, block, buffer) {
debug('read drive=' + drive);
debug('read buffer=' + buffer);
debug('read block=$' + toHex(block));
_debug('read drive=' + drive);
_debug('read buffer=' + buffer);
_debug('read block=$' + toHex(block));
if (!disks[drive] || !disks[drive].length) {
debug('Drive', drive, 'is empty');
@ -198,9 +190,9 @@ export default function SmartPort(io, cpu) {
*/
function writeBlock(state, drive, block, buffer) {
debug('write drive=' + drive);
debug('write buffer=' + buffer);
debug('write block=$' + toHex(block));
_debug('write drive=' + drive);
_debug('write buffer=' + buffer);
_debug('write block=$' + toHex(block));
if (!disks[drive] || !disks[drive].length) {
debug('Drive', drive, 'is empty');
@ -233,37 +225,64 @@ export default function SmartPort(io, cpu) {
state.s &= 0xfe;
}
function _access(off, val) {
var result;
var readMode = val === undefined;
switch (off & 0x8f) {
case 0x80:
if (readMode) {
result = 0;
for (var idx = 0; idx < disks.length; idx++) {
result <<= 1;
if (disks[idx]) {
result |= 0x01;
}
}
}
break;
}
return result;
}
_init();
/*
* Interface
*/
return {
read: function(page, off, debugFlag) {
ioSwitch: function (off, val) {
return _access(off, val);
},
read: function(page, off) {
var state = cpu.getState();
var cmd;
var unit;
var buffer;
var block;
var blockOff = rom[0xff];
var smartOff = blockOff + 3;
if (!debugFlag) {
debug('read $' + toHex(page) + toHex(off) + '=$' + toHex(ROM[off]), cpu.sync());
}
if (off == 0x00 && cpu.sync()) {
readBlock(state, 1, 0, new Address(0x0800));
} else if (off == 0x20 && cpu.sync()) { // Regular block device entry POINT
debug('block device entry');
cmd = cpu.read(0x00, 0x42);
unit = cpu.read(0x00, 0x43);
var bufferAddr;
var blockAddr;
if (off === blockOff && cpu.sync()) { // Regular block device entry POINT
_debug('block device entry');
cmd = cpu.read(0x00, COMMAND);
unit = cpu.read(0x00, UNIT);
var bufferAddr = new Address(ADDRESS_LO);
var blockAddr = new Address(BLOCK_LO);
var drive = (unit & 0x80) ? 2 : 1;
var driveSlot = (unit & 0x70) >> 4;
debug('cmd=' + cmd);
debug('unit=$' + toHex(unit));
buffer = bufferAddr.readAddress();
block = blockAddr.readWord();
debug('slot=' + driveSlot + ' drive=' + drive);
_debug('cmd=' + cmd);
_debug('unit=$' + toHex(unit));
_debug('slot=' + driveSlot + ' drive=' + drive);
_debug('buffer=' + toHex(buffer) + ' block=' + toHex(block));
switch (cmd) {
case 0: // INFO
@ -271,41 +290,32 @@ export default function SmartPort(io, cpu) {
break;
case 1: // READ
bufferAddr = new Address(0x44);
buffer = bufferAddr.readAddress();
blockAddr = new Address(0x46);
block = blockAddr.readWord();
readBlock(state, drive, block, buffer);
break;
case 2: // WRITE
bufferAddr = new Address(0x44);
buffer = bufferAddr.readAddress();
blockAddr = new Address(0x46);
block = blockAddr.readWord();
writeBlock(state, drive, block, buffer);
break;
case 3: // FORMAT
formatDevice(state, unit);
break;
}
} else if (off == 0x23 && cpu.sync()) {
debug('smartport entry');
} else if (off == smartOff && cpu.sync()) {
_debug('smartport entry');
var retVal = {};
var stackAddr = new Address(state.sp + 1, 0x01);
retVal = stackAddr.readAddress();
debug('return=' + retVal);
_debug('return=' + retVal);
var cmdBlockAddr = retVal.inc(1);
cmd = cmdBlockAddr.readByte();
var cmdListAddr = cmdBlockAddr.inc(1).readAddress();
debug('cmd=' + cmd);
debug('cmdListAddr=' + cmdListAddr);
_debug('cmd=' + cmd);
_debug('cmdListAddr=' + cmdListAddr);
stackAddr.writeAddress(retVal.inc(3));
@ -314,13 +324,13 @@ export default function SmartPort(io, cpu) {
buffer = cmdListAddr.inc(2).readAddress();
var status;
debug('parameterCount=' + parameterCount);
_debug('parameterCount=' + parameterCount);
switch (cmd) {
case 0x00: // INFO
status = cmdListAddr.inc(4).readByte();
debug('info unit=' + unit);
debug('info buffer=' + buffer);
debug('info status=' + status);
_debug('info unit=' + unit);
_debug('info buffer=' + buffer);
_debug('info status=' + status);
switch (unit) {
case 0:
switch (status) {
@ -396,7 +406,7 @@ export default function SmartPort(io, cpu) {
cpu.setState(state);
return ROM[off];
return rom[off];
},
write: function() {

View File

@ -4,10 +4,10 @@ import { driveLights, initUI, updateUI } from './ui/apple2';
import Printer from './ui/printer';
import DiskII from './cards/disk2';
import CFFA from './cards/cffa';
import LanguageCard from './cards/langcard';
import Parallel from './cards/parallel';
import RAMFactor from './cards/ramfactor';
import SmartPort from './cards/smartport';
import Thunderclock from './cards/thunderclock';
import VideoTerm from './cards/videoterm';
@ -103,9 +103,9 @@ var videoTerm = new VideoTerm(io, options.screen[0]);
var slinky = new RAMFactor(io, 1024 * 1024);
var disk2 = new DiskII(io, driveLights, sectors);
var clock = new Thunderclock(io);
var cffa = new CFFA(io);
var smartport = new SmartPort(io, cpu, { block: true });
initUI(apple2, disk2, cffa, false);
initUI(apple2, disk2, smartport, false);
io.setSlot(0, lc);
io.setSlot(1, parallel);
@ -113,5 +113,6 @@ io.setSlot(2, slinky);
io.setSlot(4, clock);
io.setSlot(3, videoTerm);
io.setSlot(6, disk2);
io.setSlot(7, smartport);
cpu.addPageHandler(lc);

View File

@ -3,10 +3,10 @@ import Prefs from './prefs';
import { driveLights, initUI, updateUI } from './ui/apple2';
import Printer from './ui/printer';
import CFFA from './cards/cffa';
import DiskII from './cards/disk2';
import Parallel from './cards/parallel';
import RAMFactor from './cards/ramfactor';
import SmartPort from './cards/smartport';
import Thunderclock from './cards/thunderclock';
import apple2e_charset from './roms/apple2e_char';
@ -76,6 +76,7 @@ if (canvas4) {
var apple2 = new Apple2(options);
var io = apple2.getIO();
var cpu = apple2.getCPU();
var printer = new Printer('#printer-modal .paper');
@ -83,14 +84,14 @@ var parallel = new Parallel(io, printer);
var slinky = new RAMFactor(io, 1024 * 1024);
var disk2 = new DiskII(io, driveLights);
var clock = new Thunderclock(io);
var cffa = new CFFA(io);
var smartport = new SmartPort(io, cpu);
initUI(apple2, disk2, cffa, options.e);
initUI(apple2, disk2, smartport, options.e);
io.setSlot(1, parallel);
io.setSlot(2, slinky);
io.setSlot(5, clock);
io.setSlot(6, disk2);
io.setSlot(7, cffa);
io.setSlot(7, smartport);

View File

@ -0,0 +1,26 @@
/*
$Cn01=$20
$Cn03=$00
$Cn05=$03
$Cn07=$00 Smartport / $3C Disk controller
*/
export var rom = [
0xa2,0x20,0xa2,0x00,0xa2,0x03,0xa2,0x00, 0x20,0x58,0xff,0xba,0xbd,0x00,0x01,0x8d,
0xf8,0x07,0x0a,0x0a,0x0a,0x0a,0xa8,0xb9, 0x80,0xc0,0x4a,0xb0,0x11,0xa5,0x00,0xd0,
0x0a,0xa5,0x01,0xcd,0xf8,0x07,0xd0,0x03, 0x4c,0xba,0xfa,0x4c,0x00,0xe0,0xa2,0x01,
0x86,0x42,0xca,0x86,0x46,0x86,0x47,0x86, 0x44,0xa2,0x08,0x86,0x45,0xad,0xf8,0x07,
0x48,0x48,0xa9,0x47,0x48,0xb8,0x50,0x0b, 0x68,0x0a,0x0a,0x0a,0x0a,0xaa,0x4c,0x01,
0x08,0x00,0x00,0x60,0x00,0x00,0x60,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xd7,0x53,
];

View File

@ -34,7 +34,7 @@ var stats;
var vm;
var tape;
var _disk2;
var _cffa;
var _smartPort;
var audio;
var keyboard;
var io;
@ -260,7 +260,7 @@ function doLoadLocalDisk(drive, file) {
var ext = parts.pop().toLowerCase();
var name = parts.join('.');
if (this.result.byteLength >= 800 * 1024) {
if (_cffa.setBinary(drive, name, ext, this.result)) {
if (_smartPort.setBinary(drive, name, ext, this.result)) {
driveLights.label(drive, name);
focused = false;
initGamepad();
@ -321,7 +321,7 @@ export function doLoadHTTP(drive, _url) {
var ext = fileParts.pop().toLowerCase();
var name = decodeURIComponent(fileParts.join('.'));
if (data.byteLength >= 800 * 1024) {
if (_cffa.setBinary(drive, name, ext, data)) {
if (_smartPort.setBinary(drive, name, ext, data)) {
driveLights.label(drive, name);
initGamepad();
}
@ -769,7 +769,7 @@ export function openPrinterModal() {
MicroModal.show('printer-modal');
}
export function initUI(apple2, disk2, cffa, e) {
export function initUI(apple2, disk2, smartPort, e) {
_apple2 = apple2;
cpu = _apple2.getCPU();
io = _apple2.getIO();
@ -777,7 +777,7 @@ export function initUI(apple2, disk2, cffa, e) {
vm = apple2.getVideoModes();
tape = new Tape(io);
_disk2 = disk2;
_cffa = cffa;
_smartPort = smartPort;
keyboard = new KeyBoard(cpu, io, e);
keyboard.create('#keyboard');