;+ ; ; E11 loadable module for accessing private extended memory from FORTRAN. ; ; By John Wilson . ; ; Copyright (C) 1999-2008 by Digby's Bitpile, Inc. All rights reserved. ; ; 10/07/1999 JMBW Created (from sample E11 DLL). ; 01/16/2000 JMBW Modified to just handle a memory buffer, no interrupts ; or anything fancy like that. ; 01/20/2000 JMBW Added IDATA autoincrementing data port. ; 01/18/2002 JMBW Debugged WEP now that it's really called on exit. ; 12/31/2006 JMBW 32-bit version. ; 09/04/2008 JMBW Fixed DATO parameter order. ; ;- .386 .model flat .code ; extrn _GetCSRBlock@20:near,_RetCSRBlock@4:near extrn _GetMemory@4:near,_RetMemory@4:near ; csr= 17777100o ;base CSR address in PDP-11 space memsiz= 8d*1048576d ;size of extended memory block ; DLL_PROCESS_ATTACH=1 ;library is newly loaded DLL_PROCESS_DETACH=0 ;bed time ; .assume macro cond if &cond else .err Assumption &cond is false endif endm ;+ ; ; Init/shutdown entry point. ; BOOL DllMain(HINSTANCE hInstDLL,DWORD fdwReason,LPVOID lpvReserved) ; ;- start: mov eax,[esp+04h+04h] ;get fdwReason dec eax ;newly loaded? .assume jnz short init2 ;no ; set up CSR handler ;;; lpvReserved points at counted command line string ;;; should parse "CSR=xxxxxx" and/or "SIZE=xxxx" instead of hard-coding those ; GetCSRBlock(ulong iobase,ulong nwords,uint (*dati)(),void (*dato)(), ; void (*init)() push offset init ;INIT routine push offset dato ;DATO routine push offset dati ;DATI routine push 4 ;4 registers push csr ;base I/O address call _GetCSRBlock@20 ;alloc block of CSR addresses test eax,eax ;success? jz short init4 ;no mov ds:csrhnd,eax ;save handle push memsiz ;size of memory block call _GetMemory@4 ;allocate and zero memory test eax,eax ;success? jz short init3 ;no, give up mov ds:mem,eax ;save it init1: mov eax,-1 ;success ret 3*4 ;EAX=0 if failed, NZ if succeeded init2: inc eax ;unloading? .assume jnz short init1 ;no, return success for others (no op) push dword ptr ds:mem ;memory block call _RetMemory@4 ;return it init3: push dword ptr ds:csrhnd ;CSR block handle call _RetCSRBlock@4 ;flush it init4: xor eax,eax ;error return ret 3*4 ; dati: ; handle DATI cycles (register reads) ; dati(uint32 addr) push ebx ;save mov ebx,[esp+04h+04h] ;get address sub ebx,csr ;subtract base addr and bl,not 1 ;force even call dword ptr ds:input[ebx+ebx] ;handle it (preserve EBP/ESI/EDI) pop ebx ;restore ret 4 ; dato: ; handle DATO(B) cycles (register writes) ; (uint32 addr, uint32 value, uint32 datob) push ebx ;save mov ebx,[esp+04h+04h] ;get address mov edx,ebx ;copy sub ebx,csr ;subtract base addr and bl,not 1 ;force even mov eax,[esp+04h+04h+04h] ;get data mov ecx,[esp+04h+04h+08h] ;DATOB flag call dword ptr ds:output[ebx+ebx] ;handle it (preserve EBP/ESI/EDI) ;AX=data written, ECX=DATOB flag, EDX=address pop ebx ;restore ret 3*4 ; init: ; handle bus init (RESET instruction) ; (uint32 addr) xor eax,eax ;load 0 mov ds:addrs,eax ;clear addr ports ret 4 ;+ ; ; +00 data port ; ; 15 0 ; +------------+ ; | DATA | ; +------------+ ; ; DATA RW One-word window to word of extended memory addressed by ALOW ; and AHIGH. Byte accesses are OK and read/write only that ; particular byte. If ALOW/AHIGH select a byte or word that's ; beyond the end of the extended memory block, writes to DATA are ; ignored and reads from DATA return 0. ; ;- datai: ; input from data port mov ebx,ds:addrs ;get pointer into memory xor eax,eax ;load 0 in case NXM cmp ebx,memsiz ;off end of memory? jae short datai1 ;yes add ebx,ds:mem ;add base of block movzx eax,word ptr [ebx] ;fetch word at addressed location datai1: ret ; datao: ; output to data port mov ebx,ds:addrs ;get pointer into memory cmp ebx,memsiz ;off end of memory? (MEMSIZ assumed even) jae short datao3 ;yes, ignore the write add ebx,ds:mem ;add base of block jecxz short datao2 ;DATO, easy test dl,1 ;DATOB, to high byte? jz short datao1 mov [ebx+1],ah ;yes, save ret datao1: mov [ebx],al ;no, low byte ret datao2: mov [ebx],ax ;store a word datao3: ret ;+ ; ; +02 autoincrementing data port ; ; 15 0 ; +-------------+ ; | IDATA | ; +-------------+ ; ; IDATA RW One-word window to word of extended memory addressed by ALOW ; and AHIGH. AHIGH'ALOW are incremented (as a single 32-bit ; quantity, the LSB is always 0) by 2 after the access. Byte ; accesses are OK and read/write only that particular byte, just ; like the DATA register, but the resulting autoincrement ; probably won't be what you want. If ALOW/AHIGH select a byte ; or word that's beyond the end of the extended memory block, ; writes to DATA are ignored and reads from DATA return 0, and ; AHIGH'ALOW aren't incremented. ; ;- idati: ; input from autoincrementing data port mov ebx,ds:addrs ;get pointer into memory xor eax,eax ;load 0 in case NXM cmp ebx,memsiz ;off end of memory? jae short idati1 ;yes add ebx,ds:mem ;add base of block movzx eax,word ptr [ebx] ;fetch word at addressed location add dword ptr ds:addrs,2 ;increment address idati1: ret ; idato: ; output to data port mov ebx,ds:addrs ;get pointer into memory cmp ebx,memsiz ;off end of memory? (MEMSIZ assumed even) jae short idato4 ;yes, ignore the write add ebx,ds:mem ;add base of block jecxz short idato2 ;DATO, easy test dl,1 ;DATOB, to high byte? jz short idato1 mov [ebx+1],ah ;yes, save jmp short idato3 idato1: mov [ebx],al ;no, low byte jmp short idato3 idato2: mov [ebx],ax ;store a word idato3: add dword ptr ds:addrs,2 ;increment address idato4: ret ;+ ; ; +04 low word of address ; ; 15 1 0 ; +------------+-+ ; | ALOW |/| ; +------------+-+ ; ; ALOW RW Low 16 bits (bit 0 masked off) of extended memory address. ; ;- alowi: mov eax,ds:addrs ;fetch value (junk in LH) ret alowo: and al,not 1 ;mask off low bit mov word ptr ds:addrs,ax ;save low word of value ret ;+ ; ; +06 high word of address ; ; 15 0 ; +-------------+ ; | AHIGH | ; +-------------+ ; ; AHIGH RW High 16 bits of extended memory address. ; ;- ahighi: movzx eax,word ptr ds:addrs+2 ;fetch value ret ahigho: mov word ptr ds:addrs+2,ax ;save high word of value ret ; .data ; ; Register dispatch table: input dd datai,idati,alowi,ahighi output dd datao,idato,alowo,ahigho ; addrs dd 0 ;extended address (forced even) ; .data? ; csrhnd dd 1 dup(?) ;handle from GetCSRBlock for our CSRs mem dd 1 dup(?) ;address of our memory ; end start