This post originally appeared on Spectrum Computing.
STRMS and CHANS on SAM with Network
SAM's ROM supports the Network as a device for LOADing and SAVEing but doesn't really have a Net channel that we can use with BASIC streams. The BAISC interpreter will allow you to use an “N” channel specifier, but it expects DOS to provide the routines. (I think? But none of SAMDOS, MasterDOS or BDOS seem to provide it, in fact they (BDOS in particular) tend to clobber the save/load functions).
Adding a custom channel specification is well documented for the Spectrum, and SAM works in much the same way. SAM's networking is not compatible with Interface 1 Net (unlike MGT DiSCIPLE) but Streams and Channels are very similar to the ZX Spectrum implementation, even using the same system variable locations (see Ian Beardsmore's article Spectrolysis: Channels and Streams).
A typical channel definition is a group of 5 bytes (Microdrives are a bit different). They contain pointer to an input routine, a pointer to an output routine, and a channel letter. As with the Spectrum it seems the letter doesn’t really matter.
I set up a couple of routines that use the ROM routines for Net/MIDI input and output. The routines expect the data byte in register A and are called for each byte to be sent or received. ROM1 needs to be paged in, and for INKEY$ it needs to remain paged in after the routine RETurns.
I picked $4000 as a load and run address (which is the start of the system heap) because it is kept paged-in along with the system variables while stuff is being shuffled in the higher memory area. I didn't bother using JHEAPROOM to formally request some heap space, but that would be more elegant I think. Maybe there's a better place to stash these routines anyway!
Once installed, you can use stream #4 for input or output. It works fine, unfortunately it's REALLY slow! But it works.
BASIC example
PRINT #4; "Spectrum Computing" INPUT #4; A$ : PRINT A$ PRINT INKEY$ #4 LIST #4 DIR #4;1
Source code
; MAKEROOM works similarly to ZX MAKESPACE but also has other entry points ; to handle paging etc. The entry point 0x1E1B will open BC bytes at (hl). ; The Tech manual gives STRMS as 0x5C0C, (but that includes the extra ones ; that the Spectrum doesn't have?). The ones in common start at 0x5C10 (as ; they do on ZX Spectrum) so we can use the same values. DELBC: equ 0x005F ; Delay BC MAKEROOM: equ 0x1E1B ; Open BC bytes at (HL), must be in area C. PROGP: equ 0x5A9F ; RAM page number (0-31) (usually 0) PROG: equ 0x5AA0 ; Offset within PROGP, plus 0x8000 (usually 0x9CD5) HPST: equ 0x5BC8 ; Start of Sytem Heap (usually 0x4000) STRMS: equ 0x5C10 ; Streams area (same as ZX) CHANS: equ 0x5C4F ; Channels area (same as ZX) NMOUT: equ 0xE54D ; Net/MIDI out (byte in A) CKNET: equ 0xE73D ; Check if Net busy NMIN: equ 0xE74F ; Net/MIDI in. Byte in A with carry set ; or NC and A=0 if no byte was recieved. LMPR: equ 0xFA ; The Lower Memory Page Register Address HMPR: equ 0xFB ; The Higher Memory Page Register Address org 0x4000 ; 16384 // start of Heap dump 0,0 ; RAM page 0, offset 0 autoexec ; AUTO boot ; Move heap pointer to account for our program ld hl,newhpst ld (HPST),hl di in a,(HMPR) push af ld a,(PROGP) ; Usually 0 out (HMPR),a ; Page bank 0 into area C (0x8000-0xBFFF) ld hl,(PROG) ; Usually holds 0x9CD5 dec hl ; Make space for 5 bytes immediately below PROG. ld bc,0x0005 ; (We will find the top of the CHANS call MAKEROOM ; area by going backwards from PROG). inc hl ; hl points to 1st byte of new channel data ld a, nso \ 0x100 ; LSB of output routine ld (hl),a inc hl push hl ; Save address of 2nd byte of new channel data ld a, nso / 0x100 ; MSB of output routine ld (hl),a inc hl ld a,nsi \ 0x100 ; LSB of input routine ld (hl),a inc hl ld a,nsi / 0x100 ; MSB of input routine ld (hl),a inc hl ld a,0x4E ; Channel name 'N' ld (hl),a POP hl ; Get address of 2nd byte of output routine ld de,(CHANS) ; Calculate the offset to the channel data and a ; sbc hl,de ; ex de,hl ; and store it in DE ld hl,STRMS ; ld a,0x04 ; Stream to open, in this case #4. add a,0x03 ; Account for streams -3, -2, -1 add a,a ; Calculate the offset (2 bytes per stream) ld b,0x00 ; ld c,a ; add hl,bc ; … and store it in hl ld (hl),e ; LSB of 2nd byte of new channel data inc hl ; ld (hl),d ; MSB of 2nd byte of new channel data pop af out (HMPR),a ret ; Net/MIDI output nso: di push af in a,(LMPR) ; set 6,a ; out (LMPR),a ; enable ROM1 push bc ld B,100 ; delay call DELBC ; POP bc call CKNET ; wait for Net ready POP af call NMOUT ; send byte ei ret ; Net/MIDI Input nsi: di in a,(LMPR) set 6,a out (LMPR),a call CKNET ;wait for Net ready wait: call NMIN ;wait for a byte JR NC,wait ei ret newhpst: equ $