Initial commit with basic sound and speech support.

This commit is contained in:
Jeremy Rand 2016-09-30 23:06:47 -04:00
parent d871fb4660
commit 84ddb58602
8 changed files with 506 additions and 1 deletions

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXFileReference section */
9D16BCE21D9E070B005EE214 /* speech.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = speech.s; 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>"; };
9DB3C98F1D84A11600395532 /* AppleCommander.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = AppleCommander.jar; path = make/AppleCommander.jar; sourceTree = "<group>"; };
@ -17,6 +18,8 @@
9DB3C9941D84A11600395532 /* prodos_template.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; name = prodos_template.dsk; path = make/prodos_template.dsk; sourceTree = "<group>"; };
9DB3C9951D84A11600395532 /* tail.mk */ = {isa = PBXFileReference; lastKnownFileType = text; name = tail.mk; path = make/tail.mk; sourceTree = "<group>"; };
9DB3C9961D84A11600395532 /* V2Make.scpt */ = {isa = PBXFileReference; lastKnownFileType = file; name = V2Make.scpt; path = make/V2Make.scpt; sourceTree = "<group>"; };
9DB3C99C1D84A21E00395532 /* mockingboard.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mockingboard.c; sourceTree = "<group>"; };
9DB3C99D1D84A21E00395532 /* mockingboard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mockingboard.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
@ -31,6 +34,9 @@
isa = PBXGroup;
children = (
9DB3C98C1D84A11600395532 /* main.c */,
9DB3C99C1D84A21E00395532 /* mockingboard.c */,
9DB3C99D1D84A21E00395532 /* mockingboard.h */,
9D16BCE21D9E070B005EE214 /* speech.s */,
9DB3C98D1D84A11600395532 /* Makefile */,
9DB3C98E1D84A11600395532 /* make */,
);
@ -223,6 +229,7 @@
9DB3C99B1D84A11600395532 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};

View File

@ -5,6 +5,22 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9DB3C98A1D84A11600395532"
BuildableName = "mocktest"
BlueprintName = "mocktest"
ReferencedContainer = "container:mocktest.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
@ -26,6 +42,15 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9DB3C98A1D84A11600395532"
BuildableName = "mocktest"
BlueprintName = "mocktest"
ReferencedContainer = "container:mocktest.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
@ -35,6 +60,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9DB3C98A1D84A11600395532"
BuildableName = "mocktest"
BlueprintName = "mocktest"
ReferencedContainer = "container:mocktest.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@ -25,7 +25,7 @@ PGM=mocktest
# Uncomment the one you want below (the first one is the default):
# MACHINE = apple2
# MACHINE = apple2-dos33
# MACHINE = apple2-system
MACHINE = apple2-system
# MACHINE = apple2-loader
# MACHINE = apple2-reboot
# MACHINE = apple2enh

View File

@ -8,13 +8,105 @@
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <conio.h>
#include "mockingboard.h"
extern void setupSpeech(void);
uint8_t **tabPtr = (uint8_t **)0x00f9;
tMockingSoundRegisters soundData1 = {
{ TONE_PERIOD_A(4), 0, 0 }, // Tone period for the three channels
MIN_NOISE_PERIOD, // Noise period
ENABLE_CHANNEL(TONE_CHANNEL_A), // Enable
{ MAX_AMPLITUDE, MIN_AMPLITUDE, MIN_AMPLITUDE }, // Amplitude for the three channels
MIN_ENVELOPE_PERIOD, // Envelope period
ENVELOPE_SHAPE_ONE_SHOT_DECAY, // Envelope shape
0, // Dummy1
0 // Dummy2
};
tMockingSoundRegisters soundData2 = {
{ TONE_PERIOD_F_SHARP(3), 0, 0 }, // Tone period for the three channels
MIN_NOISE_PERIOD, // Noise period
ENABLE_CHANNEL(TONE_CHANNEL_A), // Enable
{ MAX_AMPLITUDE, MIN_AMPLITUDE, MIN_AMPLITUDE }, // Amplitude for the three channels
MIN_ENVELOPE_PERIOD, // Envelope period
ENVELOPE_SHAPE_ONE_SHOT_DECAY, // Envelope shape
0, // Dummy1
0 // Dummy2
};
uint8_t speechData[] = {
0xCF, 0x00, 0xE8, 0x70, 0xA8, 0x5F, 0x00, 0xE8,
0x70, 0xA8, 0x5F, 0x00, 0xE8, 0x70, 0xA8, 0x5F,
0x00, 0xE8, 0x7B, 0xA8, 0x5F, 0x63, 0xE7, 0x6B,
0xA8, 0x59, 0x47, 0xE8, 0x6A, 0xA8, 0x61, 0x36,
0xE8, 0x79, 0xA8, 0x65, 0x37, 0xE7, 0x79, 0xA8,
0x69, 0x0E, 0xE7, 0x6A, 0xA8, 0x61, 0x29, 0xE8,
0x6B, 0xA8, 0x59, 0xAD, 0xE8, 0x6B, 0xA8, 0x51,
0xC0, 0xE8, 0x6A, 0xA8, 0x51, 0x07, 0xE8, 0x6A,
0xA8, 0x4B, 0x39, 0xE8, 0x6A, 0xA8, 0x49, 0x64,
0xE7, 0x6A, 0x88, 0x49, 0x11, 0xE7, 0x5A, 0xB8,
0x51, 0x63, 0xE7, 0x5A, 0xB8, 0x59, 0x1D, 0xE8,
0x7A, 0xA8, 0x61, 0x65, 0xE8, 0x79, 0xA8, 0x61,
0xC0, 0xE8, 0x70, 0x78, 0x51, 0x00, 0xE8, 0x70,
0x78, 0x51, 0x00, 0xE8, 0x70, 0x78, 0x59, 0x00,
0xE7, 0x79, 0xA8, 0x65, 0x04, 0xE7, 0x6A, 0x98,
0x61, 0x16, 0xE8, 0x6B, 0xA8, 0x61, 0x60, 0xE8,
0x7C, 0xA8, 0x59, 0x78, 0xE7, 0x7C, 0xA8, 0x55,
0x0A, 0xE8, 0x6B, 0xA8, 0x62, 0x33, 0xE8, 0x6A,
0xA8, 0x59, 0x1C, 0xE8, 0x7A, 0xA8, 0x51, 0x64,
0xE7, 0x7B, 0x88, 0x51, 0x01, 0xE8, 0x7C, 0xA8,
0x59, 0x30, 0xE8, 0x7D, 0xA8, 0x59, 0x27, 0xE7,
0x7D, 0x78, 0x61, 0x01, 0xE8, 0x6C, 0xA8, 0x61,
0x28, 0xE8, 0x6B, 0xA8, 0x59, 0x32, 0xE8, 0x6A,
0xA8, 0x4D, 0x60, 0xE7, 0x29, 0xA8, 0x41, 0x0A,
0xE8, 0x78, 0xA8, 0x41, 0x30, 0xE8, 0x70, 0xA8,
0x39, 0xFF, 0xE8, 0x70, 0xA8, 0x39, 0x00, 0xE8,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
void delay(void)
{
int i;
for (i = 0; i < 1000; i++) ;
}
int main(void)
{
mockingBoardInit(4);
printf("HELLO, WORLD!\n");
while (!kbhit()) {
mockingBoardTableAccess(SOUND_CHIP_1, &soundData1);
delay();
mockingBoardReset(SOUND_CHIP_1);
mockingBoardTableAccess(SOUND_CHIP_2, &soundData2);
delay();
mockingBoardReset(SOUND_CHIP_2);
}
cgetc();
printf("RUN SPEECH TEST (Y/N) ");
if (cgetc() != 'Y')
return 0;
*tabPtr = speechData;
setupSpeech();
cgetc();
return 0;
}

Binary file not shown.

114
mocktest/mockingboard.c Normal file
View File

@ -0,0 +1,114 @@
//
// mockingboard.c
// mocktest
//
// Created by Jeremy Rand on 2016-09-10.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "mockingboard.h"
// Defines
#define LATCH_COMMAND 0x7
#define WRITE_COMMAND 0x6
#define RESET_COMMAND 0x0
#define THROUGH_PORT_B 0x4
// Globals
// 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 *gMockPortA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc401, (uint8_t *)0xc481 };
static uint8_t *gMockDataDirB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc402, (uint8_t *)0xc482 };
static uint8_t *gMockDataDirA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc403, (uint8_t *)0xc483 };
static uint8_t gMockingBoardInitialized = false;
static uint8_t *mapIOPointer(uint8_t slot, uint8_t *ptr)
{
uint16_t temp1 = (uint16_t)ptr;
uint16_t temp2 = slot;
temp2 << 8;
temp1 &= 0xf0ff;
temp1 |= temp2;
ptr = (uint8_t *)temp1;
return ptr;
}
void mockingBoardInit(tSlot slot)
{
tSoundChip soundChip;
if (sizeof(tMockingSoundRegisters) != 16) {
printf("The sound registers must be 16 bytes long!\n");
}
for (soundChip = SOUND_CHIP_1; soundChip < NUM_SOUND_CHIPS; soundChip++) {
#if 0
gMockPortB[soundChip] = mapIOPointer(slot, gMockPortB[soundChip]);
gMockPortA[soundChip] = mapIOPointer(slot, gMockPortA[soundChip]);
gMockDataDirB[soundChip] = mapIOPointer(slot, gMockDataDirB[soundChip]);
gMockDataDirA[soundChip] = mapIOPointer(slot, gMockDataDirA[soundChip]);
#endif
*(gMockDataDirA[soundChip]) = 0xff; // Set port A for output
*(gMockDataDirB[soundChip]) = 0x7; // Set port B for output
}
gMockingBoardInitialized = true;
}
static void writeCommand(tSoundChip soundChip, uint8_t command)
{
volatile uint8_t *ptr = gMockPortB[soundChip];
*ptr = command;
*ptr = THROUGH_PORT_B;
}
void mockingBoardLatch(tSoundChip soundChip)
{
writeCommand(soundChip, LATCH_COMMAND);
}
void mockingBoardWrite(tSoundChip soundChip)
{
writeCommand(soundChip, WRITE_COMMAND);
}
void mockingBoardReset(tSoundChip soundChip)
{
writeCommand(soundChip, RESET_COMMAND);
}
void mockingBoardTableAccess(tSoundChip soundChip, tMockingSoundRegisters *registers)
{
uint8_t *data = (uint8_t *)registers;
volatile uint8_t *ptr = gMockPortA[soundChip];
uint8_t index;
mockingBoardReset(soundChip);
for (index = 0; index < 16; index++) {
*ptr = index;
mockingBoardLatch(soundChip);
*ptr = *data;
mockingBoardWrite(soundChip);
data++;
}
}

123
mocktest/mockingboard.h Normal file
View File

@ -0,0 +1,123 @@
//
// mockingboard.h
// mocktest
//
// Created by Jeremy Rand on 2016-09-10.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#ifndef __mocktest__mockingboard__
#define __mocktest__mockingboard__
#include <stdint.h>
// Defines
#define MOCK_NUM_CHANNELS 3
#define TONE_PERIOD_C(octave) (0x7a3 >> (octave - 1))
#define TONE_PERIOD_C_SHARP(octave) (0x735 >> (octave - 1))
#define TONE_PERIOD_D(octave) (0x6cd >> (octave - 1))
#define TONE_PERIOD_D_SHARP(octave) (0x66c >> (octave - 1))
#define TONE_PERIOD_E(octave) (0x60f >> (octave - 1))
#define TONE_PERIOD_F(octave) (0x5b8 >> (octave - 1))
#define TONE_PERIOD_F_SHARP(octave) (0x566 >> (octave - 1))
#define TONE_PERIOD_G(octave) (0x518 >> (octave - 1))
#define TONE_PERIOD_G_SHARP(octave) (0x4cf >> (octave - 1))
#define TONE_PERIOD_A(octave) (0x48a >> (octave - 1))
#define TONE_PERIOD_A_SHARP(octave) (0x449 >> (octave - 1))
#define TONE_PERIOD_B(octave) (0x40b >> (octave - 1))
#define MIN_NOISE_PERIOD 0
#define MAX_NOISE_PERIOD 31
#define TONE_CHANNEL_A 1
#define TONE_CHANNEL_B 2
#define TONE_CHANNEL_C 4
#define NOISE_CHANNEL_A 8
#define NOISE_CHANNLE_B 16
#define NOISE_CHANNEL_C 32
#define ENABLE_CHANNEL(channels) (0x3f ^ (channels))
#define MIN_AMPLITUDE 0
#define MAX_AMPLITUDE 15
#define VARIABLE_AMPLITUDE 16
#define MIN_ENVELOPE_PERIOD 0
#define MAX_ENVELOPE_PERIOD 65535u
#define MILLISEC_TO_ENVELOP_PERIOD(ms) ((ms) * 4)
// Here is a table of the envelope shapes and how they look:
//
// ENVELOPE_SHAPE_ONE_SHOT_DECAY \__________...
//
// ENVELOPE_SHAPE_ONE_SHOT_ATTACK /__________...
//
// ENVELOPE_SHAPE_CONT_DECAY \|\|\|\|\|\...
//
// ENVELOPE_SHAPE_CONT_DECAY_HOLD \__________...
//
// ENVELOPE_SHAPE_CONT_DECAY_ALT \/\/\/\/\/\...
// _________
// ENVELOPE_SHAPE_CONT_DECAY_ALT_HOLD \| ...
//
// ENVELOPE_SHAPE_CONT_ATTACK /|/|/|/|/|/...
// __________
// ENVELOPE_SHAPE_CONT_ATTACK_HOLD / ...
// ENVELOPE_SHAPE_CONT_ATTACK_ALT /\/\/\/\/\/...
//
// ENVELOPE_SHAPE_CONT_ATTACK_ALT_HOLD /|_________...
#define ENVELOPE_SHAPE_ONE_SHOT_DECAY 0
#define ENVELOPE_SHAPE_ONE_SHOT_ATTACK 4
#define ENVELOPE_SHAPE_CONT_DECAY 8
#define ENVELOPE_SHAPE_CONT_DECAY_HOLD 9
#define ENVELOPE_SHAPE_CONT_DECAY_ALT 10
#define ENVELOPE_SHAPE_CONT_DECAY_ALT_HOLD 11
#define ENVELOPE_SHAPE_CONT_ATTACK 12
#define ENVELOPE_SHAPE_CONT_ATTACK_HOLD 13
#define ENVELOPE_SHAPE_CONT_ATTACK_ALT 14
#define ENVELOPE_SHAPE_CONT_ATTACK_ALT_HOLD 15
// Typedefs
typedef uint8_t tSlot;
typedef enum {
SOUND_CHIP_1 = 0,
SOUND_CHIP_2 = 1,
NUM_SOUND_CHIPS = 2
} tSoundChip;
typedef struct tMockingSoundRegisters {
uint16_t tonePeriod[MOCK_NUM_CHANNELS];
uint8_t noisePeriod;
uint8_t enable;
uint8_t amplitude[MOCK_NUM_CHANNELS];
uint16_t envelopePeriod;
uint8_t envelopeShape;
uint8_t dummy1;
uint8_t dummy2;
} tMockingSoundRegisters;
// API
void mockingBoardInit(tSlot slot);
void mockingBoardLatch(tSoundChip soundChip);
void mockingBoardWrite(tSoundChip soundChip);
void mockingBoardReset(tSoundChip soundChip);
void mockingBoardTableAccess(tSoundChip soundChip, tMockingSoundRegisters *registers);
#endif /* defined(__mocktest__mockingboard__) */

135
mocktest/speech.s Normal file
View File

@ -0,0 +1,135 @@
;
; speech.s
; mocktest
;
; Created by Jeremy Rand on 2016-09-29.
; Copyright © 2016 Jeremy Rand. All rights reserved.
;
.export _setupSpeech
TABPTR := $F9 ;DATA POINTER
OUTPTR := $FB ;START OF DATA POINTER
ENDPTR := $FD ;END OF DATA POINTER
BUSY := $FF ;BUSY FLAG
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 REG-6522
IFR := $C48D ;INTERRUPT FLAG REG-6522
IER := $C48E
.CODE
.proc _setupSpeech
SEI ;DISABLE INTERRUPTS
LDA #<_interr ;SET INTERRUPT VECTOR
STA IRQL ;TO POINT TO INTERRUPT
LDA #>_interr ;SERVICE ROUTINE
STA IRQH
LDA #$00
STA DDRA
STA DDRB
LDA TABPTR+1 ;GET HIGH ADDRESS OF DATA
STA OUTPTR+1 ;STORE IN WORK POINTER
LDX TABPTR ;GET LOW ADDRESS OF DATA
INX ;INCREMENT TWICE
INX ;TO SKIP OVER LENGTH BYTES
BNE @L1 ;CHECK FOR PAGE BOUNDARY
INC OUTPTR+1
@L1:
STX OUTPTR ;STORE LOW BYTE
LDY #$01
LDA (TABPTR),Y ;GET HIGH LENGTH BYTE
CLC
ADC TABPTR+1 ;AND ADD TO BASE ADDRESS
STA ENDPTR+1 ;STORE END ADDRESS
DEY
LDA (TABPTR),Y ;GET LOW LENGTH BYTE
CLC
ADC TABPTR ;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 BUSY ;AND SET PERIPHERAL CONTROL
LDA #$0C ;REGISTER TO RECOGNIZE
STA PCR ;SIGNAL FROM SPEECH CHIP
LDA #$80 ;RAISE CTRL BIT IN REGISTER 3
STA CTTRAMP
LDA #$C0 ;SET TRANSITIONED INFLECTION
STA DURPHON ;MODE IN REGISTER 0
LDA #$70 ;LOWER CTRL BIT
STA CTTRAMP
LDA #$82 ;ENABLE 6522 INTERRUPTS
STA IER
CLI ;CLEAR INTERRUPT MASK
RTS ;RETURN TO CALLER
.endproc
.proc _interr
TXA ;SAVE REGISTERS
PHA
TYA
PHA
LDA IFR
BPL @L2
LDA #$02 ;CLEAR INTERRUPT FLAG
STA IFR
LDY #$00 ;INIT REGISTERS
LDX #$04
LDA OUTPTR ;CHECK FOR END OF DATA FILE
CMP ENDPTR
BCC @L1 ;IF NOT THEN CONTINUE
LDA OUTPTR+1 ;CHECK HIGH ADDRESS ALSO
CMP ENDPTR+1
BCC @L1 ;IF NOT THEN CONTINUE
LDA #$00 ;IF END, TURN EVERYTHING OFF
STA DURPHON ;STORE PAUSE PHONEME
LDA #$70 ;ZERO AMPLITUDE
STA CTTRAMP
LDA #$00 ;CLEAR BUSY FLAG
STA BUSY
LDA #$02 ;CLEAR INTERRUPT ENABLE
STA IER ;IN 6522
LDA #$FF
STA DDRA
LDA #$07
STA DDRB
@L2:
PLA ;RESTORE REGISTERS
TAY
PLA
TAX
LDA $45
RTI ;RETURN FROM INTERRUPT
@L1:
LDA (OUTPTR),Y ;GET DATA
STA BASE,X ;STORE IN SPEECH CHIP
INC OUTPTR ;NEXT DATA
BNE @L3
INC OUTPTR+1
@L3:
DEX ;NEXT REGISTER
CPX #$FF ;LAST REGISTER?
BNE @L1 ;NO, CONTINUE
BEQ @L2 ;YES, RETURN
.endproc