,ll 6.6
,cs 10
,pl 66
,lm 0.2,0.5
,pn 6
,ju
,hd
,ce
OmegaSoft 6809 Cross Pascal Language Handbook (V1.0)
,,
,ft

,ce 1
8-##
,,
,ce
OmegaSoft 6809 Cross Pascal Language Handbook (V1.0)
,ce
WRITING DEVICE DRIVERS

delline  equ     $18          
*
* descriptor offset for input device only
*
         abs     7            
*
p$break  rmb     1            break enable if true
p$pntr   rmb     2            buffer pointer
p$buf    rmb     128          buffer
*
         abs     $bf40        terminal port 2661 address
epcidata rmb     1            epci data register
epcistat rmb     1            epci status register
epcimode rmb     1            epci mode register
epcicom  rmb     1            epci control register
*
* queues for input and output of 2661
*
         varib                
inq_err  rmb     1            error flag for input from 2661
roff     rmb     1            receive buffer full
toff     rmb     1            transmit buffer hold
special  rmb     1            xon/xoff flag
inq_mode rmb     2            pointer to input descriptor
inq_in   rmb     2            input from 2661 input pointer
inq_out  rmb     2            input from 2661 output pointer
inq_max  rmb     2            end of input queue
inq_cnt  rmb     1            number of characters in input queue
outq_in  rmb     2            output to 2661 input pointer
outq_out rmb     2            output to 2661 output pointer
outq_max rmb     2            end of output queue
outq_cnt rmb     1            number of characters in output queue
inq      rmb     qsize        input from 2661 queue
outq     rmb     qsize        output to 2661 queue
*
         code                 
*
         xref    global       
         xdef    .input,.output,.keyboar,int2661 
*
* each entry point has room for 4 sub-entries
*
* + 0 - initialization
* + 3 - output
* + 6 - input
* + 9 - setup
*
* table for input
*
.input   lbra    inp_init     
         rts                  cannot due output function
         rmb     2            
         lbra    data_in      
         lbra    key_set      
*
inp_init pshs    y,x          
         ora     #m$in        open for input
         leay    <.input,pcr  driver address
         lbsr    ddset        setup descriptor
         leay    p$buf,x      
         sty     p$pntr,x     

         ldb     #cr          
         stb     0,y          
         ldy     global       
         stx     inq_mode,y   save address of desc.
         clr     p$break,x    assume break not enabled
         lda     p$mode,x     
         bita    #m$bk        
         beq     inp_1        
         anda    #$ff-m$bk    
         sta     p$mode,x     
         lda     #1           
         sta     p$break,x    set flag true
inp_1    equ     *            
         leax    inq,y        
         stx     inq_in,y     
         stx     inq_out,y    input queue is empty
         leax    qsize,x      
         stx     inq_max,y    limit of input queue
         clr     inq_cnt,y    
         clr     inq_err,y    no error yet
         clr     roff,y       
         puls    y,x,pc       
*
* table for output
*
.output  lbra    out_init     
         lbra    dat_out      
         rts                  can't do input function
         rmb     2            
         lbra    out_set      
*
out_init pshs    y,x          
         ora     #m$out       open for output
         leay    <.output,pcr driver address
         bsr     ddset        
         ldy     global       
         leax    outq,y       
         stx     outq_in,y    
         stx     outq_out,y   queue is empty
         leax    qsize,x      
         stx     outq_max,y   
         clr     outq_cnt,y   
         clr     toff,y       
         clr     special,y    
         lda     #reset       
         sta     epcicom      clear epci
         lda     #mode1a      
         sta     epcimode     mode register 1
         lda     #mode1b      
         sta     epcimode     mode register 2
         lda     epcidata     make sure receive empty
         lda     #mode2       
         sta     epcicom      enable receive interrupt
out_2    puls    y,x,pc       
*
* table for keyboard
*
.keyboar lbra    key_init     
         rts                  can't do output function
         rmb     2            
         lbra    data_in      
         lbra    key_set      

key_init pshs    y,x          
         ora     #m$in        open for input
         leay    <.keyboar,pcr driver address
         bsr     ddset        
         puls    y,x,pc       
*
ddset    sta     p$mode,x     
         clr     p$err,x      
         sty     p$drv,x      
         ldy     #1           
         sty     p$elnt,x     
         rts                  
*
* transfer data to device
*
dat_out  pshs    y,x,d        
         ldy     global       
         tsta                 see if writeln
         bmi     txto3        if string write
         beq     txto1        nope
         lda     #cr          
         bsr     outch        
         lda     #lf          
         bra     txto5        
txto1    equ     *            
         lda     p$elmt,x     
txto5    bsr     outch        
txto4    puls    y,x,d,pc     
txto3    equ     *            
         leax    1,u          
         bra     txto3a       
txto3b   lda     0,x+         
         bsr     outch        
txto3a   decb                 
         bpl     txto3b       
         bra     txto4        
*
* put one character in output queue
*
outch    pshs    x,b          
outch0   ldb     outq_cnt,y   
         cmpb    #110         
         bhi     outch0       too full
         pshs    cc           
         orcc    #$10         disable interrupts
         ldx     outq_in,y    
         leax    1,x          
         cmpx    outq_max,y   
         blo     outch1       
         leax    outq,y       past buffer, back to beginning
outch1   pshs    x            
         ldx     outq_in,y    
         sta     0,x          
         puls    x            
         stx     outq_in,y    update pointer
         inc     outq_cnt,y   
         tst     toff,y
         bne     outch3       keep blocked until released
         ldb     #mode3       
         stb     epcicom      
outch3   puls    cc           restore interrupts
outch2   puls    x,b,pc       

*
* transfer data from device
*
data_in  pshs    y,x,d        
         ldy     global       
         ldb     p$mode,x     
         andb    #$ff-m$eof-m$eoln clear flags
         orb     #m$val       set to valid
         stb     p$mode,x     
         bitb    #m$text      
         bne     txti         use text input
         lbsr    inch         get character
         lbcs    inerr        
         sta     p$elmt,x     
         bra     txti7        
txti     ldy     p$pntr,x     get buffer pointer
         lda     0,y+         
         cmpa    #cr          
         beq     txti4        need new buffer
txti5    lda     0,y          get new character
         sta     p$elmt,x     
         sty     p$pntr,x     update registers
         cmpa    #cr          
         beq     txti6        set eoln flag
txti7    clr     p$err,x      
         puls    y,x,d,pc     
txti6    orb     #m$eoln      
         stb     p$mode,x     
         lda     #space       
         sta     p$elmt,x     return space to user
         bra     txti7        
txti4    leay    p$buf,x      
         sty     p$pntr,x     reset pointers
         clrb                 character counter
         leax    0,y          
         ldy     global       
txti10   bsr     inch         
         bcs     inerr        
         cmpa    #back        
         beq     txti10a      
         cmpa    #del         
         bne     txti11       
txti10a  lda     #1           
txti12   tstb                 
         beq     txti10       nothing to back out
         tsta                 
         beq     txti10       count
         pshs    a            
         lda     #back        
         lbsr    outch        
         lda     #space       
         lbsr    outch        
         lda     #back        
         lbsr    outch        
         puls    a            
         leax    -1,x         move pointer back
         decb                 decrement character count
         deca                 backup counter
         bra     txti12       
txti11   cmpa    #delline     
         bne     txti13       
         tfr     b,a          remove all characters

         bra     txti12       
txti13   cmpa    #cr          see if end of line
         beq     txti14       yes
         cmpb    #127         
         bhs     txti10       cannot accept more characters
         sta     0,x+         put in buffer
         incb                 bump counter
         lbsr    outch        echo
         bra     txti10       
txti14   sta     0,x+         
         lbsr    outch        send cr
         lda     #lf          
         lbsr    outch        send lf
         ldx     2,s          get descriptor back
         ldy     p$pntr,x     start of buffer
         ldb     p$mode,x     
         bra     txti5        go for more
inerr    lda     inq_err,y    
         ldx     2,s          
         sta     p$err,x      put in error
         clr     inq_err,y    acknowledge error
         puls    y,x,d,pc     
*
* get one character from queue
*
inch     pshs    x,b          
inch0    ldb     inq_err,y    
         bne     inch2        
         tst     inq_cnt,y    
         beq     inch0        
         pshs    cc           
         orcc    #$10         disable interrupts
         tst     roff,y       
         beq     inch3        
         ldb     inq_cnt,y    
         cmpb    #50          see if empty enough
         bhi     inch3        
         clr     roff,y       
         ldb     #$11         
         stb     special,y    tell other end to go ahead
         ldb     #mode3
         stb     epcicom      make sure can send this
inch3    ldx     inq_out,y    
         lda     0,x+         get character
         cmpx    inq_max,y    
         blo     inch1        
         leax    inq,y        move to start of queue
inch1    stx     inq_out,y    update pointer
         dec     inq_cnt,y    
         puls    cc           
         andcc   #$fe         no error
         puls    x,b,pc       
inch2    orcc    #1           error 
         puls    x,b,pc       
*
* output status handler
* return true if output queue empty
*
out_set  pshs    y            
         ldy     global       
         cmpa    #st$stat     
         bne     outs2        

         clrb                 
         tst     outq_cnt,y   
         bne     key1         
         ldb     #1           
         bra     key1         
outs2    puls    y,pc         
*
* keyboard status handler
* return true if a character in queue
*
key_set  pshs    y            
         ldy     global       
         cmpa    #st$stat     
         bne     key2         
         clrb                 
         tst     inq_cnt,y    
         beq     key1         
         ldb     #1           
key1     stb     [0,s]        
key2     puls    y,pc         
*
* interrupt handler for 2661
*
int2661  ldy     global       
int0     ldb     epcistat     
         bitb    #2           
         bne     int1         receive data register full
*
* transmit register empty
*
         tst     special,y    
         bne     int6a        put in special ahead of other stuff
         tst     toff,y       
         bne     int6         
         tst     outq_cnt,y   
         beq     int6         empty
         ldx     outq_out,y   
         lda     0,x+         
         sta     epcidata     get character
         cmpx    outq_max,y   
         blo     int7         
         leax    outq,y       move to start of queue
int7     stx     outq_out,y   update pointer
         dec     outq_cnt,y   
         lbra    intexit      
int6     ldb     #mode2       
         stb     epcicom      disable xmit interrupt
         lbra    intexit      
int6a    lda     special,y    
         sta     epcidata     
         clr     special,y    
         bra     intexit      
*
* receive register full
*
int1     lda     epcidata     clear interrupt
         anda    #$7f         clear msb
         andb    #%00110000   
         bne     int2         error
         cmpa    #break       see if break
         beq     int4         
         cmpa    #lf          

         beq     intexit      ignore line feeds
         cmpa    #$13         
         beq     int15        disable xmitter
         cmpa    #$11         
         beq     int16        enable xmitter
         ldb     inq_cnt,y    
         cmpb    #110         
         blo     int14        
         tst     roff,y       
         bne     int14        already off
         inc     roff,y       is stopped
         ldb     #$13         
         stb     special,y    
         ldb     #mode3       
         stb     epcicom      
int14    ldx     inq_in,y     
         leax    1,x          
         cmpx    inq_max,y    
         blo     int3         
         leax    inq,y        past buffer, back to beginning
int3     pshs    x            
         ldx     inq_in,y     
         sta     0,x          put into queue
         puls    x            
         stx     inq_in,y     update pointer
         inc     inq_cnt,y    
         bra     intexit      
int2     ldb     #readerr     
         stb     inq_err,y    flag error
         bra     intexit      
int4     ldx     inq_mode,y   get descriptor
         ldb     p$mode,x     
         orb     #m$bk        
         stb     p$mode,x     
intexit  rti                  
int15    ldb     #1           
         stb     toff,y       disable output
         bra     intexit      
int16    clr     toff,y       
         ldb     #mode3       
         stb     epcicom      re-enable interrupts
         bra     intexit      
         end                  

The stack setup file was (extest.ps) :

.start   idnt    0,5          
         xdef    start,global 
         xref    varibend,extest 
global   equ     $A000        
start    lds     #$BC00       set system stack
         leau    -$00F6-varibend,s set data stack
         leay    10,u         set global stack mark
         sty     global       
         leax    varibend,y   
         stx     -4,y         set system stack limit
         sty     -6,y         set global mark pointer
         clr     -7,y         disable errors
         stu     0,y          set heap limit
         ldx     #$A002       
         stx     2,y          set heap start
         clr     4,y          no conversion error yet

         lbsr    extest       
         bra     start        
         end     start        

This reflects global stack mark being stored at location $a000, the heap starting at location $a002, and the top of RAM being at $bc00. $100 bytes were allocated to the system stack.

The error driver simple inhibits interrupts and restarts the program :

exsd2    idnt    1,1          runtime error printing device
*
         xdef    .error       
*
.error   orcc    #$50         
         jmp     [$fffe]      
         end                  

The end of program marker (exse1) simply has a equate for each section :

se1      idnt    1,1          end of program locator
*
         xdef    finish,dataend,varibend 
*
finish   equ     *            
         data                 
dataend  equ     *            
         varib                
varibend equ     *            
         end                  

The test program is very simple :

program extest (input, keyboard, output) ;
  var
    s : string ;
    ch : char ;
    
  begin
    ! andcc #$ef ;
    writeln ;
    writeln ('Enter lines, they repeat until you type "stop"') ;
    repeat
      readln (s) ;
      writeln (s)
    until s = 'stop' ;
    writeln ('Enter characters, their hex value will be shown') ;
    writeln ('Terminates when you type a "@"') ;
    repeat
      read (keyboard, ch) ;
      writeln (hex(ch))
    until ch = '@' ;
    writeln ('I will now go into an infinate loop') ;
    repeat until false
  end.

An I/O library for the GESSBS-4 was created after assembling exdrive, exsd2, and exse1 using the librarian :

lb exio exdrive exsd2 exse1

The lib linker command was :

lib xrl exio

The compiler that you use with this driver should be patched to allocate the correct amount of stack space for the input, output, and keyboard descriptors. Refer to chapter 2 for the locations in the compiler for this operation. The example input descriptor needs hex $8a bytes, the keyboard and output require 7 bytes.

I hope this example will make device drivers a bit less mysterious.
