RS232 Routines for MicroBee :)

Discussion about other targets
Post Reply
tschak909
Well known member
Posts: 171
Joined: Sun Sep 09, 2018 5:44 pm

RS232 Routines for MicroBee :)

Post by tschak909 »

I got this from the guy currently running MicroBee:

Code: Select all

;************************************************************************
;**                                                                       **
;**                Simple terminal for the microbee.                      **
;**                (or how to use the rs232 routines)                     **
;**                                                                       **
;*******************************************************(C)EJW****19/7/89
;        the program initialises itself for 1200 baud, if 2400 or 
;        4800 baud are required, call the relevant init subroutines
;        (init_2400 and init_4800)
;        It is set to 8 data bits , no parity 
        .z80

        aseg

        org        0100h

bdos        equ        5

;initialise program bits....
        call        look_col
        call        cls                ;clear the screen
        call        rs_init                ;initialise the rs232 queue and interupts ..
        call        init_screen        ;sign on and select baud rate

term_loop:
        
        call        rs_in                ;see if any data available at rs232 input queue
        jr        nz,nochar        ;nz means no char available

        call        conout                ;give character to screen 
nochar:        call        conin                ;look for char from keyboard
        jr        z,nokey                ;z means no key available

        call        rs8_out                ;give char (in A) to rs232 output.
nokey:        jr        term_loop        ;jump back to start the terminal loop again

look_col:
        ld        a,64
        out        (8),a
        ld        hl,0f800h
        ld        a,(hl)
        ld        (col_sto),a
        ld        a,0
        out        (8),a
        ret                        ;this saves current color for use in term.


cls:        ld        a,26
        call        conout                ;clear screen and home cursor
        ret

conin:        push        bc
        push        de
        push        hl
        ld        e,255
        ld        c,6                ;BDOS function 6 direct console I/O
        call        bdos
        pop        hl
        pop        de
        pop        bc
        cp        0
        ret

conout:        push        af
        push        bc
        push        de
        push        hl
        ld        e,a
        ld        c,2                ;BDOS function 2 screen output
        call        bdos
        pop        hl
        pop        de
        pop        bc
        pop        af
        ret
        


init_screen:
        ld        a,64
        out        (8),a
        ld        hl,0f800h
        ld        de,0f801h
        ld        bc,1919
        ld        a,15
        ld        (hl),a
        ldir                        ;set color to white on grey
        ld        a,0
        out        (8),a
        ld        a,10
        ld        b,6
downlp:        call        conout
        djnz        downlp
        call        spaceout
        ld        hl,mess1
        call        prnmes
        ld        hl,mess2
        call        prnmes
        ld        hl,mess3
        call        prnmes
        ld        hl,mess4
        call        prnmes
        ld        hl,mess5
        call        prnmes
        ld        hl,mess6
        call        prnmes
        ld        hl,mess1
        call        prnmes
        ld        hl,l1200
        ld        (simult),hl        ;initialise for 1200/2400
wait_lp:
        call        conin         
        jr        z,wait_lp
        cp        '1'
        jp        z,go_term_loop
        cp        '2'
        jp        z,init_2400
        cp        '3'
        jp        z,init_4800
        cp        27
        jp        z,wboot
        jp        wait_lp
                

wboot:        call        cls
        ld        c,0
        jp        bdos


spaceout:
        ld        a,32
        ld        b,16
space_loop:
        call        conout
        djnz        space_loop
        ret


init_2400:
        ld        a,13
        ld        (brpat),a        ;set l1200 to 2400 baud
        ld        hl,1*256+33        ;change delay for rec routine
        ld        (semi_del),hl
        ld        hl,1*256+85
        ld        (full_del),hl
        jp        go_term_loop

init_4800:
        ld        hl,1*256+15
        ld        (semi_del),hl
        ld        hl,1*256+42
        ld        (full_del),hl
        ld        hl,l4800
        ld        (simult),hl
        jp        go_term_loop


go_term_loop:
        call        cls
        ld        a,64
        out        (8),a
        ld        hl,0f800h
        ld        de,0f801h
        ld        bc,1919
        ld        a,(col_sto)
        ld        (hl),a
        ldir                        ;restore original color
        ld        a,0
        out        (8),a
        jp        term_loop

                
        

prnmes:
        ld        a,27
        call        conout
        ld        a,')'
        call        conout
        ld        b,32
prnlp:        ld        a,(hl)
        call        conout
        inc        hl
        djnz        prnlp
        ld        a,27
        call        conout
        ld        a,'('
        call        conout
        ld        a,10
        call        conout
        ld        a,13
        call        conout
        call        spaceout
        ret
        


;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;::                 R S - 2 3 2    R O U T I N E S                        ::
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

;These routines implement full-duplex communication.

nstrt        equ        1        ;number of start bits (always 1)
ndata          equ        8        ;number of data bits (7 or 8)
npar        equ        0        ;number of parity bits
par_typ        equ        1        ;parity type (1=none,2=odd,3=even)
nstop        equ        1        ;number of stop bits
baud_rt        equ        1        ;baud rate (1=1200,2=2400,3=4800)

;Bits of interest on PIO B data port
cass_in         equ        0
cass_out equ        1
ser_clk         equ        2
ser_cts         equ        3
ser_in         equ        4
ser_out         equ        5
spker         equ        6
net_bit         equ        7
piob_data        equ        2
piob_ctl        equ        3
q_start                equ        0a000h
q_size                equ        01000h
piob_vec        equ        0df4ah
vwait_off        equ        9                

;Disk version has bit 7 as output for network
norm_mask equ        (1 shl cass_in) or (1 shl ser_cts) or (1 shl ser_in)

;Character to use when received parity is illegal
par_nok         equ        7fh

;Equates from the master program
;q_start        start of RS-232 queue storage
;q_size                RS-232 queue size

;**************************************************
;**     Output a character to the RS-232 port    **
;**************************************************

RS8_out:
;Output a character to the RS-232 port
        push        af                ;save regs
        push        bc
        push        de
        push        hl
        push        ix
        exx
        push        af
        push        bc
        push        de
        exx

        ld        l,0                ;start bit
        ld        b,8                ;number of data bits
;        res        7,a                ;kill top bit of character to send
eight8:        rrca                        ;shift lsb of char into C (parity remains same)
        adc        hl,hl                ;now put into lsb of HL
        djnz        eight8                ;and loop for number of valid data bits

;        or        a                ;set P flag (and clear C)
;        jp        pe,send_par8        ;if parity is even already, jump
;        scf                        ;set C to one for new parity
send_par8:
;        adc        hl,hl                ;install the parity bit

        ld        b,13-nstrt-ndata-npar ;get starting bit position
align8:        scf                        ;fill up rest of image with ones
        adc        hl,hl
        djnz        align8

        ld        d,nstrt+ndata+npar+nstop
                                ;total number of bits to transmit
        ld        e,4                ;number of loops between bits
        exx
        ld        de,0                ;not receiving at the moment
        exx

        in        a,(piob_data)        ;get current data of port
        ld        b,a                ;and save
        res        ser_out,b        ;set RS-232 output high (spacing)
;        set        3,b                ;so automodem (hayes ) can transmit
        ld        ix,(simult)        ;address of timing routine

        out        (vwait_off),a        ;stop video waiting

        di                        ;no interrupts at this point
        call        jp_sim                ;do the output/input
        ei                        ;interrupts can occur now

;        call        key_update        ;and scan the keyboard
;        xor        a                ;clear eol counter as most keypresses
;        ld        (eol_cnt),a        ;cause lots of characters to come back

        exx
        pop        de
        pop        bc
        pop        af
        exx        
        pop        ix
        pop        hl
        pop        de
        pop        bc
        pop        af
        ret

jp_sim:        jp        (ix)

l1200:
;1200 baud output routine
        call        txrx12                ;input/send a bit

;*********************************
        db        03eh
brpat:        db        34                ;ld        a,34                ;adjusted for no rx
l12001:        dec        a
        jr        nz,l12001

        or        a                ;4        
        or        a                ;4
        ld        a,0                ;7
        ld        a,0                ;7

;************************************************
;34 T-cycles
        ld        a,d                ;4        get number of transmitted bits to go
        or        e                ;4
        exx                        ;4
        or        d                ;4
        or        e                ;4
        exx                        ;4
        jp        nz,l1200        ;10        if not zero, jump
        ret

l4800:
        call        txrx12        
        ld        a,d
        ld        a,d
        ld        a,d
        ld        a,d
        ld        a,d
        ld        a,d
;************************************************
;34 T-cycles
        ld        a,d                ;4        get number of transmitted bits to go
        or        e                ;4
        exx                        ;4
        or        d                ;4
        or        e                ;4
        exx                        ;4
        jr        nz,l4800        ;7        if not zero, jump
        ret



txrx12:
;353 t-cycles
;Transmit section
        ld        a,d                ;4        finished transmitting?
        or        e                ;4
        jr        z,ndly1_hay                ;        jump if we have
                                ;7
        ld        a,e                ;4        ready to send a bit?
        or        a                ;4
        jr        nz,ndly2_hay        ;        jump if not
                                ;7
        add        hl,hl                ;11        shift transmit image by one bit
        ld        a,h                ;4        create PIO data
        and        1 shl ser_out        ;7
        or        b                ;4
        out        (piob_data),a        ;11        change the output bit
        dec        d                ;4        dec number of bits transmitted
        ld        e,3                ;7
nret1_hay:
;        dec        e                ;4        dec counter for time between bits
        ret
;Receive section
        exx                        ;4        switch to regs for receive
        ld        a,d                ;4        receive in progress?
        or        e                ;4
        jp        z,start_det_hay        ;        if not, look for a start bit
                                ;7
        ld        a,e                ;4        time to recive a bit?
        or        a                ;4
        jp        nz,ndly3_hay        ;        jump if not
                                ;7
        in        a,(piob_data)        ;11        input the bit
        and        1 shl ser_in        ;7
        sub        1                ;7
        rr        c                ;8
        dec        d                ;4        dec number of bits to receive
        ld        e,4                ;7
        jp        nz,ndly4_hay        ;        jump if not end of received char
                                ;7
        call        stor_rs                ;147        store char in queue
        ld        de,0*100h+3        ;10        wait for end of character
        ld        a,0                ;7
        or        a                ;4
nret3_hay:
        dec        e                ;4        dec counter for time between bits
        exx                        ;4        switch regs back
        ret                        ;10

start_det_hay:
;start bit detection
;259 t-cycles
        in        a,(piob_data)        ;11
        bit        ser_in,a        ;8
        jr        z,mark_hay                ;        jump if no start bit
                                ;7
        ld        de,9*100h+1        ;10        set number of bits to receive
                                ;        (start + data + parity- start bit gets
                                ;        dumped ) 
        ld        a,0                ;7
nretm_hay:        
        ld        a,5                ;7
startb1_hay:
        bit        0,(ix+1)        ;20*5=100
        dec        a                ;4*5=20
        jr        nz,startb1_hay        ;12*4+7=55
        bit        0,(ix+1)        ;20
        exx                        ;4
        ret                        ;10
        
mark_hay:
                                ;12
        jp        nretm_hay                ;12

ndly1_hay:
;70 t-cycles
                                ;12
        ld        a,0                ;7
        ld        a,0                ;7
        ld        a,0                ;7
        ld        a,0                ;7
        ld        a,0                ;7
        ld        a,0                ;7
        or        a                ;4
        or        a
        jp        nret1_hay        ;12

ndly2_hay:
;55 t-cycles
                                ;12
        or        a                ;4
        or        a                ;4
        or        a                ;4
        or        a                ;4
        or        a                ;4
        or        a                ;4
        dec        e                ;4
        ld        a,0                ;7
        jp        nret1_hay        ;12

ndly3_hay:
;226 t-cycles
                                ;12
        ld        a,5                ;7
ndly31_hay:
        bit        0,(ix+1)        ;20*5=100
        dec        a                ;4*5=20
        jr        nz,ndly31_hay        ;12*4+7=55
        bit        0,(ix+1)        ;20
        jp        nret3_hay        ;12

ndly4_hay:
;175 t-cycles
                                ;12
        ld        a,4                ;7
ndly41_hay:
        bit        0,(ix+1)        ;20*4=80
        dec        a                ;4*4=16
        jr        nz,ndly41_hay        ;12*4+7=43
        ld        a,0                ;7
        jp        nret3_hay        ;10



;**********************************************************
;**    Get the next character out of the RS-232 queue    **
;**********************************************************
; return char in A and Z, or NZ if no char available from q
RS_in:
        call        RS_inst                ;get the RS-232 input port status
        ret        nz                ;return if not avail
        push        de
        push        hl
        di
        ld        hl,(r_ptr)        ;get pointer out of queue
        xor        a                ;set Z
        ld        e,(hl)                ;get the character
        inc        hl
        ld        a,h
        and        0fh
        or        0f0h and high q_start
        ld        h,a
        ld        (r_ptr),hl
        ei
;        ld        a,e
;        or        a                ;see if parity is valid
;        jp        pe,parity_ok        ;jump if is OK
;        ld        e,par_nok+80h        ;else get illegal parity char + flag
parity_ok:
;        res        7,e                ;kill parity bit
        xor        a
        ld        a,e
        pop        hl
        pop        de
        ret

RS_inst:
;Return NZ if if no character available, or Z if avail
        push        de                ;save regs
        push        hl
        di
        ld        de,(w_ptr)        ;get pointer into the queue
        ld        hl,(r_ptr)        ;get pointer out of queue
        or        a
        sbc        hl,de                ;see if pointing to same byte
        ld        a,0                ;if not the same, we have to return Z
        jr        nz,RS_ex        ;if this is so, jump
        dec        a                ;if the same, return NZ
RS_ex:
        or        a
        ei
        pop        hl                ;else return
        pop        de
        ret

;********************************************
;**    RS-232 receive interrupt routine    **
;********************************************
;interrupt routine which receives an asynchronous character.
;Rotate in only the number of actual data bits,
;if there is a parity bit specified, then wait one bit time
;extra using full_del
;(if this is a false alarm, then ignore it)
int_rtn:
        out        (vwait_off),a        ;kill wait states IMMEDIATELY!!!!
        push        af                ;and all the regs
        push        bc
        push        de
        push        hl

        in        a,(piob_data)        ;get the data
        and        1 shl ser_in
        jr        z,abort                ;if a false alarm (??), ignore it

;Adjust semi_del appropriately to give exactly one half bit time
        ld        hl,(semi_del)        ;wait for half a bit time
llp1:        dec        l
        jr        nz,llp1
        dec        h
        jr        nz,llp1

        ld        e,8                ;get number of data bits + parity into E
data_lp:
;Adjust full_del to give exactly one bit time
        ld        hl,(full_del)        ;get full bit delay time
llp2:        dec        l
        jr        nz,llp2
        dec        h
        jr        nz,llp2

        in        a,(piob_data)        ;get the data
        and        1 shl ser_in
        sub        1
        rr        c                ;into C
        dec        e                ;dec number of bits
        jr        nz,data_lp        ;loop till we get the lot

        ld        hl,(full_del)        ;delay for a full bit time for parity bit
llp3:        dec        l
        jr        nz,llp3
        dec        h
        jr        nz,llp3

        call        stor_rs                ;store char in C in queue
        xor        a                ;and clear EOL counter
        ld        (eol_cnt),a
abort:
        pop        hl
        pop        de
        pop        bc
        pop        af
        ei
noint:
        reti

stor_rs:
;given char to save in c, store it on the queue
;(all paths take equal time - 147 t-cycles)
        ld        hl,(w_ptr)        ;16        get pointer into the queue
        ld        (hl),c                ;7        put the character onto the queue
        ld        de,(r_ptr)        ;20        get pointer out of the queue
        inc        hl                ;6
        ld        a,h                ;4
        and        0fh                ;7
        or        0f0h and high q_start        ;7
        ld        h,a                ;4
        or         a                ;7
        push        hl                ;11
        sbc        hl,de                ;15        see if the same
        pop        hl                ;10
        jr        z,stor_rs1        ;        jump if they are
                                ;7
        ld        (w_ptr),hl        ;16        and re-save it
        ret                         ;10        and return

stor_rs1:
                                ;12
        ld        a,b                ;4
        ld        a,0                ;7
        ret                        ;10



dly_milli:
;Delay DE milliseconds
        push        bc
dly_lp:
        ld        b,0
        djnz        $
        dec        de
        ld        a,d
        or        e
        jr        nz,dly_lp
        pop        bc
        ret



rs_init:
;Initialize for the RS-232 routines
        di                        ;no interrupts

        call        disk_type
        jr        z,k56_1

        ld        a,4                ;get PIO B interrupt vector address
        rst        28h
        inc        hl
        inc        hl
        ld        e,(hl)                ;get old vector
        inc        hl
        ld        d,(hl)
        ld        (old_vec),de        ;save old vector
        ld        de,int_rtn        ;now install the new vector
        ld        (hl),d
        dec        hl
        ld        (hl),e
        jr        k128_1

k56_1:        ld        hl,(piob_vec)        ;get current vector
        ld        (old_vec),hl        ;save it
        ld        hl,int_rtn        ;get new vector
        ld        (piob_vec),hl        ;and install it

k128_1:
        call        noint                ;do a RETI

        call        disk_type
        jr        z,k56_2
        ld        a,l
        jr        k128_2

k56_2:
        ld        a,low piob_vec        ;interrupt vector
k128_2:
        out        (piob_ctl),a

        ld        a,10110111b        ;wait for a 1,enable ints and mask follows
        out        (piob_ctl),a

        ld        a,not (1 shl ser_in)        ;interrupt mask
        out        (piob_ctl),a

;Initialize the RS-232 queue
        ld        hl,q_start
        ld        (r_ptr),hl
        ld        (w_ptr),hl

        ld        hl,1*256+65
        ld        (semi_del),hl
        ld        hl,1*256+171
        ld        (full_del),hl

        ld        hl,l1200                        ;address of the routine
        ld        (simult),hl

        ei
        ret
disk_type:
;Return Z if on CIAB/56k/workstation else return NZ
        ld        a,(2)
        cp        0d6h
        ret


simult:                ds        2
w_ptr:                ds        2
r_ptr:                ds        2
old_vec:        ds        2
eol_cnt:        ds        1
full_del:        ds        2
semi_del:        ds        2

col_sto:        db        0

mess1:        db        '                                '
mess2:        db        '   Microbee Simple Terminal.    '
mess3:        db        '   Press   (1) - 1200 Bd        '
mess4:        db        '           (2) - 2400 Bd        '
mess5:        db        '           (3) - 4800 Bd        '
mess6:        db        '       or [ESC] for CP/M        '


        end
Post Reply