PC <> ZX
ZXNet echo conference «zxnet.pc»
From Kirill Frolov → To Max Melnikov 4 March 2001
Press RESET immediately, Max!
04 Mar 01 00:07, Max Melnikov wrote to All:
MM> We need programs for PC and SPECA to throw files between them
MM> (via the printer port or some other way).
MacroModem (MMD) on Spectrum. Better 4.51 and above. Something on the pussy
compatible.
The link must first be made with wires. There are several options:
1. Masovsky via a parallel port using 4 signals.
2. Mine is via a parallel port, 16 wires. Fast but with problems.
3. Mine is through software emulation of a serial port on a spec.
4. Like option 3, but in a cartoon according to the Kondratiev scheme.
5. Connecting the sound blaster to the tape input of the Spectrum.
Options 1, 2 and 3 worked in MMD. The first and second require
specialized software on the PC
and have major compatibility problems... In the first version, CPS=~1500 in MMD,
in the second
the speeds can be enormous, but it was almost impossible to add the software, so
CPS worked
very floating from 1300 to 4000. In reality, up to 16-32Kb/sec is possible. Third
option IMHO is the best (if you do not take into account the 4th one which was not
tested). The spec needs a source
supply +12 and -12 volts, 2 TTL inputs with diodes plus to the common wire, 2 TTL
output and microcircuit
converter MC1489 (or 1488 - I don’t remember). On pussy only free
serial port.Software port emulation on the spec works at a speed of 38400 bps.
Regarding low CPS, I can say that a significant part of the brakes comes from
MMD itself - that's why
You shouldn’t chase speed if you plan to use MMD. A
first two options
I don’t recommend it, although they are extremely simple - there will be problems with the software later
it will be easy
immeasurably since the options are very non-standard. And the speed is not much different
serial port
are different. And if there is a turbo mode, then you can emulate the 57600 software
problem-free (you can do it without
turbo, but buggy). With multichay you can immediately 115200 which gives 11.5kb/sec. In general
about parallel
It's better to forget the port.
From software for PC there is: for option 1, Masovskaya link program for dos. Under
second
special fossil for DOS (BBS worked!) and MMD-compatible program
x-modem.
For the third option under DOS the same x-modem program as for the second option and
any fossil under
serial port. It is written for Linux... For the fourth on PC you also need
x-modem program,
and on the spec there is a multimedia driver for MMD. Or you can transfer files via Melon
Z-modem.
For the fifth option there are some bourgeois programs, but the speed there is 1500
bit/sec -- they
They just emulate a tape recorder.
Connection diagram for 3 (or 4) connection options:
Spec: Direction: Pisyuk:
GND <------------> GNDTXD --> RXD
RXD <--TXD
not all software will work.
On the Scorpion computer
There's no need to solder anything at all...
these signals are already there.
RTS --> CTS
bytes are lost during SOFTWARE
There will be NO port emulation.
CTS <-- RTS
didn't get lost by accident. Why the hell not
necessary. Branded ZX-Spectrum
has these 4 signals on Interface-1.
DSR <-- DTR
DTR --> DCD
without any fossils and unnecessary software on the PC.
WHEN CONNECTING, BE SURE TO CONNECT THE COMPUTER CASES WITH A SEPARATE
BY WIRE! FOR EXAMPLE, PLUG ALL COMPUTER EQUIPMENT INTO A COMMON EXTENSION CORD
'PILOT' TYPE. Or connect when everything is unplugged. Otherwise maybe
BURN EVERYTHING CONNECTED TO BOTH COMPUTERS (TV from Spectrum,
Spectrum,
pisyuk, ethernet that leads to a neighbor, a neighbor’s computer...)
By the way, in the first (MAS) connection option there is an optical
denouement.
You can also make optical isolation on the serial port, like in MIDI.
But II decided that I don’t mind the pussy, but the Spectrum is oak, what will happen to him...
From Aleksandr Majorov → To Max Melnikov 6 March 2001
Hello Max!
05 Mar 01 16:55, Max Melnikov -> Aleksandr Majorov:
[skipped]
AM>> MMD of any series with a special modem driver, small
AM>> will a wire for the PC and a rope with 5 wires work? :)
MM> Suitable, as long as you solder as little as possible in the sinter...
I did everything under Scorp...
And it was necessary to solder the current wiring, and also the optical coupler just in case.
For Scorp - two wires to the Kempston joystick, two wires to the printer output.
Hy and general. And if there is an optocoupler, then another +5.
There are four wires on the PC in LPT, common.
Well, if there is an optocoupler, then you need to pull another +5 somehow from the PC ;)
I took the keyboard out through the socket :)
If you are not Scorpio, then you will have to change the addresses and bits in the MMD driver...
Alexand
From Kirill Frolov → To Aleksandr Majorov 11 March 2001
Press RESET immediately, Aleksandr!
11 Mar 01 02:33, Aleksandr Majorov wrote to Kirill Frolov:
KF>> Don't do that. From my own experience I say - twice later
KF>> redone.
AM> You are not like other people :-))
AM> Who else did it - they didn’t seem to complain...
At first I used your program. But she worked poorly or not at all
worked
in Windows what is called in the background. Then I made my own link. Everything was fine
but
in OS/2 it stopped the entire system! And when I installed Linux, then DOS
programs
There was nothing they could do to help me. And just write a module for the kernel like this (!!!)
for support
I didn’t really want a link via LPT. I did it fine via RS232.
Works
WITH ANY COMPUTER, ON ANY OS.
KF>> And in the end I came to the connection via a regular serial
KF>> port.
AM> And many more wires between computers.
A heap - at least 3, preferably 4. This is together with the common wire.
KF>> All this homemade stuff works extremely unreliably
AM> Hmm, how long have I been using this link? ...more than a year?
AM> I went on business trips for weeks - everything worked without problems.But when your link works, the whole system SLOWS. And the processor gets hot.
KF>> and only under DOS and Windows,
AM> What is worth it to me - that’s why I did it ;-)))))
And you wouldn’t be able to do it so easily for something other than dos.
You would have to read several tens of megabytes of documentation and
the same amount of raw materials.
Your link and mine on LPT and in dosemu work but 100% loading and everything slows down.
From Kirill Frolov → To All 13 March 2001
Press RESET immediately, All!
04 Mar 01 22:30, Valerij Kozhevnikoff wrote to Max Melnikov:
MM>> We need programs for PC and SPECA to throw files between them
MM>> (via the printer port or some other way).
VK> There is such a thing and a lot of it. Kirill Frolov and Alexander Majorov are their authors, and
VK> not only. I want it myself, but I only have something that spits out the contents
VK> disk in AY. Sources for PC and ZX can be found here.
Well, since raw materials are used here, I’ll throw them in too.
HO! There’s no need to point your finger at the program and say that I’m lame—I know it myself.
There is a bug when displaying file names. Maybe someone can fix it...
You can compile in TURBO PASCAL or freeware TMT PASCAL.
Doesn't seem to compile in Free-Pascal. Works only in DOS (Windows, OS/2).
The program works through the FOSSIL serial port driver. Via
I don’t remember which port and how, by default it seems to be through the first (zero). Fossil
It could be anything, including the link program.
=== Cut ===
{{$define DEBUG}
{$define BETA}
{$M 65520, 0, 655360}
{$V+,T+,P+,X+,I-,F-,Q-,S+}
{$D-,L-,R-,Y-}
{$ifdef BETA}
{$D+,L+,R+,Y+}
{$endif}
uses dos, crt, {windos,} strings, objects;
const _VERSION:string[16]='XMD ver 2.1'+
{$ifdef BETA}
'beta';
{$else}
'full';
{$endif}const _XMODEMERROR=1;
_PARAMERROR=2;
_FOSSILERROR=3;
_BADVIDEO=4;
_IOERROR=5;
_LOGBUFSIZE=8192;
_UPDATETIME=10;
_TIMERINT=$1C;
type wordptr=^word;
const Cfg:record
CheckSnow,DirectVideo:boolean;
LongNames:boolean;
LogName:string;
FossPort:word;
end=(CheckSnow:false;DirectVideo:false;LongNames:false;LogName:';FossPort:0);
var StdOut: text;
{$ifdef DEBUG} var xlog : text; {$endif}
procedure Log(s:string); forward;
{------------------------- DISPLAY VARIABLES -----------------------------}
{type DirStr=string;
type NameStr=string;
type ExtStr=string;}
var filenum : byte ; {file number global}
filepath : DirStr ; {send file path / receive path [79]}
filename : NameStr ; {file name [8]}
fileext : ExtStr ; {file extension ' or '.???' [4]}
fsize : longint ; {file size, HOBETA if RX}
transfered : longint ; {bytes transfered of file}
filetime : longint ; {вpемя начала пеpедачи файла}
attempts : byte ; {число попыток 10..0}
CPS : longint ; {CPS текущего файла}
files : byte ; {files to send / received}
totalsize: longint ; {bytes transfered global}
errors : longint ; {errors global}
starttime: longint ; {time programm started}{--------------------------------------- COMMON FUNCTIONS ------------------------------}
function HexWord(a:word):string;
const HexDigit:array[0..$F] of char = '0123456789ABCDEF';
var i:byte;
begin
HexWord[0]:=#4;
for i:=4 downto 1 do
begin HexWord[i]:=HexDigit[a mod $10]; a:=a div $10; end;
end;
function str2dig(a:byte):string;
var s:string[2];
begin
Str(a:2,s);
if s[1]=' ' then s[1]:='0';
str2dig:=s;
end;
procedure WrStd(s:string);
begin
WriteLn(StdOut,s);
end;
Function SubTime (oldtime : longint) : longint; forward;
procedure UpdateGlobalInfo; forward;
procedure UpdateFileInfo; forward;
{---------------------------- X-MODEM -----------------------------------}
const
RxTime = 3 ; {time during which nothing happens
must be accepted} {1/18 of seconds}
RxTimeSend = 40 ; {Max. pause between received blocks}
TxTime = 150 {75} ; {timeout for transmitter}
XTimeOut = 40 ; {X-modem timeout (for receiver?)}
BreakTime = 3 ; {delay when sending BREAK}
MaxAttempt = 10 ; {maximum number of attempts}
BlockSize = 256 ; {block size}
BuffSize = 16384 ; {buffer size for file}
{ --- Constants for the FOSSIL driver ---}
const RxNotEmpty=$0100 ;
TxEmpty=$4000 ;
FossRead = $0200 ;
{ FossWrite = $0100 ;}FossStatus = $0300 ;
FossInit = $0400 ;
FossPurgeRx = $0A00 ;
FossPurgeTx = $0900 ;
FossWrite2 = $0B00 ;
FossBlockWrite = $1900 ;
FossGetInfo = $1B00 ;
type FossInfo = record
StrSize : word ;
Version : byte ;
RevLevel : byte ;
ID : Pointer ;
InputSize : word ;
InputAvail : word ;
OutputSize : word ;
OutputAvail : word ;
ScreenWidth : byte ;
ScreenHeigh : byte ;
BaudRateMask : byte ;
end ;
type FI = ^FossInfo ;
{--- Константы X-modem из MMD ---}
const SOH_ = $01 ; {Start of every X-Modem Block}
ACK_ = $06 ; {Block acknowledge}
CRC_ = $43 ; {Request block, CRC mode}
NAK_ = $15 ; {Block NOT acnowledged}
EOT_ = $04 ; {End of Text (file)}
SYNC_= $16 ; {MMD command receipt aknowledge}
CAN_ = $18 ; {BREAK signal}
ERR_ = $17 ; {ERROR prefix}
EOF_ = $1A ; {EOF char}
COM_ = $1B ; {MMD command prefix}
EOB_ = $20 ; {MMD End Of Batch char}
errDisk = 10 ; {ошибка диска}
errEndFiles = 2 ; {конец пеpедачи}
{--- Пеpеменные и константы для pаботы ---}
type xmodetype = (undefined, send, recv) ;
type fnc = set of char ;
const fchar: fnc = ['!
From Kirill Frolov → To All 13 March 2001
Press RESET immediately, All!
04 Mar 01 22:30, Valerij Kozhevnikoff wrote to Max Melnikov:
VK> There is such a thing and a lot of it. Kirill Frolov and Alexander Majorov are their authors, and
VK> not only. I want it myself, but I only have something that spits out the contents
VK> disk in AY. Sources for PC and ZX can be found here.
And now I’m throwing raw fossils for a link via LPT. Useful for remodeling
BUT YOU SHOULD NOT DO THIS!!!
Two files. First one first.
=== Cut ===
IDEAL
P486
MODEL TINY
VER EQU "0.0 alpha"
_TEST = 0
PUBLIC StDCD, Baud
PUBLIC StRxTx
PUBLIC RxBot, RxRead, RxWrite, RxTop
PUBLIC TxBot, TxRead, TxWrite, TxTop
PUBLIC _TxEmpty, _TxNotFull, _RxNotEmpty, _RxOverrun
EXTRN LinkInit, LinkDeinit, IntLink
CODESEG
STARTUPCODE
ORG 100h
IF_TEST
ELSE
jmp Install
lea dx, LogoTxt
mov ah, 9
int 21h
lea dx, ASCII_ID
mov ah, 9
int 21h
mov cl, [80h]
mov ch, 0
or cx, cx
jz @@noparam
mov bx, 81h
@@cmp: mov ax, [bx]
inc bx
cmp al, ' '
jnz @@xparam
loop @@cmp jmp @@noparam
@@xparam: cmp al, '0'
jc @@noparam
cmp al, '8'
jnc @@noparam
sub al, '0'
mov ah, 0
mov [FossPort], ax
jmp CheckInst
@@noparam: lea dx, @@nopartxt
mov ah, 9
int 21h
mov ax, 4c01h
int 21h ; EXIT
@@nopartxt db 13,10,"No Port specified.",13,10
db "USAGE: zxfos ",13,10,"$"
CheckInst: mov cx, 19 ; fossil driver info structure size
mov ax, cs
mov es, ax
lea di, TopMemory
mov dx, [FossPort]
mov ah,1bh
int 14h ; GetDriverInfo
cmp ax,8
jc Install ; driver not installed
mov ax, cs
mov ds, ax
mov es, [word TopMemory+4] ; ASCII ID 4-byte pointer
mov di, [word TopMemory+6]
lea si, ASCII_ID
mov cx, ASCII_ID_Length
jnz Install ; DIFFERENT ASCII STRINGS -> not installed
; Driver already installed on specified port
lea dx, @@alreadytxt
mov ah, 9
int 21h
mov ax, 4c00h
int 21h ; EXIT
@@alreadytxt: db 13,10
db "Fossil Driver already installed on specified port."
db 13,10,"$"
LogoTxt db 13,10
db "----------------------------------------------------------------"
db 13,10,"$"
ENDIF
Install: lea ax, TopMemory ; set buffers
mov [TxBot], ax
mov [TxWrite], ax
mov [TxRead], ax
add ax, [TxSize]
mov [TxTop], ax
mov [RxBot], ax
mov [RxWrite], ax
mov [RxRead], ax
add ax, [RxSize]
mov [RxTop], ax ; buffers empty
call near LinkInit ; link initialization
jc @@failinit
call near LinkDeinit
mov ax, cs
mov [ID_seg], ax ; ASCII_ID segment
xchg ah, al
bswap eax ; set user function (80..C0) address
lea ax, JMPOLDINT14
mov cx, 40h
lea bx, UFADDR
@@fill1: mov [bx], eax
add bx, 4
loop @@fill1
mov ax, 3514h ; save old and set new int14 vector
int 21h
mov [word OldInt14], bx
mov [word OldInt14+2], es
mov ax, 2514h
lea dx, INT14
int 21h
IF _TEST
mov ah, 4
mov dx, 00ffh
int 14h
mov ah, 4
mov dx, 0
int 14h
mov ah, 1bh
mov cx, 100h
sub sp, cx ; Get driver info
mov di, sp
push cx
push ss
pop es
mov dx, 0
int 14h
pop cx
add sp, cx
;@@keyloop: mov ah, 01
; int 21h
; jmp @@ttyexit
@@fossloop: mov ah, 03h
mov dx, 0
int 14h
test ah, _RxNotEmpty
jz @@reltime
mov ah, 02h
mov dx, 0
int 14h
mov ah, 0bh
mov dx, 0
int 14h
jmp @@chkkey
@@reltime: hlt
@@chkkey: mov ah, 0dh
int 14h
inc ax
jz @@fossloop
jmp @@ttyexit
;-- TERMINAL ---
@@ttyloop: mov ah, 03h
mov dx, 0
int 14h
test ah, _RxNotEmpty
jz @@ttykeyb
mov ah, 02h
int 14h
; mov cx, 1
; mov ax, cs
; mov es, ax
; mov di, offset @@al_
; mov dx, 0
; mov ah, 18h
; int 14h
; mov al, [@@al_]
mov ah, 15h
int 14h
@@ttykeyb: mov ah, 0dh
int 14h
inc ax
jz @@ttyloop
mov ah, 0eh
int 14h
cmp al, 1bh
jz @@ttyexit
@@send: mov ah, 0bh
mov [@@al_], al
mov dx, 0
int 14h
dec ax
; mov [@@al_], al
; mov cx, 1
; mov ax, cs
; mov es, ax
; mov di, offset @@al_
; mov dx, 0
; mov ah, 19h
; int 14h
; dec ax
jnz @@ttybeep
mov al, [@@al_]
mov ah, 15h
int 14h
jmp @@ttyloop
@@ttybeep: mov ax, 1507h
int 14h
jmp @@ttyloop
@@ttyexit: jmp DeInstall
@@al_ db 0
ELSE
lea dx, @@installtxt
mov ah, 9
int 21h
mov dx, [RxTop]
add dx, 200h ; 100h
ror dx, 4
test dx, 0f000h
jz @@noadd
inc dx
@@noadd: and dx, 0fffh ; MAX 0fff0h bytes !
mov ax, 3100h ; Terminate and stay Resident
int 21h
ENDIF
@@failinit: mov ax, 4c01h
int 21h ; EXIT
@@installtxt db 13,10,"Fossil Driver installed.",13,10,"$"
DeInstall: call near LinkDeinit
mov ax, [word OldInt14]
mov ds, [word OldInt14+2]
mov ax, 2514h
int 21h ; restore old INT14
mov ax, 4c00h
int 21h ; EXIT
;----------------------------------------------------------------------------
;***************** DATA SEGMENT ********************************
;----------------------------------------------------------------------------
include "zxfos.inc"
InitFlg db 0 ; 1 if need Init Video.
DriverInfo dw DriverInfo_Length
FSpec db 5
FRev db 5
ID_ofs dw offset ASCII_ID
ID_seg dw ?
RxSize dw 512 ;2048 ; default value
RxFree dw ?
TxSize dw 512 ;2048 ; too ^^
TxFree dw ?
Width db ?
Height db ?
Baud db 11100011b ; 8N1
DriverInfo_Length = ($-DriverInfo)
ASCII_ID db "Fr0lOFF ZXLINK fossil driver (C) ver.",VER,0dh,0ah
db "Compiled at ", ??date, " ", ??time
db 0,"$"
ASCII_ID_Length = ($-ASCII_ID)
;FossPort dw ?
;Status equ word StDCD
;StDCD db 08h
;StRxTx db _TxEmpty + _TxNotFull
;RxBot dw ?
;RxTop dw ?
;TxBot dw ?
;TxTop dw ?
;TxRead dw ?
;TxWrite dw ?
;RxRead dw ?
;RxWrite dw ?
;; StackFrame
_ES equ [word bp+12h]
_DS equ [word bp+10h]
_AX equ [word bp+0eh]
_CX equ [word bp+0ch]
_DX equ [word bp+0ah]
_BX equ [word bp+8]
_SP equ [word bp+6]
_BP equ [word bp+4]
_SI equ [word bp+2]
_DI equ [word bp+0]
_AL equ [byte bp+0eh]
_AH equ [byte bp+0fh]
_CL equ [byte bp+0ch]
_CH equ [byte bp+0dh]
_DL equ [byte bp+0ah]
_DH equ [byte bp+0bh]
_BL equ [byte bp+08h]
_BH equ [byte bp+09h]
;----------------------------------------------------------------------------
;********************* INT 14 HANDLE **************************************
;----------------------------------------------------------------------------
PROC INT14
push es
push ds
pusha ; ax,cx,dx,bx,sp,bp,si,di
mov bp,sp
mov cx,cs ; set DS=ES=CS
mov ds,cx
mov es,cx
cmp ah, 4
jz @@spec ; special INIT / DEINIT.
cmp ah, 5
jz @@spec
cmp ah, 7 ; check for valid PORT
jz @@run
cmp ah, 0dh
jc @@check
cmp ah, 0fh
jc @@run
cmp ah, 11h
jc @@check
cmp ah, 14h
jc @@run
jz @@check
cmp ah, 18h
jc @@run
cmp ah, 1ch
jnc @@run
jmp @@check
@@spec: cmp dx, 00ffh
jz @@run ; "SPECIAL PORT"
@@check: cmp dx, 8000h
org $-2
FossPort dw 0
jnz @@cont ; INVALID PORT -> CALL PREVIOUS INT14
@@run: cmp ah, 1ch ; BASIC (00..1Bh) funtions
jc @@runbasic
cmp ah, 80h ; USER 80h..BFh functions
jnc @@runuser
cmp ah, 7eh ; EXTENDED 7Eh, 7Fh -- install/remove user
function
jc @@cont ; 1ch..7dh not supported
movzx bx,ah ; start EXTENDED functions
add bx,bx
jmp [bx+EFADDR]
@@runbasic: movzx bx,ah ; start BASIC function
add bx,bx
jmp [bx+FADDR]
@@runuser: cmp ah,0c0h ; start USER function
jnc @@cont ; not supported
movzx bx,ah
add bx,bx
jmp [bx+UFADDR]
@@cont: popa
pop ds
pop es
JMPOLDINT14:
db 0eah ; jump far to old INT14
OldInt14: dd 0
ENDP
PROC Exit
popa
pop ds
pop es
iret
ENDP
;----------------------------------------------------------------------------
;***************** FOSSIL FUNCTIONS JMP TABLE ****************************
;----------------------------------------------------------------------------
FADDR dw SetBaud
dw TxChar
dw RxChar
dw StatusRq
dw InitDriv
dw Deinit
dw DTRctrl
dw TimerParam
dw FlushTx
dw PurgeTx
dw PurgeRx
dw TxNoWait
dw PeekAhead
dw PeekKeyb
dw ReadKeyb
dw FlowCtrl
dw CtrlKcheck
dw SetCursor
dw ReadCursor
dw WriteANSI
dw WatchDog
dw WriteChar
dw HookTimerInt
dw Reboot
dw ReadBlock
dw WriteBlock
dw SendBreak
dw GetDrivInfo
EFADDR dw InstallUser
dw RemoveUser
;----------------------------------------------------------------------------
;***************** FOSSIL BASIC FUNCTIONS ********************************
;----------------------------------------------------------------------------
PROC SetBaud ; AX=BAUD RATE DX=PORT -> AX=STATUS
jmp StatusRq
ENDP
;----------------------------------------------------------------------------
PROC TxChar ; AL=CHAR DX=PORT -> AX=Status ; Wait if buffer id full
@@wait: test [StRxTx], _TxNotFull
jnz @@ready
sti
hlt
jmp @@wait
@@ready: cli
mov al, _AL
call PutByte
jmp StatusRq
ENDP
;----------------------------------------------------------------------------
PROC RxChar ; DX=PORT -> AH=0 AL=CHAR ; Wait if buffer is empty
@@wait: test [StRxTx], _RxNotEmpty
jnz @@ready
sti
hlt
jmp @@wait
@@ready: cli
mov bx, 8000h
org $-2
RxRead dw 0
mov al, [bx]
inc bx
cmp bx, 8000h
org $-2
RxTop dw 0
jc @@nover
mov bx, 8000h
org $-2
RxBot dw 0
@@nover: cmp bx, 8000h
org $-2
RxWrite dw 0
jnz @@nempty
and [StRxTx], not _RxNotEmpty
@@nempty: and [StRxTx], not _RxOverrun
mov [RxRead], bx
mov ah, 0
mov _AX, ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC StatusRq ; DX=PORT -> AX=Status
;
; AH: bit: 6 =1 : Output is empty
; 5 =1 : Output is NOT full
; 1 =1 : Input OVERRUN
; 0 =1 : Input NOT EMPTY
;
; AL: bit: 7 =1 : CARRIER DETECT
; 3 =1 : Always =1, newer 0 !
mov ax, 0
org $-2
StDCD db 08h
StRxTx db _TxEmpty + _TxNotFull
Status equ word StDCD
mov _AX, ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC InitDriv ; DX=PORT -> AX=1954H BL=Max.Funct. BH=Rev.Level ; DTR raised
;
; if DX=00FF then any initialization needed to make keyboard
; and display available for FOSSIL use should be performed.
; bx=4F50h signals that ES:CX points to a flag byte in the
; application that the driver should increment when its
; keyboard routines detect a CTRL-C
;
cmp _DX, 00ffh
jnz @@init ; Not SPECIAL
mov [InitFlg], 1
jmp @@end
@@init: mov [StRxTx], _TxEmpty + _TxNotFull
mov ax, [RxBot]
mov [RxWrite], ax
mov [RxRead], ax
mov ax, [TxBot]
mov [TxWrite], ax
mov [TxRead], ax ; purge buffers
test [InitFlg], 0ffh
jz @@cont
; video and keyboard initialization
mov ax, 0003h
int 10h ; set video mode 3
@@clkey: mov ah, 1
int 16h
jz @@cont ; keyb. buffer empty
mov ah, 0
int 16h
jmp @@clkey
@@cont: call near LinkInit
@@end: mov _AX, 1954h
mov _BX, 051bh
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC Deinit ; DX=PORT -> none
;
; if dx=00FFh then the initialization that was performed when
; FOSSIL function 04h (INIT) with DX=00FFh should be undone
;
cmp _DX, 00ffh
jnz @@cont ; Not SPECIAL
mov [InitFlg], 0
jmp Exit
@@cont: ;;; call near LinkDeinit ; ???
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC DTRctrl ; AL=1 raise /0 lower DTR DX=PORT -> AL=DTR 1=true 0=false
test _AL, 1
jnz @@raise
call near LinkDeinit
mov _AL, 0
jmp Exit
@@raise: call near LinkInit
mov ax, 1
sbb ax, 0
mov _AL, al
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC TimerParam ; none -> AL=timer tick interrupt AH=ticks/second DX=mS/tick
mov _AX, 1c12h ; INT 1CH, 18 ticks / second
mov _DX, 56 ; 55.555[5]
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC FlushTx ; DX=PORT -> none ; Wait until buffer is empty
@@wait: test [StRxTx], _TxEmpty
jnz @@ready
sti
hlt
jmp @@wait
@@ready:
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC PurgeTx ; DX=PORT -> none ; Exit immendiatelly
or [StRxTx], _TxEmpty + _TxNotFull
mov ax, [TxBot]
mov [TxRead], ax
mov [TxWrite], ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC PurgeRx ; DX=PORT -> none ; Exit immendiatelly
and [StRxTx], not (_RxOverrun + _RxNotEmpty)
mov ax, RxBot
mov [RxRead], ax
mov [RxWrite], ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC TxNoWait ;DX=PORT AL=CHAR -> AX=1 char sent AX=0 not sent (buffer
full)
test [StRxTx], _TxNotFull
jnz @@ready
xor ax,ax
jmp @@exit
@@ready: mov al, _AL
call PutByte
mov ax, 1
@@exit: mov _AX, ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC PeekAhead ; DX=PORT -> AH=0 AL=CHAR if available / AX=FFFFh if not
test [StRxTx], _RxNotEmpty
jnz @@ready
mov ax,0ffffh
jmp @@exit
@@ready: mov bx, [RxRead]
mov al, [bx]
mov ah,0
@@exit: mov _AX, ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC PeekKeyb ; none -> AX=CHAR if available / AX=FFFFh of not
mov ah,11h ; get keyb status
int 16h
jnz @@exit ; character available in keyb. buffer AX=SCANCODE
mov ax,0ffffh ; no char available
@@exit: mov _AX, ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC ReadKeyb ; none -> AX=CHAR ; Wait if not available
mov ah,10h ; get keyb scan code / wait if not available
int 16h
mov _AX, ax
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC FlowCtrl ; DX=PORT AL=Flow ctrl bit mask -> none
; AL bits:
; 0 =1 : enables remote XON/XOFF (contrl FOSSIL tx)
; 1 =1 : RTS/CTS for FOSSIL<->MODEM
; 3 =1 : enables fossil XON/XOFF (control REMOTE tx)
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC CtrlKcheck ; DX=PORT AL=flag byte ->
; -> AX=1 Ctrl-C(-K) detected sinse last call, esle AX=0
; AL bits:
; 0 =1 : enable/disable CTRL-C(-K) check
; 1 =1 : stop transmitter
; =0 : release previous stop
mov _AX, 0 ; fake
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC SetCursor ; DH=ROW DL=COL -> none
mov dx, _DX
mov ah, 02h
xor bx, bx
int 10h
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC ReadCursor ; none -> DH=ROW DL=COL
mov ah,03h
xor bx,bx
int 10h
mov _DX, dx
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC WriteANSI ; AL=CHAR -> none ; not re-entrant, DOS funct. may be used
mov ah,02h
mov dl, _AL
int 21h ; ANSI.SYS required
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC WatchDog ; AL=1 enable AL=0 disable watchdog DX=PORT -> none
; FOSSIL will force the system to reboot if CARRIER DETECT
; on specified port drops while watchdog is on.
; Is not nessesary for port to be active (funct. 04)
; for this function to be used.
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC WriteChar ; AL=CHAR -> none ; this function must be re-entrant !
mov al, _AL
mov ah, 0eh
xor bx, bx
int 10h
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC HookTimerInt ; AL=1 set AL=0 remove, ES:DX=ADDRESS ->
; -> AX=0 if ok, AX=FFFFh if unsuccessful
mov _AX, 0ffffh ; not released
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC Reboot ; AL=0 cold AH=1 warm boot -> never returns
db 0eah ; jump far
dd 0ffff0000h ; reboot
ENDP
;----------------------------------------------------------------------------
PROC ReadBlock ; CX=MAXIMUM SIZE ES:DI=USER BUFFFER PTR DX=PORT ->
; -> AX=CHARS ACTUALLY REMOVED ; not wait if no char avail.
xor bx, bx ; counter
test [StRxTx], _RxNotEmpty
jz @@nempty ; no data in buffer
mov cx, _CX ; max SIZE in application
or cx, cx
jz @@nempty
mov es, _ES
mov di, _DI ; dest. ES:DI
mov si, [RxRead] ; source DS:SI
mov ax, [RxWrite] ; if (RxWrite > RxRead)
sub ax, si ; then { move (ax) or move (cx) ?}
jnc @@moveax ;
mov ax, [RxTop] ; if (RxTop-RxRead > _CX)
sub ax, si ; then { move (cx) }
cmp ax, cx ;
jnc @@movecx ;
mov cx, ax ; else move (RxTop-RxRead)
add bx, cx ; add to counter
rep movsb ;
mov cx, _CX ; bytes left = _CX - (RxTop-RxRead)
sub cx, ax ;
mov si, [RxBot] ; buffer left = RxWrite - RxBot
mov ax, [RxWrite] ;
sub ax, si ;
@@moveax: cmp ax, cx ; if bytes_left < buffer_left
jnc @@movecx ; then move (bytes_left)
mov cx, ax ; else move (buffer_left)
@@movecx: add bx, cx ; add to counter
rep movsb
mov [RxRead], si
and [StRxTx], not _RxOverrun
cmp si,[RxWrite]
jnz @@nempty
and [StRxTx], not _RxNotEmpty
@@nempty: mov _AX, bx ; return data
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC WriteBlock ; CX=COUNT ES:DI=USER BUFFER PTR DX=PORT ->
; -> AX=CHARS ACTUALLY REMOVED ;
xor bx, bx ; counter bytes removed
test [StRxTx], _TxNotFull
jz @@nfull ; tx buffer is full
mov cx, _CX ; bytes MAX.
or cx, cx
jz @@nfull
mov ds, _ES
mov si, _DI ; source -> DS:SI
mov ax, cs
mov es, ax
mov di, cs:[TxWrite] ; dest. -> ES:DI
mov ax, cs:[TxRead] ; if TxWrite < TxRead
sub ax, di ; then { move (ax) or move (cx) ? }
ja @@moveax ;
mov ax, cs:[TxTop] ; if TxTop-TxWrite >= BytesMax (_CX)
sub ax, di ; then move _CX bytes
cmp ax, cx ;
jnc @@movecx ;
mov cx, ax ; else move (TxTop-TxWrite) bytes
add bx, cx ; add to counter
rep movsb ; and move it
mov cx, _CX ; then BytesLeft := _CX - (TxTop-TxWrite)
sub cx, ax ;
mov di, cs:[TxBot] ; if (TxRead-TxBot) > BytesLeft
mov ax, cs:[TxRead] ; then move (BytesLeft) bytes
sub ax, di ;
@@moveax: cmp ax, cx ; if ax >= cx then move (cx)
jnc @@movecx ; else move (ax)
mov cx,ax ; else move (TxRead-TxBot) bytes
@@movecx: add bx, cx ; add to counter
rep movsb ; and move it
mov ax,cs
mov ds,ax
mov [TxWrite], di
and [StRxTx], not _TxEmpty
cmp di, [TxRead]
jnz @@nfull
and [StRxTx], not _TxNotFull
@@nfull: mov _AX, bx ; return data
call near IntLink
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC SendBreak ; AL=1 start AL=0 stop sending BREAK DX=PORT -> none
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC GetDrivInfo ; CX=BUFFER SIZE ES:DI=ADDRESS DX=PORT ->
; -> AX=BYTES TRANSFERED ACTUALLY
; 0 (word) = Structure size
; 2 (byte) = FOSSIL spec version
; 3 (byte) = Driver rev level
; 4 (dwrd) = Pointer to ASCII ID
; 8 (word) = Input buffer size
; 0A (word) = Bytes avail (input)
; 0C (word) = Output buffer size
; 0E (word) = Bytes avail (output)
; 10 (byte) = Screen width, chars
; 11 (byte) = Screen height, chars
; 12 (byte) = Baud rate mask
; (See call 00h)
mov ah, 0fh
int 10h ; Get video mode
mov [Width], ah
mov [Height], 25
xor ax, ax
test [StRxTx], _RxNotEmpty
jz @@rxadd
mov ax, [RxWrite]
sub ax, [RxRead]
jnc @@rxfree
@@rxadd: add ax, [RxSize]
@@rxfree: mov [RxFree], ax
xor ax, ax
test [StRxTx], _TxEmpty
jnz @@txadd
mov ax, [TxWrite]
sub ax, [TxRead]
jnc @@txfree
@@txadd: add ax, [TxSize]
@@txfree: mov [TxFree], ax
mov si, offset DriverInfo
mov es, _ES
mov di, _DI
mov cx, _CX
mov ax, [DriverInfo]
cmp ax, cx
jnc @@movecx
mov cx, ax
@@movecx: mov _AX, cx
rep movsb
jmp Exit
ENDP
;----------------------------------------------------------------------------
; ************** FOSSIL EXTENDED FUNCTIONS ********************************
;----------------------------------------------------------------------------
PROC InstallUser ; AL=code ES:DX=address ->
; AX=1954H BL=code (same as AL) BH=1 if ok else BH=0
xor ax,ax
mov al, _AL
mov _BX, ax
mov _AX, 1954h
jmp Exit
ENDP
;----------------------------------------------------------------------------
PROC RemoveUser ; AL=code ES:DX=address ->
; AX=1954h BL=code (same as AL) BH=1 if ok, else BH=0
; if ES:DX not same as address in JMP table error occurs.
xor ax,ax
mov al, _AL
mov _BX, ax
mov _AX, 1954h
jmp Exit
ENDP
;----------------------------------------------------------------------------
;******************** Common Subrutines ********************************
;----------------------------------------------------------------------------
;
PROC PutByte ; AL=Byte, tx buffer not full.
mov bx, 8000h
org $-2
TxWrite dw 0
mov[bx], al
inc bx
cmp bx, 8000h
org $-2
TxTop dw
jc @@never
mov bx, 8000h
org $-2
TxBot dw
@@nover : cmp bx , 8000h
org $-2
TxRead dw
jnz @@exit
and [ StRxTx ] , not _TxNotFull
@@exit : and [ StRxTx ] , not _TxEmpty
mov [ TxWrite ] , bx
call near IntLink
ret
ENDP
;---------------------------------------------------------------------------------------------
;***************** UNDEFINED DATA SEGMENT *****************************
;---------------------------------------------------------------------------------------------
UDATASEG
UFADDR dd 40h dup(?) ; USER DEFINED FUNCTION ADDRESSES
;; STACK 400h
TopMemory = $
END
=== Cut ===
To the rest of the world in this category:
=== Cut ===
;---------------------------------------------------------------------------------------------
;***************** ZX-LINK Send and Receive procedures *******************
;---------------------------------------------------------------------------------------------
;
IDEAL
P486
TINY MODEL
_LOOPBACK = 0
EXTRN StRxTx, StDCD
EXTRN RxBot, RxTop, RxRead, RxWrite
EXTRN TxBot, TxTop, TxRead, TxWrite
include "zxfos.inc"PUBLIC LinkInit, LinkDeinit, IntLink ; DS=CS!
_PE equ 20h ; direction change 0=receive 1=send
_ACK equ 40h ; interrupt request
_ERROR equ 08h ; reversed / DCD
_AUTO equ 02h ; invert acknowledge
_SLCT equ 08h ; return direction 1=receive
_IRQ equ 10h ; enable interrupts
_DIR equ 20h ; direction set 1=receive
DATASEG
LptInt db 07h
LptPort dw 378h
LptActive db 0
UDATASEG
RxBlockProc dd ?
OldIntVec dd ?
CODESEG
;===============================================================================
; Initialization and configuration. The output flag is cf=1 if there are errors.
;
PROC LinkInit
; setting up an LPT port
test [LptActive], 1
jnz @@exit
mov [byte LptActive], 1
mov ax, [word LptInt]
call Int2PIC
pusha; a new interrupt vector is installed
mov ah, 35h
int 21h
mov [word OldIntVec], bx
mov [word OldIntVec+2], es
mov ah, 25h
mov dx, offset LptIntProc
int 21h
popa
not cx
cli
in al, (dx) ; interrupt enable in PIC
and al, ch
out (dx), al
stimov dx, [LptPort] ; enabling interrupts in the port
inc dx
inc dx
mov al, _SLCT or _IRQ or _DIR
out (dx), al
mov [byte StRxTx], _TxEmpty or _TxNotFull
mov ax, [TxBot]
mov [TxRead], ax
mov [TxWrite], ax
@@exit: clc
ret
ENDP
;================================================================================
; Shutdown
;
PROC LinkDeinit
mov ax, [word LptInt]
call Int2PIC
push ax
cli ; disabling interrupts in PIC
in al, (dx)
or al, ch
out (dx), al
sti
pop ax
push ds ; restoring the interrupt vector
mov dx, [word OldIntVec]
mov ds, [word OldIntVec+2]
mov ah, 25h
int 21h
pop ds
mov dx, [LptPort] ; disabling LPT port
add dx, 402h
mov al, 34h; ECP set to ps/2
out (dx), al
sub dx, 400h
mov al, 2bh ; off...
out (dx), al
mov [byte LptActive], 0
ret
ENDP
; INPUT: AL=hardware interrupt number.
; OUTPUT: DX=address PIC+1, AL=vector for DOS, CH=mask for PIC.
PROC Int2PIC NEARmov right, 9pm
add ax, 8
cmp al, 10h
jc @@pic20
mov right, 0a1h
add ax, 60h
@@pic20: mov cx, ax
and cx, 7
mov ch, 1
shl ch, cl
ret
ENDP
;========================================================================================
;
PROC IntLink
ret
ENDP
;==========================================================================================
; Обpаботка пpеpываний от поpта
;
PROC LptIntProc FAR
pusha ; ax,cx,dx,bx,sp,bp,si,di
push right
mov ax, cs
mov ds, ax
mov right, [LptPort]
inc right
in al