mirror of
https://github.com/jeremysrand/mocklib.git
synced 2024-06-08 21:29:28 +00:00
Lots more cleanup. Make everything slot independent including the speech routines. Adopt the mockingBoard prefix for everything. Put the speech APIs right into mockingboard.h.
This commit is contained in:
parent
80cabff983
commit
cbb37cae43
|
@ -7,10 +7,8 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
9D16BCE21D9E070B005EE214 /* speech.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = speech.s; sourceTree = "<group>"; };
|
9D16BCE21D9E070B005EE214 /* mockingboard_speech.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = mockingboard_speech.s; sourceTree = "<group>"; };
|
||||||
9D49929C1DB5C5F700606789 /* speech.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = speech.h; sourceTree = "<group>"; };
|
9D49929C1DB5C5F700606789 /* mockingboard_speech.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mockingboard_speech.h; sourceTree = "<group>"; };
|
||||||
9D49929D1DB5C65200606789 /* speech_api.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = speech_api.c; sourceTree = "<group>"; };
|
|
||||||
9D49929E1DB5C65200606789 /* speech_api.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = speech_api.h; sourceTree = "<group>"; };
|
|
||||||
9DB3C98C1D84A11600395532 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
|
9DB3C98C1D84A11600395532 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
|
||||||
9DB3C98D1D84A11600395532 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
9DB3C98D1D84A11600395532 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
||||||
9DB3C98F1D84A11600395532 /* AppleCommander.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = AppleCommander.jar; path = make/AppleCommander.jar; sourceTree = "<group>"; };
|
9DB3C98F1D84A11600395532 /* AppleCommander.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = AppleCommander.jar; path = make/AppleCommander.jar; sourceTree = "<group>"; };
|
||||||
|
@ -39,10 +37,8 @@
|
||||||
9DB3C98C1D84A11600395532 /* main.c */,
|
9DB3C98C1D84A11600395532 /* main.c */,
|
||||||
9DB3C99C1D84A21E00395532 /* mockingboard.c */,
|
9DB3C99C1D84A21E00395532 /* mockingboard.c */,
|
||||||
9DB3C99D1D84A21E00395532 /* mockingboard.h */,
|
9DB3C99D1D84A21E00395532 /* mockingboard.h */,
|
||||||
9D16BCE21D9E070B005EE214 /* speech.s */,
|
9D16BCE21D9E070B005EE214 /* mockingboard_speech.s */,
|
||||||
9D49929C1DB5C5F700606789 /* speech.h */,
|
9D49929C1DB5C5F700606789 /* mockingboard_speech.h */,
|
||||||
9D49929D1DB5C65200606789 /* speech_api.c */,
|
|
||||||
9D49929E1DB5C65200606789 /* speech_api.h */,
|
|
||||||
9DB3C98D1D84A11600395532 /* Makefile */,
|
9DB3C98D1D84A11600395532 /* Makefile */,
|
||||||
9DB3C98E1D84A11600395532 /* make */,
|
9DB3C98E1D84A11600395532 /* make */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
|
||||||
#include "mockingboard.h"
|
#include "mockingboard.h"
|
||||||
#include "speech_api.h"
|
|
||||||
|
|
||||||
|
|
||||||
tMockingSoundRegisters soundData1 = {
|
tMockingSoundRegisters soundData1 = {
|
||||||
|
@ -80,7 +79,7 @@ void delay(void)
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
mockingBoardInit(4);
|
mockingBoardInit(4, false);
|
||||||
|
|
||||||
printf("HELLO, WORLD!\n");
|
printf("HELLO, WORLD!\n");
|
||||||
|
|
||||||
|
@ -96,16 +95,19 @@ int main(void)
|
||||||
|
|
||||||
cgetc();
|
cgetc();
|
||||||
printf("RUN SPEECH TEST (Y/N) ");
|
printf("RUN SPEECH TEST (Y/N) ");
|
||||||
if (cgetc() != 'Y')
|
if (cgetc() == 'Y') {
|
||||||
return 0;
|
printf("\n");
|
||||||
printf("\n");
|
|
||||||
|
mockingBoardInit(4, true);
|
||||||
speakMessage(mySpeechData, sizeof(mySpeechData));
|
mockingBoardSpeak(mySpeechData, sizeof(mySpeechData));
|
||||||
while (speechIsBusy()) {
|
while (mockingBoardSpeechIsBusy()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nDone speaking\n");
|
||||||
|
cgetc();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nDone speaking\n");
|
mockingBoardShutdown();
|
||||||
cgetc();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "mockingboard.h"
|
#include "mockingboard.h"
|
||||||
|
#include "mockingboard_speech.h"
|
||||||
|
|
||||||
|
|
||||||
// Defines
|
// Defines
|
||||||
|
@ -25,20 +26,21 @@
|
||||||
// Globals
|
// Globals
|
||||||
|
|
||||||
// Addresses for the two 6522's (assuming slot 4 for now)
|
// Addresses for the two 6522's (assuming slot 4 for now)
|
||||||
static uint8_t *gMockPortB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc400, (uint8_t *)0xc480 };
|
static uint8_t *gMockPortB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc000, (uint8_t *)0xc080 };
|
||||||
static uint8_t *gMockPortA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc401, (uint8_t *)0xc481 };
|
static uint8_t *gMockPortA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc001, (uint8_t *)0xc081 };
|
||||||
static uint8_t *gMockDataDirB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc402, (uint8_t *)0xc482 };
|
static uint8_t *gMockDataDirB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc002, (uint8_t *)0xc082 };
|
||||||
static uint8_t *gMockDataDirA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc403, (uint8_t *)0xc483 };
|
static uint8_t *gMockDataDirA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc003, (uint8_t *)0xc083 };
|
||||||
|
|
||||||
static uint8_t gMockingBoardInitialized = false;
|
static uint8_t gMockingBoardInitialized = false;
|
||||||
|
static uint8_t gMockingBoardSpeechInitialized = false;
|
||||||
|
|
||||||
|
|
||||||
static uint8_t *mapIOPointer(uint8_t slot, uint8_t *ptr)
|
static uint8_t *mapIOPointer(tSlot slot, uint8_t *ptr)
|
||||||
{
|
{
|
||||||
uint16_t temp1 = (uint16_t)ptr;
|
uint16_t temp1 = (uint16_t)ptr;
|
||||||
uint16_t temp2 = slot;
|
uint16_t temp2 = slot;
|
||||||
|
|
||||||
temp2 << 8;
|
temp2 <<= 8;
|
||||||
temp1 &= 0xf0ff;
|
temp1 &= 0xf0ff;
|
||||||
|
|
||||||
temp1 |= temp2;
|
temp1 |= temp2;
|
||||||
|
@ -46,7 +48,8 @@ static uint8_t *mapIOPointer(uint8_t slot, uint8_t *ptr)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mockingBoardInit(tSlot slot)
|
|
||||||
|
void mockingBoardInit(tSlot slot, bool hasSpeechChip)
|
||||||
{
|
{
|
||||||
tSoundChip soundChip;
|
tSoundChip soundChip;
|
||||||
|
|
||||||
|
@ -55,21 +58,41 @@ void mockingBoardInit(tSlot slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (soundChip = SOUND_CHIP_1; soundChip < NUM_SOUND_CHIPS; soundChip++) {
|
for (soundChip = SOUND_CHIP_1; soundChip < NUM_SOUND_CHIPS; soundChip++) {
|
||||||
#if 0
|
|
||||||
gMockPortB[soundChip] = mapIOPointer(slot, gMockPortB[soundChip]);
|
gMockPortB[soundChip] = mapIOPointer(slot, gMockPortB[soundChip]);
|
||||||
gMockPortA[soundChip] = mapIOPointer(slot, gMockPortA[soundChip]);
|
gMockPortA[soundChip] = mapIOPointer(slot, gMockPortA[soundChip]);
|
||||||
gMockDataDirB[soundChip] = mapIOPointer(slot, gMockDataDirB[soundChip]);
|
gMockDataDirB[soundChip] = mapIOPointer(slot, gMockDataDirB[soundChip]);
|
||||||
gMockDataDirA[soundChip] = mapIOPointer(slot, gMockDataDirA[soundChip]);
|
gMockDataDirA[soundChip] = mapIOPointer(slot, gMockDataDirA[soundChip]);
|
||||||
#endif
|
|
||||||
|
|
||||||
*(gMockDataDirA[soundChip]) = 0xff; // Set port A for output
|
*(gMockDataDirA[soundChip]) = 0xff; // Set port A for output
|
||||||
*(gMockDataDirB[soundChip]) = 0x7; // Set port B for output
|
*(gMockDataDirB[soundChip]) = 0x7; // Set port B for output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasSpeechChip) {
|
||||||
|
if (gMockingBoardSpeechInitialized) {
|
||||||
|
mockingBoardSpeechShutdown();
|
||||||
|
}
|
||||||
|
mockingBoardSpeechInit(slot);
|
||||||
|
gMockingBoardSpeechInitialized = true;
|
||||||
|
} else if (gMockingBoardSpeechInitialized) {
|
||||||
|
mockingBoardSpeechShutdown();
|
||||||
|
gMockingBoardSpeechInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
gMockingBoardInitialized = true;
|
gMockingBoardInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mockingBoardShutdown(void)
|
||||||
|
{
|
||||||
|
if (gMockingBoardSpeechInitialized) {
|
||||||
|
mockingBoardSpeechShutdown();
|
||||||
|
gMockingBoardSpeechInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gMockingBoardInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void writeCommand(tSoundChip soundChip, uint8_t command)
|
static void writeCommand(tSoundChip soundChip, uint8_t command)
|
||||||
{
|
{
|
||||||
volatile uint8_t *ptr = gMockPortB[soundChip];
|
volatile uint8_t *ptr = gMockPortB[soundChip];
|
||||||
|
@ -103,6 +126,9 @@ void mockingBoardTableAccess(tSoundChip soundChip, tMockingSoundRegisters *regis
|
||||||
volatile uint8_t *ptr = gMockPortA[soundChip];
|
volatile uint8_t *ptr = gMockPortA[soundChip];
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
|
|
||||||
|
if (!gMockingBoardInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
mockingBoardReset(soundChip);
|
mockingBoardReset(soundChip);
|
||||||
for (index = 0; index < 16; index++) {
|
for (index = 0; index < 16; index++) {
|
||||||
*ptr = index;
|
*ptr = index;
|
||||||
|
@ -112,3 +138,31 @@ void mockingBoardTableAccess(tSoundChip soundChip, tMockingSoundRegisters *regis
|
||||||
data++;
|
data++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool mockingBoardSpeechIsBusy(void)
|
||||||
|
{
|
||||||
|
return (mockingBoardSpeechBusy != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool mockingBoardSpeechIsPlaying(void)
|
||||||
|
{
|
||||||
|
return (mockingBoardSpeechPlaying != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen)
|
||||||
|
{
|
||||||
|
if (!gMockingBoardSpeechInitialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mockingBoardSpeechIsBusy())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mockingBoardSpeechData = data;
|
||||||
|
mockingBoardSpeechLen = dataLen + 1;
|
||||||
|
mockingBoardSpeakPriv();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define __mocktest__mockingboard__
|
#define __mocktest__mockingboard__
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,13 +112,18 @@ typedef struct tMockingSoundRegisters {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
void mockingBoardInit(tSlot slot);
|
extern void mockingBoardInit(tSlot slot, bool hasSpeechChip);
|
||||||
|
extern void mockingBoardShutdown(void);
|
||||||
|
|
||||||
void mockingBoardLatch(tSoundChip soundChip);
|
extern void mockingBoardLatch(tSoundChip soundChip);
|
||||||
void mockingBoardWrite(tSoundChip soundChip);
|
extern void mockingBoardWrite(tSoundChip soundChip);
|
||||||
void mockingBoardReset(tSoundChip soundChip);
|
extern void mockingBoardReset(tSoundChip soundChip);
|
||||||
|
|
||||||
void mockingBoardTableAccess(tSoundChip soundChip, tMockingSoundRegisters *registers);
|
extern void mockingBoardTableAccess(tSoundChip soundChip, tMockingSoundRegisters *registers);
|
||||||
|
|
||||||
|
extern bool mockingBoardSpeechIsBusy(void);
|
||||||
|
extern bool mockingBoardSpeechIsPlaying(void);
|
||||||
|
extern bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen);
|
||||||
|
|
||||||
|
|
||||||
#endif /* defined(__mocktest__mockingboard__) */
|
#endif /* defined(__mocktest__mockingboard__) */
|
||||||
|
|
26
mocktest/mockingboard_speech.h
Normal file
26
mocktest/mockingboard_speech.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// mockingboard_speech.h
|
||||||
|
// mocktest
|
||||||
|
//
|
||||||
|
// Created by Jeremy Rand on 2016-10-17.
|
||||||
|
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef mockingboard_speech_h
|
||||||
|
#define mockingboard_speech_h
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t *mockingBoardSpeechData;
|
||||||
|
extern uint16_t mockingBoardSpeechLen;
|
||||||
|
extern uint8_t mockingBoardSpeechBusy;
|
||||||
|
extern uint8_t mockingBoardSpeechPlaying;
|
||||||
|
|
||||||
|
extern void mockingBoardSpeechInit(uint8_t slot);
|
||||||
|
extern void mockingBoardSpeechShutdown(void);
|
||||||
|
extern void mockingBoardSpeakPriv(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* mockingboard_speech_h */
|
288
mocktest/mockingboard_speech.s
Normal file
288
mocktest/mockingboard_speech.s
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
;
|
||||||
|
; speech.s
|
||||||
|
; mocktest
|
||||||
|
;
|
||||||
|
; Created by Jeremy Rand on 2016-09-29.
|
||||||
|
; Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
.export _mockingBoardSpeechInit, _mockingBoardSpeechShutdown, _mockingBoardSpeakPriv
|
||||||
|
.export _mockingBoardSpeechData, _mockingBoardSpeechLen
|
||||||
|
.export _mockingBoardSpeechBusy, _mockingBoardSpeechPlaying
|
||||||
|
|
||||||
|
|
||||||
|
TMPPTR := $FB ; Temporary pointer used in interrupt handler
|
||||||
|
IRQL := $03FE ; Interrupt vector, low byte
|
||||||
|
IRQH := $03FF ; Interrupt vector, high byte
|
||||||
|
BASE := $40 ; First speech chip
|
||||||
|
DURPHON := BASE ; Register 0 of speech chip
|
||||||
|
INFLECT := BASE+$01 ; Register 1 of speech chip
|
||||||
|
RATEINF := BASE+$02 ; Register 2 of speech chip
|
||||||
|
CTTRAMP := BASE+$03 ; Register 3 of speech chip
|
||||||
|
FILFREQ := BASE+$04 ; Register 4 of speech chip
|
||||||
|
DDRB := $02
|
||||||
|
DDRA := $03
|
||||||
|
PCR := $8C ; Peripheral control register, 6522
|
||||||
|
IFR := $8D ; Interrupt flag register, 6522
|
||||||
|
IER := $8E
|
||||||
|
|
||||||
|
|
||||||
|
.DATA
|
||||||
|
_mockingBoardSpeechData: .byte $00, $00
|
||||||
|
_mockingBoardSpeechLen: .byte $00, $00
|
||||||
|
_outptr: .byte $00, $00
|
||||||
|
_endptr: .byte $00, $00
|
||||||
|
_mockingBoardSpeechBusy: .byte $00
|
||||||
|
_mockingBoardSpeechPlaying: .byte $00
|
||||||
|
_irqLandingPad: .byte $4C, $00, $00
|
||||||
|
|
||||||
|
|
||||||
|
.CODE
|
||||||
|
|
||||||
|
writeChip:
|
||||||
|
sta $C000,X
|
||||||
|
rts
|
||||||
|
|
||||||
|
readChip:
|
||||||
|
lda $C000,X
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
.proc _mockingBoardSpeechInit
|
||||||
|
sei
|
||||||
|
|
||||||
|
; The accumulator has the slot number of the mockingboard.
|
||||||
|
; Turn that into the address of the slot and set the address
|
||||||
|
; in the read and write functions.
|
||||||
|
and #$7
|
||||||
|
ora #$c0
|
||||||
|
sta writeChip+2
|
||||||
|
sta readChip+2
|
||||||
|
|
||||||
|
; Save the old interrupt vector
|
||||||
|
lda IRQL
|
||||||
|
sta _irqLandingPad+1
|
||||||
|
lda IRQH
|
||||||
|
sta _irqLandingPad+2
|
||||||
|
|
||||||
|
; Set the interrupt vector to point to the interrupt service
|
||||||
|
; routine.
|
||||||
|
lda #<_interr
|
||||||
|
sta IRQL
|
||||||
|
lda #>_interr
|
||||||
|
sta IRQH
|
||||||
|
cli
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
|
||||||
|
.proc _mockingBoardSpeechShutdown
|
||||||
|
sei
|
||||||
|
|
||||||
|
; Restore the old interrupt vector
|
||||||
|
lda _irqLandingPad+1
|
||||||
|
sta IRQL
|
||||||
|
lda _irqLandingPad+2
|
||||||
|
sta IRQH
|
||||||
|
cli
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
|
||||||
|
.proc _mockingBoardSpeakPriv
|
||||||
|
sei
|
||||||
|
lda #$00
|
||||||
|
ldx #DDRA
|
||||||
|
jsr writeChip
|
||||||
|
ldx #DDRB
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Get the starting address of the data and store in the work pointer
|
||||||
|
lda _mockingBoardSpeechData+1
|
||||||
|
sta _outptr+1
|
||||||
|
lda _mockingBoardSpeechData
|
||||||
|
sta _outptr
|
||||||
|
|
||||||
|
; Calculate the end address from the start address and the length
|
||||||
|
lda _mockingBoardSpeechLen+1
|
||||||
|
clc
|
||||||
|
adc _mockingBoardSpeechData+1
|
||||||
|
sta _endptr+1
|
||||||
|
lda _mockingBoardSpeechLen
|
||||||
|
clc
|
||||||
|
adc _mockingBoardSpeechData
|
||||||
|
bcc @L2
|
||||||
|
inc _endptr+1
|
||||||
|
@L2:
|
||||||
|
sta _endptr
|
||||||
|
|
||||||
|
; Set the busy flag
|
||||||
|
lda #$FF
|
||||||
|
sta _mockingBoardSpeechBusy
|
||||||
|
|
||||||
|
; Set peripheral control register to recognize the signal from the
|
||||||
|
; speech chip.
|
||||||
|
lda #$0C
|
||||||
|
ldx #PCR
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Raise control bit in register 3
|
||||||
|
lda #$80
|
||||||
|
ldx #CTTRAMP
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Set transitioned inflection mode in register 0
|
||||||
|
lda #$C0
|
||||||
|
ldx #DURPHON
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Lower control bit
|
||||||
|
lda #$70
|
||||||
|
ldx #CTTRAMP
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Enable 6522 interrupts
|
||||||
|
lda #$82
|
||||||
|
ldx #IER
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
cli
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
|
||||||
|
.proc _interr
|
||||||
|
; Save the accumulator and X registers
|
||||||
|
pha
|
||||||
|
txa
|
||||||
|
pha
|
||||||
|
|
||||||
|
; If we have a 6522 interrupt, jump to L4.
|
||||||
|
ldx #IFR
|
||||||
|
jsr readChip
|
||||||
|
bmi @L4
|
||||||
|
|
||||||
|
; Otherwise restore the accumulator and X registers and jump
|
||||||
|
; to the old interrupt handler.
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
pla
|
||||||
|
jmp _irqLandingPad
|
||||||
|
|
||||||
|
@L4:
|
||||||
|
; Save the Y register also
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
|
||||||
|
; Clear the interrupt flag
|
||||||
|
lda #$02
|
||||||
|
ldx #IFR
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Check for end of data file. If not the end, jump to L1
|
||||||
|
lda _outptr+1
|
||||||
|
cmp _endptr+1
|
||||||
|
bcc @L1
|
||||||
|
bne @L5
|
||||||
|
lda _outptr
|
||||||
|
cmp _endptr
|
||||||
|
bcc @L1
|
||||||
|
|
||||||
|
@L5:
|
||||||
|
|
||||||
|
; If at the end, turn everything off. Store a pause phoneme.
|
||||||
|
lda #$00
|
||||||
|
ldx #DURPHON
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Zero amplitude
|
||||||
|
lda #$70
|
||||||
|
ldx #CTTRAMP
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Clear busy and playing flags
|
||||||
|
lda #$00
|
||||||
|
sta _mockingBoardSpeechBusy
|
||||||
|
sta _mockingBoardSpeechPlaying
|
||||||
|
|
||||||
|
; Clear interrupt enable in 6522
|
||||||
|
lda #$02
|
||||||
|
ldx #IER
|
||||||
|
jsr writeChip
|
||||||
|
lda #$FF
|
||||||
|
ldx #DDRA
|
||||||
|
jsr writeChip
|
||||||
|
lda #$07
|
||||||
|
ldx #DDRB
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
@L2:
|
||||||
|
; Restore registers
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
pla
|
||||||
|
|
||||||
|
; Return from interrupt
|
||||||
|
rti
|
||||||
|
|
||||||
|
@L1:
|
||||||
|
|
||||||
|
; Set the speach playing flag
|
||||||
|
lda #$ff
|
||||||
|
sta _mockingBoardSpeechPlaying
|
||||||
|
|
||||||
|
; Save the value of the tmp pointer on the stack
|
||||||
|
lda TMPPTR
|
||||||
|
pha
|
||||||
|
lda TMPPTR+1
|
||||||
|
pha
|
||||||
|
|
||||||
|
; Move the _outptr into the tmp pointer
|
||||||
|
lda _outptr
|
||||||
|
sta TMPPTR
|
||||||
|
lda _outptr+1
|
||||||
|
sta TMPPTR+1
|
||||||
|
|
||||||
|
; Init registers
|
||||||
|
ldy #$00
|
||||||
|
ldx #FILFREQ
|
||||||
|
|
||||||
|
@L6:
|
||||||
|
; Get the next data
|
||||||
|
lda (TMPPTR),Y
|
||||||
|
|
||||||
|
; Store in the speech chip
|
||||||
|
jsr writeChip
|
||||||
|
|
||||||
|
; Next data
|
||||||
|
inc TMPPTR
|
||||||
|
bne @L3
|
||||||
|
inc TMPPTR+1
|
||||||
|
|
||||||
|
@L3:
|
||||||
|
; Go to next register
|
||||||
|
dex
|
||||||
|
|
||||||
|
; If we are not done the last register, then loop back to L6
|
||||||
|
cpx #BASE-1
|
||||||
|
bne @L6
|
||||||
|
|
||||||
|
; We are done writing so move the tmp pointer back into _outptr
|
||||||
|
lda TMPPTR
|
||||||
|
sta _outptr
|
||||||
|
lda TMPPTR+1
|
||||||
|
sta _outptr+1
|
||||||
|
|
||||||
|
; Restore the tmp pointer from the stack
|
||||||
|
pla
|
||||||
|
sta TMPPTR+1
|
||||||
|
pla
|
||||||
|
sta TMPPTR
|
||||||
|
|
||||||
|
; Finish the interrupt handler
|
||||||
|
jmp @L2
|
||||||
|
.endproc
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
//
|
|
||||||
// speech.h
|
|
||||||
// mocktest
|
|
||||||
//
|
|
||||||
// Created by Jeremy Rand on 2016-10-17.
|
|
||||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef speech_h
|
|
||||||
#define speech_h
|
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t *speechData;
|
|
||||||
extern uint16_t speechLen;
|
|
||||||
extern uint8_t speechBusy;
|
|
||||||
|
|
||||||
extern void setupSpeech(void);
|
|
||||||
extern void unsetupSpeech(void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* speech_h */
|
|
|
@ -1,175 +0,0 @@
|
||||||
;
|
|
||||||
; speech.s
|
|
||||||
; mocktest
|
|
||||||
;
|
|
||||||
; Created by Jeremy Rand on 2016-09-29.
|
|
||||||
; Copyright © 2016 Jeremy Rand. All rights reserved.
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
.export _setupSpeech, _unsetupSpeech
|
|
||||||
.export _speechData, _speechLen, _speechBusy
|
|
||||||
|
|
||||||
|
|
||||||
TMPPTR := $FB ; Temporary pointer used in interrupt handler
|
|
||||||
IRQL := $03FE ; Interrupt vector, low byte
|
|
||||||
IRQH := $03FF ; Interrupt vector, high byte
|
|
||||||
BASE := $C440 ; First speech chip
|
|
||||||
DURPHON := BASE ; Register 0 of speech chip
|
|
||||||
INFLECT := BASE+$01 ; Register 1 of speech chip
|
|
||||||
RATEINF := BASE+$02 ; Register 2 of speech chip
|
|
||||||
CTTRAMP := BASE+$03 ; Register 3 of speech chip
|
|
||||||
FILFREQ := BASE+$04 ; Register 4 of speech chip
|
|
||||||
DDRB := $C402
|
|
||||||
DDRA := $C403
|
|
||||||
PCR := $C48C ; Peripheral control register, 6522
|
|
||||||
IFR := $C48D ; Interrupt flag register, 6522
|
|
||||||
IER := $C48E
|
|
||||||
|
|
||||||
|
|
||||||
.DATA
|
|
||||||
_speechData: .byte $00, $00
|
|
||||||
_speechLen: .byte $00, $00
|
|
||||||
_outptr: .byte $00, $00
|
|
||||||
_endptr: .byte $00, $00
|
|
||||||
_speechBusy: .byte $00
|
|
||||||
_irqLandingPad: .byte $4C, $00, $00
|
|
||||||
|
|
||||||
|
|
||||||
.CODE
|
|
||||||
|
|
||||||
.proc _setupSpeech
|
|
||||||
sei ; Disable interrupts
|
|
||||||
|
|
||||||
lda IRQL ; Store the old interrupt vector
|
|
||||||
sta _irqLandingPad+1
|
|
||||||
lda IRQH
|
|
||||||
sta _irqLandingPad+2
|
|
||||||
|
|
||||||
lda #<_interr ; Set interrupt vector
|
|
||||||
sta IRQL ; to point to interrupt
|
|
||||||
lda #>_interr ; service routine
|
|
||||||
sta IRQH
|
|
||||||
lda #$00
|
|
||||||
sta DDRA
|
|
||||||
sta DDRB
|
|
||||||
|
|
||||||
lda _speechData+1 ; Get high address of data
|
|
||||||
sta _outptr+1 ; Store in work pointer
|
|
||||||
lda _speechData ; Get low address of data
|
|
||||||
sta _outptr ; Store low byte
|
|
||||||
|
|
||||||
lda _speechLen+1 ; Get high length byte
|
|
||||||
clc
|
|
||||||
adc _speechData+1 ; And add to base address
|
|
||||||
sta _endptr+1 ; Store end address
|
|
||||||
lda _speechLen ; Get low length byte
|
|
||||||
clc
|
|
||||||
adc _speechData ; And add to base address
|
|
||||||
bcc @L2 ; Check for page boundary
|
|
||||||
inc _endptr+1
|
|
||||||
@L2:
|
|
||||||
sta _endptr ; Store end address
|
|
||||||
|
|
||||||
lda #$FF ; Set busy flag
|
|
||||||
sta _speechBusy ; And set peripheral control
|
|
||||||
lda #$0C ; Register to recognize
|
|
||||||
sta PCR ; Signal from speech chip
|
|
||||||
lda #$80 ; Raise control bit in register 3
|
|
||||||
sta CTTRAMP
|
|
||||||
lda #$C0 ; Set transitioned inflection
|
|
||||||
sta DURPHON ; Mode in register 0
|
|
||||||
lda #$70 ; Lower control bit
|
|
||||||
sta CTTRAMP
|
|
||||||
lda #$82 ; Enable 6522 interrupts
|
|
||||||
sta IER
|
|
||||||
cli ; Clear interrupt mask
|
|
||||||
rts ; Return to caller
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
|
|
||||||
.proc _unsetupSpeech
|
|
||||||
sei ; Restore the old interrupt vector
|
|
||||||
lda _irqLandingPad+1
|
|
||||||
sta IRQL
|
|
||||||
lda _irqLandingPad+2
|
|
||||||
sta IRQH
|
|
||||||
cli
|
|
||||||
rts
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
|
|
||||||
.proc _interr
|
|
||||||
pha ; Save accumulator
|
|
||||||
lda IFR
|
|
||||||
bmi @L4 ; If we have 6522 interrupt jump to L4
|
|
||||||
pla ; Otherwise restore the accumulator
|
|
||||||
jmp _irqLandingPad ; And jump to the old interrupt handler
|
|
||||||
@L4:
|
|
||||||
txa ; Save other registers
|
|
||||||
pha
|
|
||||||
tya
|
|
||||||
pha
|
|
||||||
lda #$02 ; Clear interrupt flag
|
|
||||||
sta IFR
|
|
||||||
ldy #$00 ; Init registers
|
|
||||||
ldx #$04
|
|
||||||
lda _outptr+1
|
|
||||||
cmp _endptr+1
|
|
||||||
bcc @L1
|
|
||||||
bne @L5
|
|
||||||
lda _outptr ; Check for end of data file
|
|
||||||
cmp _endptr
|
|
||||||
bcc @L1 ; If not, then continue
|
|
||||||
@L5:
|
|
||||||
lda #$00 ; If end, turn everything off
|
|
||||||
sta DURPHON ; Store pause phoneme
|
|
||||||
lda #$70 ; Zero amplitude
|
|
||||||
sta CTTRAMP
|
|
||||||
lda #$00 ; Clear busy flag
|
|
||||||
sta _speechBusy
|
|
||||||
lda #$02 ; Clear interrupt enable
|
|
||||||
sta IER ; In 6522
|
|
||||||
lda #$FF
|
|
||||||
sta DDRA
|
|
||||||
lda #$07
|
|
||||||
sta DDRB
|
|
||||||
@L2:
|
|
||||||
pla ; Restore registers
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
rti ; Return from interrupt
|
|
||||||
|
|
||||||
@L1:
|
|
||||||
lda TMPPTR ; Save the value in the tmp pointer
|
|
||||||
pha
|
|
||||||
lda TMPPTR+1
|
|
||||||
pha
|
|
||||||
lda _outptr ; Move the _outptr into the tmp pointer
|
|
||||||
sta TMPPTR
|
|
||||||
lda _outptr+1
|
|
||||||
sta TMPPTR+1
|
|
||||||
@L6:
|
|
||||||
lda (TMPPTR),Y ; Get data
|
|
||||||
sta BASE,X ; Store in speech chip
|
|
||||||
inc TMPPTR ; Next data
|
|
||||||
bne @L3
|
|
||||||
inc TMPPTR+1
|
|
||||||
|
|
||||||
@L3:
|
|
||||||
dex ; Next register
|
|
||||||
cpx #$FF ; Last register?
|
|
||||||
bne @L6 ; No, then continue
|
|
||||||
lda TMPPTR ; We are done, move tmp pointer to _outptr
|
|
||||||
sta _outptr
|
|
||||||
lda TMPPTR+1
|
|
||||||
sta _outptr+1
|
|
||||||
pla ; Restore the tmp pointer
|
|
||||||
sta TMPPTR+1
|
|
||||||
pla
|
|
||||||
sta TMPPTR
|
|
||||||
jmp @L2 ; Finish the interrupt handler
|
|
||||||
.endproc
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// speech_api.c
|
|
||||||
// mocktest
|
|
||||||
//
|
|
||||||
// Created by Jeremy Rand on 2016-10-17.
|
|
||||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "speech_api.h"
|
|
||||||
#include "speech.h"
|
|
||||||
|
|
||||||
|
|
||||||
bool speechIsBusy(void)
|
|
||||||
{
|
|
||||||
return (speechBusy != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool speakMessage(uint8_t *data, uint16_t dataLen)
|
|
||||||
{
|
|
||||||
if (speechIsBusy())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
speechData = data;
|
|
||||||
speechLen = dataLen + 1;
|
|
||||||
setupSpeech();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
//
|
|
||||||
// speech_api.h
|
|
||||||
// mocktest
|
|
||||||
//
|
|
||||||
// Created by Jeremy Rand on 2016-10-17.
|
|
||||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef __mocktest__speech_api__
|
|
||||||
#define __mocktest__speech_api__
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
extern bool speechIsBusy(void);
|
|
||||||
extern bool speakMessage(uint8_t *data, uint16_t dataLen);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* defined(__mocktest__speech_api__) */
|
|
Loading…
Reference in New Issue
Block a user