global add_hla,div32_16 global ioiniml,ioini1l global intinit global bufinit global cpu_frq global fifolst extrn ?pmsg extrn msg.sm,msg.recv,hwl2phy include config.inc include z180reg.inc ;-------------------------------------------------------------- ; ; add a to hl ; ; return: ; hl = hl + a ; Flags undefined cseg ; (common. TODO: check for banked) add_hla: add a,l ld l,a ret nc inc h ret ;-------------------------------------------------------------------- ; Divide 32 bit by 16 ; ; HLDE: Divident (x) ; BC: Divisor (y) ; ; return: ; HLDE: Quotient ; BC: Reminder cseg ; common area div32_16: exx ;low push de ;save alternate registers (de,bc) push bc exx ;high push de ;low x push bc ;low y ld bc,0 ;bc = high y = 0 ld d,b ;de = high r = 0 ld e,c ex de,hl ;de = x, hl = r exx ;low pop bc ;bc' = low y ex (sp),hl ;hl' = low x, save alternate hl ld de,0 ;de' = low r = 0 ex de,hl ;de = x, hl = r exx ;high ld a,32 ;count ; ; divide x/y ; x: hl ; y: de ; result: ; x/y: hl ; rem: de div_lp: ;do exx ; low ex de,hl ; x add hl,hl ; x <<= 1 exx ; high ex de,hl ; x adc hl,hl ; x <<= 1 exx ; low ex de,hl ; r adc hl,hl ; r <<= 1 exx ; high ex de,hl ; r adc hl,hl ; r <<= 1 exx ; low inc de ; x/q += 1 or a ; sbc hl,bc ; exx ; high sbc hl,bc ; jr nc,div_no_restore exx ; low dec de ; add hl,bc ; r += y exx ; high adc hl,bc ; div_no_restore: ; dec a ; jr nz,div_lp ;while (--count) ex de,hl ; q exx ;low ex de,hl ; q ex (sp),hl ;low q push de ;low r exx ;high pop bc ;bc = r pop de ;de = low q exx ;low pop bc ;restore alternate registers pop de exx ;high ret ;---------------------------------------------------------------------- ; output bytes to consecutive portaddresses ; ; hl: table with following structure: ; db n, port1, val1, val2,... valn ; db m, port1, val1, val2,... valm ; ... ; db 0 ; Terminate table cseg ; (common for now) ioiniml: push bc xor a ioml_lp: ld b,(hl) inc hl cp b jr z,ioml_e ld c,(hl) inc hl otimr jr ioml_lp ioml_e: pop bc ret ;---------------------------------------------------------------------- ; output bytes to ports ; ; hl: tables of port,value pairs: ; db n, port1,val1, port2,val2,... portn,valn ; ... ; db 0 ; Terminate table cseg ; (common for now) ioini1l: push bc jr io1_nxt io1_lp: ld c,(hl) ;port address inc hl otim jr nz,io1_lp io1_nxt: ld b,(hl) ;count inc hl inc b djnz io1_lp pop bc ret ;---------------------------------------------------------------------- dseg intinit: ld hl,ivtab ; ld a,h ; ld i,a ; out0 (il),l ; im 2 ; Let all vectors point to spurious int routines. ld de,sp.int0 ld bc,sp.int.len ld a,9 ivt_i1: ld (hl),e inc l ld (hl),d inc l ex de,hl add hl,bc ex de,hl dec a jr nz,ivt_i1 ret ;-------------------------------------------------------------------- ; Spurious interrupt handler cseg ; common area sp.int0: ld a,00h jr sp.i.1 sp.int.len equ $-sp.int0 ld a,01h jr sp.i.1 ld a,02h jr sp.i.1 ld a,03h jr sp.i.1 ld a,04h jr sp.i.1 ld a,05h jr sp.i.1 ld a,06h jr sp.i.1 ld a,07h jr sp.i.1 ld a,08h sp.i.1: ; out (80h),a add a,'0' ld (spi$nr),a ld hl,spi$msg call ?pmsg sp.i.2: halt jr sp.i.2 spi$msg: db 13,10,'Spurious Int: ' spi$nr: db '0' db 0 ;-------------------------------------------------------------------- ; ; Get/compute CPU clock ; ; return: ; hlde: CPU frequency (Hz) ; dseg cpu_frq: ld hl,tmr_rcv_msg_1 call get_timer ; delay ~8ms @ 18.432MHz --> 147456 clock cycles ; delay ~10ms @ 18.432MHz --> 184320 clock cycles ; ; ld hl,8192 ; 147456/18 ld hl,10240 ; 184320/18 ld de,1 or a dly_lp: sbc hl,de ; 10 jr nz,dly_lp ; 6/8 -> 18 ld hl,tmr_rcv_msg_2 call get_timer ld hl,(stamp2) ld de,(stamp1) or a sbc hl,de ; ld de,4 ; round ld de,5 ; round add hl,de ex de,hl ld hl,0 ld bc,10 call div32_16 ld b,d ld c,e ld hl,00119h ;18432000/(2**16) ld de,04000h ;18432000%(2**16) ld a,b or a jr nz,cpuf_div ld a,c cp 2 jr c,cpuf_done cpuf_div: call div32_16 cpuf_done: ret ;-------------------------------------------------------------------- get_timer: push hl ld hl,timer_msg ld b,timer_msg_len call msg.sm pop hl ld b,tmr_rcv_msg_len ; max receive message len jp msg.recv timer_msg: db 3 ; timer/clock command db 1 ; subcommand (get timer) timer_msg_len equ $ - timer_msg tmr_rcv_msg_1: ds 1 ; len ds 1 ; command ds 1 ; subcommand stamp1: ds 4 ; return value tmr_rcv_msg_len equ $ - tmr_rcv_msg_1 tmr_rcv_msg_2: ds 1 ; len ds 1 ; command ds 1 ; subcommand stamp2: ds 4 ; return value ;-------------------------------------------------------------------- cseg fifolst: rept 4 dw 0 db 0 endm ;-------------------------------------------------------------------- dseg bufinit: ld c,a ld a,(ix+o.id) cp 4 jr nc,bfi_doit2 ld hl,fifolst ld e,a ld d,0 add hl,de add hl,de add hl,de if 0 ld e,(hl) inc hl ld d,(hl) dec hl ld a,e or d jr z,bfi_doit ; TODO: address translation push de pop ix ret endif bfi_doit: push ix pop de ; TODO: address translation ld (hl),e inc hl ld (hl),d ld a,(ix+o.id) or a jr nz,bfi_doit2 ld hl,fifolst ld (040h),hl ld (040h+2),a bfi_doit2: ld (ix+o.in_idx),0 ;reset pointers ld (ix+o.out_idx),0 ld (ix+o.mask),c ;reset "size" push ix ;get phys. address of fifo pop hl call hwl2phy ex de,hl ld c,a ld a,(ix+o.id) ;fifo id or a ;test if fifo 0 jr nz,bfi_1 out (AVRINT5),a ret bfi_1: ld hl,bfi_msg_end ld (hl),c dec hl ld (hl),d dec hl ld (hl),e dec hl ld (hl),a dec hl ld b,bfi_msg_len call msg.sm ret bfi_msg: db 0 ;function: 0 db 0 ;subfunc: gets overwritten with buf id dw 0 ;physical db 0 ; address bfi_msg_len equ $ - bfi_msg bfi_msg_end equ $ - 1 ;---------------------------------------------------------------------- end