+ cpi temp,WRUAL ;write unallocated?
+ brne dsk_chkuna ;check for unalloc
+
+; write to unallocated, set parameters
+ ldi temp,blksize/128 ;next unalloc recs
+ sts unacnt,temp
+ lds temp,seekdsk ;disk to seek
+ sts unadsk,temp ;unadsk = sekdsk
+ lds temp,seektrk
+ sts unatrk,temp ;unatrk = sectrk
+ lds temp,seektrk+1
+ sts unatrk+1,temp ;unatrk = sectrk
+ lds temp,seeksec
+ sts unasec,temp ;unasec = seksec
+;
+dsk_chkuna:
+ ;check for write to unallocated sector
+ lds temp,unacnt ;any unalloc remain?
+ tst temp
+ breq dsk_alloc ;skip if not
+
+; more unallocated records remain
+ dec temp ;unacnt = unacnt-1
+ sts unacnt,temp
+ lds temp,seekdsk ;same disk?
+ lds temp2,unadsk
+ cp temp,temp2 ;seekdsk = unadsk?
+ brne dsk_alloc ;skip if not
+
+; disks are the same
+ lds temp,unatrk
+ lds temp2,unatrk+1
+ lds temp3,seektrk
+ lds temp4,seektrk+1
+ cp temp,temp3 ;seektrk = unatrk?
+ cpc temp2,temp4
+ brne dsk_alloc ;skip if not
+
+; tracks are the same
+ lds temp,seeksec ;same sector?
+ lds temp2,unasec
+ cp temp,temp2 ;seeksec = unasec?
+ brne dsk_alloc ;skip if not
+
+; match, move to next sector for future ref
+ inc temp2 ;unasec = unasec+1
+ sts unasec,temp2
+ cpi temp2,CPMSPT ;end of track? (count CP/M sectors)
+ brlo dsk_noovf ;skip if no overflow
+
+; overflow to next track
+ sts unasec,_0 ;unasec = 0
+ lds temp,unatrk
+ lds temp2,unatrk+1
+ subi temp, low(-1) ;unatrk = unatrk+1
+ sbci temp2,high(-1)
+ sts unatrk,temp
+ sts unatrk+1,temp2
+;
+dsk_noovf:
+ cbi flags,rsflag ;rsflag = 0
+ rjmp dsk_rwoper ;to perform the write
+;
+dsk_alloc:
+ ;not an unallocated record, requires pre-read
+ sts unacnt,_0 ;unacnt = 0
+ sbi flags,rsflag ;rsflag = 1
+
+;*****************************************************
+;* Common code for READ and WRITE follows *
+;*****************************************************
+
+dsk_rwoper:
+ ;enter here to perform the read/write
+ sts erflag,_0 ;no errors (yet)
+
+ ;Convert track/sector to an LBA address (in 128byte blocks)
+
+ lds xl,seeksec ;
+ ldi xh,0 ;
+ ldi yl,0 ;
+ lds temp3,seektrk ;
+ lds temp4,seektrk+1 ;
+ ldi temp,CPMSPT ;
+ mul temp3,temp ;
+ add xl,r0 ;
+ adc xh,r1 ;
+ mul temp4,temp ;
+ add xh,r0 ;xh:xl := sec + trk * SectorsPerTrack
+ adc yl,r1 ;
+ clr _0
+
+ mov temp,xl
+ andi temp,SECMSK ;mask buffer number
+ push temp ;save for later
+
+ ;Convert from CP/M LBA blocks to host LBA blocks
+ ldi temp,SECSHF
+dsk_sh1:
+ lsr xh
+ ror xl
+ ror yl
+ dec temp
+ brne dsk_sh1
+ ;yl:xh:xl = host block to seek
+; active host sector?
+ sbis flags,hostact ;host active?
+ rjmp dsk_filhst ;fill host if not
+
+; host buffer active, same as seek buffer?
+ lds temp,seekdsk
+ lds temp2,hostdsk ;same disk?
+ cp temp,temp2 ;seekdsk = hostdsk?
+ brne dsk_nomatch
+
+; same disk, same block?
+ lds temp,hostlba
+ lds temp2,hostlba+1
+ lds temp3,hostlba+2
+ cp xl,temp
+ cpc xh,temp2
+ cpc yl,temp3
+ breq dsk_match
+;
+dsk_nomatch:
+ ;proper disk, but not correct sector
+ sbic flags,hostwrt ;host written?
+ rcall dsk_writehost ;clear host buff
+
+dsk_filhst:
+ ;may have to fill the host buffer
+ lds temp,seekdsk
+ sts hostdsk,temp
+ sts hostlba,xl
+ sts hostlba+1,xh
+ sts hostlba+2,yl
+
+ sbic flags,rsflag ;need to read?
+ rcall dsk_readhost ;yes, if 1
+ cbi flags,hostwrt ;no pending write
+
+dsk_match:
+ sbi flags,hostact ;host buffer active now
+
+ ;copy data to or from buffer
+ ldi zl,low(hostbuf)
+ ldi zh,high(hostbuf)
+ ldi temp,128
+ pop temp2 ;get buffer number (which part of hostbuf)
+ mul temp2,temp
+ add zl,r0 ;offset in hostbuf
+ adc zh,r1
+.if DISK_DEBUG
+ push r0
+ push r1
+ clr _0
+ rcall printstr
+ .db "; host buf adr: ",0,0
+ pop temp
+ rcall printhex
+ pop temp
+ rcall printhex
+.endif
+ clr _0
+
+ lds xl,dmaadr
+ lds xh,dmaadr+1
+ ldi temp3,128 ;length of move
+ sbic flags,readop ;which way?
+ rjmp dsk_rmove ;skip if read
+
+; mark write operation
+ sbi flags,hostwrt ;hostwrt = 1
+dsk_wmove:
+ rcall memReadByte
+ st z+,temp
+ adiw xl,1
+ dec temp3
+ brne dsk_wmove
+ rjmp dsk_rwmfin
+
+dsk_rmove:
+ ld temp,z+
+ rcall memWriteByte
+ adiw xl,1
+ dec temp3
+ brne dsk_rmove
+dsk_rwmfin:
+; data has been moved to/from host buffer
+ lds temp,wrtype ;write type
+ cpi temp,WRDIR ;to directory?
+ breq dsk_wdir
+ lds temp,erflag
+.if 0
+ rcall timer_quit
+ rcall printstr
+ .db " Out",0
+.endif
+ ret ;no further processing
+dsk_wdir:
+; clear host buffer for directory write
+ lds temp,erflag
+ tst temp ;errors?
+ breq dsk_wdir1
+ ret ;skip if so
+dsk_wdir1:
+ rcall dsk_writehost ;clear host buff
+ cbi flags,hostwrt ;buffer written
+ lds temp,erflag
+ ret
+
+
+;*****************************************************
+;* WRITEhost performs the physical write to *
+;* the host disk, READhost reads the physical *
+;* disk. *
+;*****************************************************
+
+dsk_writehost:
+ ;hostdsk = host disk #, hostlba = host block #.
+ ;Write "hostsize" bytes from hostbuf and return
+ ;error flag in erflag.
+ ;Return erflag non-zero if error
+
+ push yh
+ push yl
+ push xh
+ push xl
+ ldi zl,low(hostdstart)
+ ldi zh,high(hostdstart)
+ lds temp,hostdsk
+ lsl temp
+ lsl temp
+ add zl,temp
+ adc zh,_0