Merge pull request #103 from ivan-tat/master

utils: added `dmaplayw` utility
This commit is contained in:
Ivan Tatarinov 2021-06-05 11:43:41 +03:00 committed by GitHub
commit 9f9327bee2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 479 additions and 47 deletions

View File

@ -1,8 +1,11 @@
; esxdos.def
;
; SPDX-FileCopyrightText: Copyright (C) 2019, 2021 Antonio Villena
; SPDX-FileCopyrightText: Copyright (C) 2017 AZXUNO association
;
; SPDX-License-Identifier: GPL-3.0-only
; SPDX-FileContributor: Copyright (C) 2019, 2021 Antonio Villena
; SPDX-FileContributor: 2021 Ivan Tatarinov <ivan-tat@ya.ru>
;
; SPDX-License-Identifier: GPL-3.0-or-later
; Compatible compilers:
; SJAsmPlus, <https://github.com/sjasmplus/sjasmplus/>
@ -10,19 +13,88 @@
ifndef esxdos_def_included
define esxdos_def_included
define FA_READ 0x01
define FA_WRITE 0x02
define FA_OPEN_AL 0x08
define M_GETSETDRV 0x89
define F_OPEN 0x9a
define F_CLOSE 0x9b
define F_READ 0x9d
define F_WRITE 0x9e
define F_FSTAT 0xa1
define HOOK_BASE 128
define MISC_BASE HOOK_BASE+8
define FSYS_BASE MISC_BASE+16
macro esxdos dato
rst $08
defb dato
endm
define DISK_STATUS HOOK_BASE+0 ; hookcodes for block devices
define DISK_READ HOOK_BASE+1
define DISK_WRITE HOOK_BASE+2
define DISK_IOCTL HOOK_BASE+3
define DISK_INFO HOOK_BASE+4
define M_DOSVERSION MISC_BASE+0
define M_GETSETDRV MISC_BASE+1
define M_DRIVEINFO MISC_BASE+2
define M_TAPEIN MISC_BASE+3
define M_TAPEOUT MISC_BASE+4
define M_GETHANDLE MISC_BASE+5
define M_GETDATE MISC_BASE+6
define F_MOUNT FSYS_BASE+0
define F_UMOUNT FSYS_BASE+1
define F_OPEN FSYS_BASE+2
define F_CLOSE FSYS_BASE+3
define F_SYNC FSYS_BASE+4
define F_READ FSYS_BASE+5
define F_WRITE FSYS_BASE+6
define F_SEEK FSYS_BASE+7
define F_FGETPOS FSYS_BASE+8
define F_FSTAT FSYS_BASE+9
define F_FTRUNCATE FSYS_BASE+10
define F_OPENDIR FSYS_BASE+11
define F_READDIR FSYS_BASE+12
define F_TELLDIR FSYS_BASE+13
define F_SEEKDIR FSYS_BASE+14
define F_REWINDDIR FSYS_BASE+15
define F_GETCWD FSYS_BASE+16
define F_CHDIR FSYS_BASE+17
define F_MKDIR FSYS_BASE+18
define F_RMDIR FSYS_BASE+19
define F_STAT FSYS_BASE+20
define F_UNLINK FSYS_BASE+21
define F_TRUNCATE FSYS_BASE+22
define F_CHMOD FSYS_BASE+23
define F_RENAME FSYS_BASE+24
define F_GETFREE FSYS_BASE+25
define FA_READ %00000001 ; Read access
define FA_WRITE %00000010 ; Write access
define FA_OPEN_EX %00000000 ; Open if exists, else error
define FA_OPEN_AL %00001000 ; Open if exists, if not create
define FA_CREATE_NEW %00000100 ; Create if not exists, if exists error
define FA_CREATE_AL %00001100 ; Create if not exists, else open and truncate
define FA_USE_HEADER %01000000 ; Use +3DOS header (passed in DE)
; Errors:
define EOK 1
define ENONSENSE 2
define ESTEND 3
define EWRTYPE 4
define ENOENT 5 ; No such file or directory
define EIO 6 ; I/O error
define EINVAL 7 ; Invalid file name
define EACCES 8 ; Access Denied
define ENOSPC 9 ; No space left on device
define ENXIO 10 ; Request beyond the limits of the device
define ENODRV 11 ; No such drive
define ENFILE 12 ; Too many files open in system
define EBADF 13 ; Bad file descriptor
define ENODEV 14 ; No such device
define EOVERFLOW 15
define EISDIR 16
define ENOTDIR 17
define EEXIST 18
define EPATH 19 ; Invalid path
define ENOSYS 20
define ENAMETOOLONG 21
define ENOCMD 22
define EINUSE 23
define ERDONLY 24
macro esxdos func
rst $08
db func
endm
endif ; !esxdos_def_included

View File

@ -2,6 +2,8 @@
;
; SPDX-FileCopyrightText: Copyright (C) 2019, 2021 Antonio Villena
;
; SPDX-FileContributor: 2021 Ivan Tatarinov <ivan-tat@ya.ru>
;
; SPDX-License-Identifier: GPL-3.0-only
; Compatible compilers:
@ -10,38 +12,55 @@
ifndef zxuno_def_included
define zxuno_def_included
define zxuno_port $fc3b
define zxuno_data $fd3b
define master_conf 0
define master_mapper 1
define flash_spi 2
define flash_cs 3
define scan_code 4
define key_stat 5
define joy_conf 6
define key_map 7
define nmi_event 8
define mouse_data 9
define mouse_status 10
define scandbl_ctrl 11
define raster_line 12
define raster_ctrl 13
define dev_control 14
define core_addr $fc
define core_boot $fd
define cold_boot $fe
define core_id $ff
define zxuno_port $fc3b ; ZX-UNO ZXI register address
define zxuno_data $fd3b ; ZX-UNO ZXI register data
define master_conf 0
define master_mapper 1
define flash_spi 2
define flash_cs 3
define scan_code 4
define key_stat 5
define joy_conf 6
define key_map 7
define nmi_event 8
define mouse_data 9
define mouse_status 10
define scandbl_ctrl 11
define raster_line 12
define raster_ctrl 13
define dev_control 14
define dev_control2 15
define newreg 16
define dma_ctrl $a0 ; ZX-UNO register to start/stop DMA
define dma_src $a1 ; ZX-UNO register to set DMA source
define dma_dst $a2 ; ZX-UNO register to set DMA destination
define dma_pre $a3 ; ZX-UNO register to set DMA prescaler
define dma_len $a4 ; ZX-UNO register to set DMA length
define dma_prob $a5
define dma_stat $a6
define ad724 $fb
define core_addr $fc
define core_boot $fd
define cold_boot $fe
define core_id $ff
define SPI_PORT $eb
define OUT_PORT $e7
define MMC_0 $fe ; D0 LOW = SLOT0 active
define CMD0 $40
define CMD1 $41
define CMD8 $48
define SET_BLOCKLEN $50
define READ_SINGLE $51
define CMD41 $69
define CMD55 $77
define CMD58 $7a
; MMC/SDC interface:
define SPI_PORT $eb
define OUT_PORT $e7
define MMC_0 $fe ; D0 LOW = SLOT0 active
; MMC/SDC commands:
define CMD0 $40+0 ; GO_IDLE_STATE
define CMD1 $40+1 ; SEND_OP_COND (MMC)
define CMD8 $40+8 ; SEND_IF_COND
define SET_BLOCKLEN $40+16
define READ_SINGLE $40+17 ; READ_SINGLE_BLOCK
define WRITE_BLOCK $40+24
define CMD41 $40+41 ; SD_SEND_OP_COND (SDC)
define CMD55 $40+55 ; APP_CMD
define CMD58 $40+58 ; READ_OCR
; SpecDrum interface:
define specdrum_port $ffdf ; Specdrum I/O port in 16-bit format for DMA destination
endif ; !zxuno_def_included

View File

@ -49,6 +49,7 @@ BINS=\
BACKUP\
CORCLEAN\
COREBIOS\
DMAPLAYW\
ROMSBACK\
ROMSUPGR\
UPGR16M\
@ -133,6 +134,12 @@ build/COREBIOS: $(srcdir)/corebios.asm\
| build
$(AS) $(AFLAGS) --raw=$@ $<
build/DMAPLAYW: $(srcdir)/dmaplayw.asm\
$(INCLUDEDIR)/zxuno.def\
$(INCLUDEDIR)/esxdos.def\
| build
$(AS) $(AFLAGS) --raw=$@ $<
build/ROMSBACK: $(srcdir)/romsback.asm\
$(INCLUDEDIR)/zxuno.def\
$(INCLUDEDIR)/esxdos.def\

334
utils/dmaplayw.asm Normal file
View File

@ -0,0 +1,334 @@
; dmaplayw.asm - play an audio file using the SpecDrum and DMA at 15.625 kHz.
;
; Copyright (C) 2017 AZXUNO association
; Contributors:
; 2021 Ivan Tatarinov <ivan-tat@ya.ru>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <https://www.gnu.org/licenses/>.
;
; SPDX-FileCopyrightText: Copyright (C) 2017 AZXUNO association
;
; SPDX-FileContributor: 2021 Ivan Tatarinov <ivan-tat@ya.ru>
;
; SPDX-License-Identifier: GPL-3.0-or-later
; Compatible compilers:
; SJAsmPlus, <https://github.com/sjasmplus/sjasmplus/>
; output DMAPLAYW
define PROGRAM "dmaplayw"
define VERSION "0.1"
include "zxuno.def"
include "esxdos.def"
define CPU_FREQ 3500000
define SPECDRUM_FREQ 15625
; Prescaler for timed DMA. The count goes from 0 to 223, that is, 224 cycles
define DMA_PRESCALER CPU_FREQ / SPECDRUM_FREQ - 1
org $2000 ; entry point of ESXDOS program
;-----------------------------------------------------------------------------
; Subroutine
; In: HL = pointer to the command line arguments string (ASCIIZ)
Main ld a, h
or l
jp nz, Init
ld hl, aUsage
.PrintLoop ld a, (hl)
or a
ret z ; Return on string end
rst $10
inc hl
jr .PrintLoop
;-----------------------------------------------------------------------------
; Subroutine
; In: HL = pointer to the command line arguments (filename)
GetFileName ld de, BufferFileName
.CheckCharacter ld a, (hl)
or a
jr z, .End
cp " "
jr z, .End
cp ":"
jr z, .End
cp 13
jr z, .End
ldi
jr .CheckCharacter
.End xor a
ld (de), a
inc de ; DE remains pointing to the buffer that is needed in OPEN, I don't know what for
ret
; 01234567890123456789012345678901
aUsage db " .", PROGRAM, " audiofile.wav", 13
db 13
db "Plays an audio file using the", 13
db "SpecDrum and DMA at 15.625 kHz", 13, 0
;-----------------------------------------------------------------------------
; Subroutine
; In: HL = pointer to the command line arguments string (ASCIIZ)
Init call GetFileName ; results DE = buffer for OPEN
xor a
esxdos M_GETSETDRV ; A = current unit
ld b, FA_READ ; B = opening mode
ld hl, BufferFileName ; HL = pointer to file name (ASCIIZ)
esxdos F_OPEN
ret c ; Return on error
ld (FHandle), a
ld l, 0 ; SEEK_START
ld bc, 0
ld de, 44 ; Skip 44 bytes from start (WAV header)
esxdos F_SEEK
ret c ; Return on error
ld hl, ScreenAddr
ld de, ScreenAddr+1
ld bc, 31
ld (hl), 255
ldir ; This line will be deleted on the first wave plot
ld hl, DMABuffer
ld de, DMABuffer+1
ld bc, DMABuffer_Len-1
ld (hl), 0
ldir ; Clear DMA buffer
; Prepare to play
di
ld hl, DMABuffer
ld bc, zxuno_port
ld a, dma_src
out (c), a
inc b ; BC = zxuno_data
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_dst
out (c), a
inc b ; BC = zxuno_data
ld hl, specdrum_port
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_pre
out (c), a
inc b ; BC = zxuno_data
ld hl, DMA_PRESCALER
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_len
out (c), a
inc b ; BC = zxuno_data
ld hl, DMABuffer_Len
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_prob
out (c), a
inc b ; BC = zxuno_data
ld hl, DMABuffer
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_ctrl
out (c), a
inc b ; BC = zxuno_data
ld a, %00000111 ; Mem to I/O, redisparable, timed, source address is checked
out (c), a
dec b ; BC = zxuno_port
.PlayLoop ld bc, $7ffe ; SPACE halfrow
in a, (c)
and %00000001
jp z, .ExitPlay
ld bc, zxuno_port
ld a, dma_stat
out (c), a
inc b ; BC = zxuno_data
.StillInSecondHalf
in a, (c)
bit 7, a
jr z, .StillInSecondHalf
dec b ; BC = zxuno_port
ld a, dma_prob
out (c), a
inc b ; BC = zxuno_data
ld hl, DMABuffer + DMABuffer_Len/2
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_stat
out (c), a
inc b ; BC = zxuno_data
in a, (c)
; Fill second half of buffer with audio data
ld hl, DMABuffer + DMABuffer_Len/2
ld bc, DMABuffer_Len/2
ld a, (FHandle)
esxdos F_READ
jp c, .ExitPlay ; End read on error
ld a, b
or c
jp z, .ExitPlay ; End read on end of data
ld hl, DMABuffer + DMABuffer_Len/2
call PlotWave
ld bc, zxuno_port
ld a, dma_stat
out (c), a
inc b ; BC = zxuno_data
.StillInFirstHalf
in a, (c)
bit 7, a
jr z, .StillInFirstHalf
dec b ; BC = zxuno_port
ld a, dma_prob
out (c), a
inc b ; BC = zxuno_data
ld hl, DMABuffer
out (c), l
out (c), h
dec b ; BC = zxuno_port
ld a, dma_stat
out (c), a
inc b ; BC = zxuno_data
in a, (c)
; Fill first half of buffer with audio data
ld hl, DMABuffer
ld bc, DMABuffer_Len/2
ld a, (FHandle)
esxdos F_READ
jp c, .ExitPlay ; End read on error
ld a, b
or c
jp z, .ExitPlay ; End read on end of data
ld hl, DMABuffer
call PlotWave
jp .PlayLoop
.ExitPlay ld bc, zxuno_port
ld a, dma_ctrl
out (c), a
inc b ; BC = zxuno_data
xor a
out (c), a
dec b ; BC = zxuno_port
ld a, (FHandle)
esxdos F_CLOSE
or a ; Clear carry flag
ei
ret
FHandle db 0
;-----------------------------------------------------------------------------
; Subroutine
PlotWave ld de, BufferCleared
ld c, 0
.Loop ld a, (de)
ld b, a
call Plot
ld a, (hl)
srl a
add a, 24
ld b, a
call Plot
ld a, b
ld (de), a
inc hl
inc de
inc c
jp nz, .Loop
ret
;-----------------------------------------------------------------------------
; Subroutine
; In: B = y
; C = x
Plot push bc
push de
push hl
ld e, b
ld d, 0 ; DE = y
sla e
rl d ; DE = DE*2
ld hl, DirScan
add hl, de ; HL = pointer to the address of the first pixel of Y
ld e, (hl)
inc hl
ld d, (hl)
ex de, hl ; HL = dir first pixel row Y
ld d, c ; save X coordinate in D
ld a, c
.3 srl a
ld c, a
ld b, 0
add hl, bc ; HL contains the address to paint the pixel
ld a, d ; restore X coordinate
and %00000111
ld de, DirBits
add a, e
ld e, a
ld a, d
adc a, 0
ld d, a
ld a, (de)
xor (hl)
ld (hl), a
pop hl
pop de
pop bc
ret
DirBits
i = %10000000
while i > 0
db i
i = i / 2
endw
DirScan
y = 0
while y < 192
dw ScreenAddr + (256 * (y & 7)) + (32 * ((y / 8) & 7)) + (64 * 32 * (y / 64))
y = y + 1
endw
BufferCleared ds 256
BufferFileName: equ $ ; Rest of RAM for filename
ScreenAddr: equ $4000
DMABuffer: equ $8000 ; DMA buffer start address (circular play buffer)
DMABuffer_Len: equ 2048 ; DMA buffer length