eris2010

Documentation: http://frombelow.net/projects/eris2010/
Clone: git clone https://git.frombelow.net/eris2010.git
Log | Files | Refs | Submodules | README | LICENSE

io.asm (8040B)


      1 ;;; Copyright 2021 Gerd Beuster (gerd@frombelow.net). This is free
      2 ;;; software under the GNU GPL v3 license or any later version. See
      3 ;;; COPYING in the root directory for details.
      4 
      5 ;;; Serial IO and string manipulation
      6 
      7 io .namespace
      8 
      9 .if SYMON
     10         acia_base = $8800
     11 .else
     12         acia_base = $c000
     13 .endif
     14         acia_data_reg = acia_base
     15         acia_status_reg = acia_base + $1
     16         acia_cmd_reg = acia_base + $2
     17         acia_ctrl_reg = acia_base + $3
     18 
     19 .section zero_page
     20 	;; Temporary zero page variables;
     21 	;; only used in subroutine
     22 puts_str:	.word ?
     23 gets_len:	.byte ?
     24 gets_str:	.word ?
     25 .send zero_page
     26 
     27 .section rom
     28 
     29 ;;; init_acia
     30 ;;;   Initialize acai for communication
     31 ;;;   Input:
     32 ;;;     -
     33 ;;;   Output:
     34 ;;;     -
     35 ;;;   Changes:
     36 ;;;     a, acai registers
     37 init_acia:
     38 	.block
     39         ;; Reset acai
     40         sta io.acia_status_reg
     41         lda #%00011111          ; 19200 bps, 8 data bits, 1 stop bit
     42         sta io.acia_ctrl_reg
     43         ;; No parity, no echo, no interrupts, DTR ready
     44         lda #%11001011
     45         sta io.acia_cmd_reg
     46         rts
     47 	.bend
     48 
     49 ;;; ----------------------------------------------------------
     50 ;;; STANDARD LIBRARY FUNCTIONS
     51 ;;;
     52 ;;; These functions may be used by user programs. Labels
     53 ;;; marked with 'EXPORT' are exported to liba.h. When
     54 ;;; the user program imports this header file, the functions
     55 ;;; are available.
     56 ;;; ----------------------------------------------------------
     57 
     58 ;;; puts
     59 ;;;   Send up to 256 characters terminated by null via acia
     60 ;;;   Input:
     61 ;;;     puts_str, put_str+1:
     62 ;;;       2 bytes on zero page containing string address
     63 ;;;   Output:
     64 ;;;     -
     65 ;;;   Changes:
     66 ;;;     a, x, y, puts_str, put_str+1
     67 puts:
     68 	.block
     69         ;; Send string terminated by '\0'
     70         ldy #$00
     71 _puts_loop:
     72         lda (io.puts_str),y
     73         beq _puts_end
     74 	phy
     75         jsr io.putc
     76 	ply
     77         iny
     78         jmp _puts_loop
     79 _puts_end:
     80         rts
     81 	.bend
     82 	
     83 ;;; putc
     84 ;;;   Send character via acia
     85 ;;;   Input:
     86 ;;;     a:
     87 ;;;       Character to be printed
     88 ;;;   Output:
     89 ;;;     -
     90 ;;;   Changes:
     91 ;;;     x, acai registers
     92 putc:
     93 	.block
     94 	;; Send character.
     95         ;; Due to bugs in the register and interrupt
     96 	;; handling of the WDC 65C02, we have to use
     97 	;; a manual delay.
     98         sta io.acia_data_reg
     99 .switch	CLOCK_SPEED
    100 .case  8			; 8 Mhz Clock
    101 	SERIAL_SEND_DELAY_X = $c3
    102 	SERIAL_SEND_DELAY_Y = $04
    103 .case  4			; 4 Mhz Clock
    104 	SERIAL_SEND_DELAY_X = $c3
    105 	SERIAL_SEND_DELAY_Y = $02
    106 .case 2				; 2 Mhz Clock
    107 	SERIAL_SEND_DELAY_X = $c2
    108 	SERIAL_SEND_DELAY_Y = $01
    109 .default			; 1 Mhz Clock
    110 	SERIAL_SEND_DELAY_X = $88
    111 	SERIAL_SEND_DELAY_Y = $01
    112 .endswitch
    113 	ldy #SERIAL_SEND_DELAY_Y
    114 outer_loop:	
    115 	ldx #SERIAL_SEND_DELAY_X
    116 inner_loop:
    117 	dex
    118         bne inner_loop
    119 	dey
    120 	bne outer_loop
    121 	rts
    122 	.bend
    123 	
    124 ;;; puth
    125 ;;;   Convert byte to hex and send via acia
    126 ;;;   Input:
    127 ;;;     a:
    128 ;;;       Byte to be printed
    129 ;;;   Output:
    130 ;;;     -
    131 ;;;   Changes:
    132 ;;;     a, x, acai registers, c-flag
    133 puth:
    134 	.block
    135         ;; Send byte a as hex number
    136         pha
    137         lsr a
    138         lsr a
    139         lsr a
    140         lsr a
    141         jsr io.puth_nibble
    142         pla
    143         jsr io.puth_nibble
    144         rts
    145 	.bend
    146 
    147 ;;; puth_nibble
    148 ;;;   Convert lower half of byte to hex and send via acia
    149 ;;;   Input:
    150 ;;;     a:
    151 ;;;       Nibble  to be printed
    152 ;;;   Output:
    153 ;;;     -
    154 ;;;   Changes:
    155 ;;;     a, x, acai registers, c-flag
    156 puth_nibble:
    157 	.block
    158         ;; Print hex digit
    159         clc
    160         and #$0F
    161         adc #$30                ; Decimal number
    162         cmp #$3A                ; >10 ?
    163         bmi _puth_putc
    164         adc #$26
    165 _puth_putc:
    166         jsr io.putc
    167         rts
    168 	.bend
    169 
    170 ;;; putd
    171 ;;;   Output decimal number
    172 ;;;   Input:
    173 ;;;     a:
    174 ;;;       The number
    175 ;;;   Output:
    176 ;;;     -
    177 ;;;   Changes:
    178 ;;;     a, x, y, acai registers, c-flag
    179 putd:
    180 	.block
    181 	ldy #$00
    182 first_digit:	
    183 	cmp #100
    184 	bcc first_digit_set
    185 	sec
    186 	sbc #100
    187 	iny
    188 	jmp first_digit
    189 first_digit_set:
    190 	ldx #$00
    191 	pha
    192 	tya
    193 	beq skip_first_leading_zero
    194 	jsr io.puth_nibble
    195 	ldx #$01		; Force printing of zeros in rest of term
    196 skip_first_leading_zero:	
    197 	pla
    198 second_digit:
    199 	cmp #10
    200 	bcc second_digit_set
    201 	sec
    202 	sbc #10
    203 	iny
    204 	jmp second_digit
    205 second_digit_set:	
    206 	pha
    207 	tya
    208 	cpx #$01
    209 	beq do_not_skip_potential_second_leading_zero
    210 	cmp #$00
    211 	beq skip_second_leading_zero
    212 do_not_skip_potential_second_leading_zero:	
    213 	jsr io.puth_nibble
    214 skip_second_leading_zero:
    215 	pla
    216 	jmp io.puth_nibble
    217 	.bend
    218 
    219 
    220 ;;; putnl
    221 ;;;   Send newline via acia
    222 ;;;   Input:
    223 ;;;     -
    224 ;;;   Output:
    225 ;;;     -
    226 ;;;   Changes:
    227 ;;;     a
    228 putnl:
    229 	.block
    230         lda #$0d
    231         jsr io.putc
    232         lda #$0a
    233         jsr io.putc
    234         rts
    235 	.bend
    236 
    237 ;;; getc
    238 ;;;   Read character from acia. Blocks until character is read
    239 ;;;   Input:
    240 ;;;     -
    241 ;;;   Output:
    242 ;;;     a:
    243 ;;;       Character read
    244 ;;;   Changes:
    245 ;;;     a, acai registers
    246 getc:
    247 	.block
    248         ;; Read character from acia
    249         lda io.acia_status_reg
    250         and #%00001000
    251         beq io.getc
    252         lda io.acia_data_reg
    253         rts
    254 	.bend
    255 
    256 ;;; getc_seed_rng
    257 ;;;   Like getc, but also updates lsfr
    258 ;;;   This is our only source of randomness right now:
    259 ;;;   While we are busy waiting for a character, lsfr is
    260 ;;;   updated.
    261 ;;;   Input:
    262 ;;;     -
    263 ;;;   Output:
    264 ;;;     a:
    265 ;;;       Character read
    266 ;;;   Changes:
    267 ;;;     a, acai registers, lsfr_state
    268 getc_seed_rng:
    269 	.block
    270         ;; Read character from acia
    271         ;; We also use the time between keystrokes
    272         ;; as entropy source for the RNG
    273         jsr lfsr.step
    274         lda io.acia_status_reg
    275         and #%00001000
    276         beq io.getc_seed_rng
    277         lda io.acia_data_reg
    278         rts
    279 	.bend
    280 
    281 getc_nonblocking:
    282 	.block
    283         ;; Non-blocking read: If
    284         ;; character has been read,
    285         ;; it is returned in A and
    286         ;; C is cleared. If not,
    287         ;; C is set
    288         sec
    289         lda io.acia_status_reg
    290         and #%00001000
    291         beq nothing_read
    292         clc
    293         lda io.acia_data_reg
    294 nothing_read:   
    295         rts
    296 	.bend
    297 
    298 ;;; gets
    299 ;;;   Read up to 255 characters terminated by CR via acia
    300 ;;;   Input:
    301 ;;;     gets_len:
    302 ;;;       Max. length of input.
    303 ;;;     gets_str, gets_str+1:
    304 ;;;       2 bytes on zero page containing destination address
    305 ;;;       +-------------------------------------------------------+
    306 ;;;       |IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! |
    307 ;;;       +-------------------------------------------------------+
    308 ;;;       Note that a terminating zero is added to the string.
    309 ;;;       Therefore gets_len+1 bytes may be written!
    310 ;;;   Output:
    311 ;;;     Zero terminated string at gets_str, gets_str+1
    312 ;;;   Changes:
    313 ;;;     a, y, ACAI registers
    314 gets:
    315 	.block
    316         ;; Read string terminated by CR
    317         ldy #$00
    318 loop:
    319 	phy
    320         jsr io.getc
    321         jsr io.putc
    322 	ply
    323         cmp #$0d                ; GOT CR?
    324         beq terminate_string    ; if not
    325         sta (io.gets_str), y ; store character
    326         iny                     ; if max length
    327         cpy io.gets_len     ; not reached,
    328         bne loop                ; continue loop.
    329 terminate_string:
    330         lda #$00
    331         sta (io.gets_str), y
    332         rts
    333 	.bend
    334 
    335 ;;; str2byte
    336 ;;;   Convert number (<= 255) given as string to byte.
    337 ;;;   Expects zero-terminated string on stack
    338 ;;;   Input:
    339 ;;;     Zero-terminated string on stack
    340 ;;;   Output:
    341 ;;;     a:
    342 ;;;       Byte value
    343 ;;;   Changes:
    344 ;;;     a, x, y
    345 str2byte:
    346 	.block
    347 	jsr ds.create_stack_frame
    348 	#ds.PUSH $04		; Local variable (string of length four)
    349 	lda #$00
    350 	pha
    351 	ldy #$00
    352 add_digit:	
    353 	lda (ds.frame_ptr),y
    354 	beq done
    355 	sec			; Convert next digit
    356 	sbc #'0'		; from ascii to
    357 	sta (ds.frame_ptr),y	; number.
    358 	pla			; Multiply current
    359 	jsr io.multiply_by_ten	; accumulator by 10.
    360 	clc			; Add new
    361 	adc (ds.frame_ptr),y	; digit.
    362 	pha
    363 	iny			; Advance to next digit
    364 	jmp add_digit
    365 done:
    366 	pla
    367 	#ds.sta_LOCAL 0
    368 	jsr ds.delete_stack_frame
    369 	.bend
    370 
    371 ;;; multiply_by_ten
    372 ;;;   Multiply A by ten.
    373 ;;;   Input:
    374 ;;;     a: Number
    375 ;;;   Output:
    376 ;;;     a: Number * 10
    377 ;;;   Changes:
    378 ;;;     a, c
    379 multiply_by_ten:
    380 	.block
    381 	sta (ds.ptr)
    382 	lda #$00
    383 	clc
    384 	.for i = 0, i < 10, i += 1
    385 		adc (ds.ptr)
    386 	.next
    387 	rts
    388 	.bend
    389 
    390 .send rom
    391 .endn