;*
;
; ### Sano.asm by JM v 0.20c ###
;
; - Created 901025 by JM -
;
; Bugs: Well...
;
;
; Edited:
;
; - 901025 by JM -> v0.01       - started writing this thing.
; - 901029 by JM -> v0.10       - works.  dpy_msg has a buffer of 256 bytes.
; - 901220 by JM -> v0.20c      - this version commented for C=Lehti.
;
;

                include "exec/types.i"
                include "exec/execbase.i"
                include "exec/tasks.i"
                include "exec/nodes.i"
                include "exec/memory.i"
                include "exec/io.i"
                include "exec/interrupts.i"
                include "hardware/intbits.i"
                include "libraries/dos.i"
                include "devices/narrator.i"

                xref    _LVOOpenLibrary,_LVOCloseLibrary,_LVORawDoFmt
                xref    _LVOOpenDevice,_LVOCloseDevice,_LVODoIO
                xref    _LVOAllocMem,_LVOFreeMem,_LVOTranslate
                xref    _LVOAllocSignal,_LVOFindTask,_LVOFreeSignal
                xref    _LVOOutput,_LVOWrite

LF              equ     10              ; line feed
BUFFER          equ     16384           ; „„nnepuskurin koko

.DosBase        equ     -4              ; muuttujien offsetit pinossa
.FinnslatorBase equ     -8
cmdlin          equ     -12
cmdlen          equ     -16
ioreq           equ     -20
msgport         equ     -24
narrator        equ     -25             ; lippu: narrator.device avattu

mem             equ     -30             ; muistiosoitin
buffer          equ     -34             ; puskurin alkuosoite
MEM             set     4+BUFFER        ; varattavan muistin koko

main            link    a4,#-34         ; varataan muuttujille tila pinosta
                move.l  a4,a1
                moveq   #7,d1
1$              clr.l   -(a1)           ; nollataan kaikki muuttujat pinossa
                dbf     d1,1$
                clr.w   -(a1)

                clr.b   -1(a0,d0.l)             ; nolla komentorivin loppuun
                move.l  a0,cmdlin(a4)           ; tallenn. kom.rivin osoite
                move.l  d0,cmdlen(a4)           ; tallenn. kom.rivin pituus

                lea     .DosName(pc),a1         ; dos-kirjaston nimi
                moveq   #0,d0                   ; mik„ tahansa versio kelpaa
                move.l  $4,a6                   ; execbase
                jsr     _LVOOpenLibrary(a6)     ; avataan dos.library
                move.l  d0,.DosBase(a4)         ; dosbase talteen
                beq     cleanup                 ; jos ei saatu auki, pois

                move.l  #MEM,d0                 ; varattavan muistin koko
                move.l  #MEMF_CLEAR!MEMF_PUBLIC,d1      ; ja tyyppi
                move.l  $4,a6                   ; execbase
                jsr     _LVOAllocMem(a6)        ; varataan muistia puskurille
                move.l  d0,mem(a4)              ; muistin osoite talteen
                beq     cleanup                 ; jos ei saatu, pois
                move.l  d0,a0
                move.l  #MEM,(a0)+              ; varatun muistin koko talteen
                move.l  a0,buffer(a4)           ; puskurin osoite talteen

                lea     .FinnslatorName(pc),a1  ; finnslator-kirjaston nimi
                moveq   #0,d0                   ; mik„ tahansa versio kelpaa
                jsr     _LVOOpenLibrary(a6)     ; avataan finnslator.library
                move.l  d0,.FinnslatorBase(a4)  ; perusosoite talteen
                beq     nofinn                  ; jos ei auennut, virhe

                moveq   #MP_SIZE,d0             ; tarvittavan portin koko
                bsr     createport              ; luodaan viestiportti
                move.l  d0,msgport(a4)          ; tallennetaan sen osoite
                beq     cleanup                 ; jos nolla, ei saatu porttia
                moveq   #NDI_SIZE,d0            ; tarvittavan iorequestin koko
                bsr     createio                ; luodaan IOReq-struktuuri
                move.l  d0,ioreq(a4)            ; sen osoite talteen
                beq     cleanup                 ; jos nolla, ei saatu luotua

                move.l  a0,a1                   ; ioreq:n osoite
                lea     channels(pc),a0         ; kanavamaskit
                move.l  a0,NDI_CHMASKS(a1)      ; IOReq:iin
                move.w  #4,NDI_NUMMASKS(a1)     ; maskien lukum„„r„
                clr.b   NDI_MOUTHS(a1)          ; ei tarvita suuinformaatiota
                lea     .NarratorName(pc),a0    ; narratorin nimi
                moveq   #0,d0                   ; unit=0
                moveq   #0,d1                   ; flags=0
                move.l  $4,a6                   ; execbase
                jsr     _LVOOpenDevice(a6)      ; avataan narrator.device
                tst.l   d0                      ; virhe?
                bne     nonarrator              ; jos, tulostetaan virheilmoitus
                st      narrator(a4)            ; lippu: narrator saatiin auki

                move.l  cmdlin(a4),a0           ; komentorivin osoite
                move.l  cmdlen(a4),d0           ; pituus
                move.l  buffer(a4),a1           ; „„nnepuskurin osoite
                move.l  #BUFFER,d1              ; ja koko
                move.l  .FinnslatorBase(a4),a6  ; finnslator-perusosoite
                jsr     _LVOTranslate(a6)       ; muunnetaan teksti „„nteiksi

                move.l  ioreq(a4),a1            ; IORequestin osoite
                move.l  buffer(a4),IO_DATA(a1)  ; asetetaan puskurin osoite
                move.l  #BUFFER,IO_LENGTH(a1)   ; ja pituus
                move.w  #CMD_WRITE,IO_COMMAND(a1)       ; komento = WRITE
                move.l  $4,a6                   ; execbase
                jsr     _LVODoIO(a6)            ; k„ynnistet„„n puhe
                bra     cleanup                 ; homma hanskassa -> pois

nonarrator      lea     .NarratorName(pc),a1    ; virhe: ei narratoria
                bra.s   err_out

nofinn          lea     .FinnslatorName(pc),a1  ; virhe: ei finnslatoria
err_out         lea     ermsg(pc),a0            ; yleinen virheilmoitus
                move.l  a1,d0                   ; vikineen nimi d0:aan
                bsr     dpymsg

cleanup         tst.b   narrator(a4)            ; narrator auki?
                beq.s   10$
                move.l  ioreq(a4),a1            ; joo, suljetaan se
                move.l  $4,a6
                jsr     _LVOCloseDevice(a6)
10$             move.l  msgport(a4),a0          ; vapautetaan portti
                bsr     deleteport
                move.l  ioreq(a4),a0            ; vapautetaan IORequest
                bsr     deleteio

                move.l  mem(a4),d0              ; muistia varattu?
                beq.s   11$
                move.l  d0,a1                   ; joo
                move.l  (a1),d0                 ; muistin koko
                move.l  $4,a6                   ; execbase
                jsr     _LVOFreeMem(a6)         ; vapautetaan muisti
11$             move.l  .FinnslatorBase(a4),d0  ; finnslator auki?
                beq.s   12$
                move.l  d0,a1                   ; joo
                move.l  $4,a6                   ; execbase
                jsr     _LVOCloseLibrary(a6)    ; suljetaan finnslator
12$             move.l  .DosBase(a4),d0         ; dos auki?
                beq.s   13$
                move.l  d0,a1                   ; joo
                move.l  $4,a6                   ; execbase
                jsr     _LVOCloseLibrary(a6)    ; suljetaan dos
13$             moveq   #0,d0                   ; virhekoodi = 0
                unlk    a4                      ; muuttujat pois pinosta
                rts                             ; paluu dossiin

createport      movem.l d2-d3/a2-a3,-(sp)       ; tulos: d0 = a0 = portin osoite
                addq.l  #4,d0                   ; tilaa portin koolle
                move.l  d0,d2                   ; varattava koko
                move.l  #MEMF_CLEAR!MEMF_PUBLIC,d1
                move.l  $4,a6
                jsr     _LVOAllocMem(a6)        ; varataan muisti
                move.l  d0,a2
                tst.l   d0
                beq     creaport1               ; ei muistia -> pois
                move.l  d2,(a2)+                ; portin koko talteen
                moveq.l #-1,d0                  ; mik„ tahansa sig.bitti kelpaa
                jsr     _LVOAllocSignal(a6)     ; varataan signaalibitti
                move.b  d0,MP_SIGBIT(a2)        ; tallennetaan bitin numero
                bmi.s   creaporte               ; bitti„ ei saatu -> pois
                sub.l   a1,a1
                jsr     _LVOFindTask(a6)        ; etsit„„n t„m„ taski
                move.l  d0,MP_SIGTASK(a2)       ; tallennetaan osoitin
                move.b  #NT_MSGPORT,LN_TYPE(a2) ; noden tyyppi = MsgPort
                move.b  #PA_SIGNAL,MP_FLAGS(a2) ; signaloidaan viestin saapuessa

                lea     MP_MSGLIST(a2),a0
                NEWLIST A0                      ; alustetaan portin viestilista
                move.l  a2,d0
                bra.s   creaport1               ; homma selv„
deleteport      movem.l d2-d3/a2-a3,-(sp)       ; a0 = portin osoite
                move.l  a0,d0
                beq.s   creaport1               ; nolla -> pois
                move.l  a0,a2
                moveq.l #0,d0
                move.b  MP_SIGBIT(a2),d0        ; signaalibitin numero
                bmi.s   creaporte               ; .mi -> ei bitti„ varattuna
                move.l  $4,a6
                jsr     _LVOFreeSignal(a6)      ; vapautetaan sigbit
creaporte       move.l  -(a2),d0                ; varatun muistin koko
                move.l  a2,a1
                move.l  $4,a6
                jsr     _LVOFreeMem(a6)         ; vapautetaan muisti
                moveq.l #0,d0
creaport1       movem.l (sp)+,d2-d3/a2-a3
                move.l  d0,a0
                rts

createio        movem.l d2/a2,-(sp)             ; d0=koko, a0=MsgPort; tulos: d0=ioreq
                move.l  a0,a2                   ; msgport* talteen
                addq.l  #4,d0                   ; tilaa stuktuurin koolle
                move.l  d0,d2
                move.l  #MEMF_PUBLIC!MEMF_CLEAR,d1
                move.l  $4,a6
                jsr     _LVOAllocMem(a6)        ; varataan muistia IORequestille
                move.l  d0,a0
                tst.l   d0
                beq.s   100$                    ; ei muistia -> pois
                move.l  d2,(a0)+                ; tallennetaan struktuurin koko
                move.l  a2,MN_REPLYPORT(a0)     ; portin osoite IORequestiin
                move.b  #NT_MESSAGE,LN_TYPE(a0) ; portin tyyppi
                subq.l  #4,d2
                move.w  d2,MN_LENGTH(a0)
                move.l  a0,d0                   ; palautetaan struktuurin osoite
100$            movem.l (sp)+,d2/a2
                rts

deleteio        move.l  a0,d0                   ; a0 = IoRequest
                beq.s   100$                    ; nolla -> ei tehd„ mit„„n
                move.l  a0,a1
                move.l  -(a1),d0                ; otetaan struktuurin koko
                move.l  $4,a6
                jsr     _LVOFreeMem(a6)         ; vapautetaan muisti
100$            rts

dpymsg          ;a0=fmstr, d0..d7=args
                movem.l d0-d7/a0-a3,-(sp)       ; rekisterit pinoon
                move.l  sp,a1                   ; osoitin datarekistereihin pinossa
                lea.l   putchar(pc),a2          ; putchar-rutiinin osoite
                move.l  buffer(a4),a3           ; puskurin osoite
                move.l  $4,a6
                jsr     _LVORawDoFmt(a6)        ; formatoidaan tulostus
                move.l  .DosBase(a4),a6
                jsr     _LVOOutput(a6)          ; tulostustiedoston filehandle
                move.l  d0,d1
                beq.s   201$                    ; jos nolla, ei voida tulostaa
                move.l  a3,d2
200$            tst.b   (a3)+                   ; lasketaan merkkijonon pituus
                bne.s   200$
                subq.w  #1,a3                   ; NULL-tavua ei lasketa
                move.l  a3,d3                   ; pituus d3:een
                sub.l   d2,d3
                jsr     _LVOWrite(a6)           ; tulostetaan puskurin sis„lt”
201$            movem.l (sp)+,d0-d7/a0-a3
                rts
putchar         move.b  d0,(a3)+                ; putchar-rutiini RawDoFmt:lle
                rts

channels        dc.b    3,6,5,10,12             ; audio.devicen kanavamaskit

.DosName        dc.b    'dos.library',0
.FinnslatorName dc.b    'finnslator.library',0
.NarratorName   dc.b    "narrator.device",0
ermsg           dc.b    "Unable to open %s.",LF,0
                ds.w    0

                end


