from problemkaputt.de: Spectrum Sound Speech SP0256 Voice Generator Voice Generator The voice generator relies on the Amplitude, Pitch, F0..F5, and B0..B5 registers, which are processed like so: Amplitude --> F0 --> F1 --> F2 --> F3 --> F4 --> F5 --> PWM --> External Pitch/Noise B0 B1 B2 B3 B4 B5 5kHz Filter Another important register is the Repeat counter, which indicates when the next opcode shall be executed (and which may then load new values into the above registers). Sample Rate and Repeat Timings The SP0256 is (usually) driven by a 3.12MHz oscillator, and it uses 7bit PWM output, which is clocked at 3.12MHz/2. To obtain a 10kHz sample rate, the chip issues some dummy steps with constant LOW level additionally to the 128 steps needed for 7bit PWM, making it a total number of 156 steps per sample. Sample Rate = 3.12MHz/2/156 = 10.0kHz ;100us per sample Which means one sample is 100us long, that value multiplied by 64 or 91 gives the following timings per repeat: 6.4ms per repeat (noise and pause), or 9.1ms per repeat (tone with pitch=91) Note: Some speech interfaces have the chip overclocked to 4MHz, resulting in higher pitch & sample rate, and shorter timings as with the normal 3.12MHz. Amplitude/Pitch/Repeat The 8bit amplitude register defines the volume in floating point form, Amplitude = lower5bit SHL upper3bit The pitch defines the frequency, counted in numbers of samples per period. For pitch=91, one HIGH sample (amplitude) is output, followed by 90 zero samples (null). That pattern is repeated as many times as specified in the repeat count, for example, with repeat=3: __ Amplitude level (+) | | | |________|________|________ __ Zero level PITCH <-Pitch-> __ Amplitude level (-) <--------repeat=3---------> As shown above, the generated waveform is NOT a square wave (which would have 50% high, and 50% low). After applying filters, the final waveform may look somewhat like so: __ Amplitude level (+) | | | |_|_.____|_|_.____|_|_.____ __ Zero level PITCH+FILTERS | | | | | | | | | __ Amplitude level (-) Note that (aside from noise) the AL2 ROM uses only one pitch value: 5Bh aka 91 decimal (meaning that all vowels are using the same base frequency, and they differ only by using different filter settings). Amplitude/Noise/Repeat Noise is activated when setting pitch=0. The timings are then same as when pitch=64, but instead of outputting HIGH and NULL levels, the hardware does now randomly output HIGH or LOW levels, for example, pitch=0 and repeat=5: __ Amplitude level (+) ||| || | | | || | || ||| | |||_|| |__|_|__||_|___|| |||_| __ Zero level NOISE | | || | || | ||| | | <-64->| || | || | ||| | | __ Amplitude level (-) <----------repeat=5----------> The exact random algorithm is unknown (probably some shift/xor stuff?), the random levels seem to be output on each sample (not only on the first sample of a repeat). Like normal pitch, the noise is passed to the 6 filters. Pause/Repeat The pause command sets amplitude=0. The timings are then same as when pitch=64, but the output is always NULL, for example, pause and repeat=5: __ Amplitude level (+) ______________________________ __ Zero level PAUSE (SILENCE) <-64-> __ Amplitude level (-) <----------repeat=5----------> Pause does reset the filters to 0, so the silence is not affected by filters. Digital Filters As shown above, the amplitude/pitch/noise output is passed through six digital filter stages (using the F0..F5 and B0..B5 registers), each stage looks like so: _____ _____ ------------------>| |------------------->| |-----+-----> _____ | SUB | ______ | SUB | | +--->| *B |--->|_____| +--->| *2*F |-->|_____| | | |_____| _____ | |______| _____ | +---------------|OLDER|<---+---------------| OLD |<----+ |_____| |_____| Ie. the incoming samples are adjusted like so: for i=0 to 5 ;filter number sample = sample - quant_table[F.i] * OLD.i * 2 ;F0..F5 registers sample = sample - quant_table[B.i] * OLDER.i ;B0..B5 registers OLDER.i = OLD.i OLD.i = sample next i Whereas, quant_table is a non-linear translation table that translates the signed 8bit registers to signed 10bit factors (with 9bit fractional part, ie. 511 means 0.99), with following entries: 0 ,9 ,17 ,25 ,33 ,41 ,49 ,57 ,65 ,73 ,81 ,89 ,97 ,105,113,121 129,137,145,153,161,169,177,185,193,201,209,217,225,233,241,249 257,265,273,281,289,297,301,305,309,313,317,321,325,329,333,337 341,345,349,353,357,361,365,369,373,377,381,385,389,393,397,401 405,409,413,417,421,425,427,429,431,433,435,437,439,441,443,445 447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477 479,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495 496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511 Above shows only positive values for index 0..127. Values for index -1..-128 should be 0..-511, or maybe -9..-512. Spectrum Sound Speech SP0256 Instruction Set Memory The SP0256 can address 60Kbytes (480Kbits) of internal or external ROM, however, usally the ROMs are only 2Kbytes (16Kbit). The ROM contains plain program code, without any kind of data arrays. The upper 4bit of the program counter cannot be zero, so the memory starts at byte-address 1000h, and ends at FFFFh. The first 512 bytes are entrypoints, usually containing JUMP opcodes for up to 256 allophones or words. The opcodes and their parameters are transferred serially, LSB first (except, for some reason, the JUMP/CALL/SETPAGE "Target" values are MSB first). The JUMP/CALL/RET opcodes can address only byte-aligned addresses, however, opcodes aren't always multiples of 8bits in size, so following opcodes may begin on any bit boundary. Opcode Summary 0000b SETPAGE/RET Set Page for JUMP/CALL, or Return from CALL 0001b SETMODE Set the MODE bits and Repeat MSBs 0010b LOAD_23 Load Pitch, Amplitude, 2-3 Coefficients 0011b LOAD_56 Load Pitch, Amplitude, 5-6 Coefficients 0100b LOAD_56D Load Pitch, Amplitude, 5-6 Coefficients, Delta 0101b SETMSB_3 Load Amplitude, MSBs of 3 Coefficients 0110b SETMSB_23 Load Amplitude, MSBs of 2 or 3 Coeffcients 0111b LOAD_PA Load Pitch, Amplitude 1000b LOAD_ALL Load All Parameters (at full 8bit precision) 1001b DELTA_56 Add Delta to Amplitude, Pitch, 5 or 6 Coefficients 1010b SETMSB_3P Load Amplitude, MSBs of 3 Coefficients, Pitch 1011b DELTA_23 Add Delta to Amplitude, Pitch, 2 or 3 Coefficients 1100b SETMSB_3D Load Amplitude, MSBs of 3 Coefficients, Delta 1101b CALL Jump to Subroutine (12-bit PAGE-Relative Address) 1110b JUMP Jump to 12-bit PAGE-Relative Address 1111b PAUSE Silent Pause Each opcode starts with a 4bit parameter field, followed by the 4bit opcode number, eventually followed by further Nbit parameter(s). Opcode 1110b - JUMP - Jump to 12-bit PAGE-Relative Address Opcode 1101b - CALL - Jump to Subroutine (12-bit PAGE-Relative Address) 4 Target bit8-11 (in reversed bit-order!) 4 Opcode (must be 1110b or 1101b) 8 Target bit0-7 (in reversed bit-order!) 0..7 Byte-alignment for next opcode (should be padded with 0 bits) Jumps to the specified memory address, Target bit12-15 are taken from the PAGE register (which is usually 01h, set like so on power up, but can be set to other values in range 01h..0Fh via SETPAGE). CALL pushes the 16bit byte-aligned return address onto stack, and marks the stack as not empty. The previous contents of the stack are lost (the stack is only one entry deep). Opcode 0000b with Zero-Operand - RET - Return from Subroutine (or HALT) 4 Zero for RET (00h=Return) 4 Opcode (must be 0000b) 0..7 Byte-alignment for next opcode (should be padded with 0 bits) If the stack was not empty: Jumps to the pushed return address (ie. to the next byte after the most recent CALL opcode), and marks the stack as empty. If the stack was already empty: Enters HALT state until/unless new data is/was input via /ALD pin. As soon as new data is available, it jumps to 1000h+data*2. Note: HALT state stops program execution, but does not stop the sound generator - to obtain silence, issue a short PAUSE (or another opcode that sets amplitude=0). Opcode 0000b with Nonzero-Operand - SETPAGE - Set the PAGE register 4 Target bit12-15 (in reversed bit-order!) (01h..0Fh=Page) The above target bits are used for ALL following JUMP/CALL opcodes 4 Opcode (must be 0000b) The PAGE register retains its setting until the next SETPAGE is encountered. (Note that address loads via ALD appear to ignore PAGE, and set the four MSBs to $1000. They do not modify the PAGE register, so subsequent JUMP/CALL instructions will jump relative to the current value in PAGE.) Opcode 0001b - SETMODE - Set the MODE bits and Repeat MSBs 2 Repeat Count bit4-5 (expands the next ONE opcode that uses 4bit repeat) 1 WIDTH for ALL following opcodes (0=Smaller, 1=Bigger bit-width) 1 EXTRA for ALL following opcodes (0=Exclude, 1=Include optional params) 4 Opcode (must be 0001b) Some opcodes have coefficient parameters of variable width (for example "3/6" means 3bit or 6bit), the smaller width is used when WIDTH=0, the bigger when WIDTH=1. Some opcodes have optional parameters (for example "(8)" means an optional 8bit parameter), which is included in the opcode only when EXTRA=1. Opcode 1111b - PAUSE - Silent Pause 4 Repeat Count 4 Opcode (must be 1111b) Provides a silent pause of varying length. The pause behaves identially to a pitch with Amplitude=0 and Period=64. All coefficients are cleared, as well. Opcode 0111b - LOAD_PA - Load Pitch, Amplitude 4 Repeat Count 4 Opcode (must be 0111b) 6 Amplitude MSBs (upper 3bit are exponent) 8 Pitch (00h=Noise) Opcode 1000b - LOAD_ALL - Load All Parameters (at full 8bit precision) 4 Repeat Count 4 Opcode (must be 1000b) 8 Amplitude unsigned (upper 3bit are exponent) 8 Pitch unsigned (00h=Noise) 8 Coeff B0 signed ;\coeff pair 0 8 Coeff F0 signed ;/ 8 Coeff B1 signed ;\coeff pair 1 8 Coeff F1 signed ;/ 8 Coeff B2 signed ;\coeff pair 2 8 Coeff F2 signed ;/ 8 Coeff B3 signed ;\coeff pair 3 8 Coeff F3 signed ;/ 8 Coeff B4 signed ;\coeff pair 4 8 Coeff F4 signed ;/ 8 Coeff B5 signed ;\coeff pair 5 8 Coeff F5 signed ;/ (8) Amplitude Interpolation, signed ;\when EXTRA=1 only (8) Pitch Interpolation, signed ;/ Notes: The pitch and amplitude deltas that are available when EXTRA=1 are applied every pitch period, not just once. Wraparound may occur. If the Pitch goes to zero, the periodic excitation switches to noise. Opcode 0010b - LOAD_23 - Load Pitch, Amplitude, 2-3 Coefficients Opcode 0011b - LOAD_56 - Load Pitch, Amplitude, 5-6 Coefficients Opcode 0100b - LOAD_56D - Load Pitch, Amplitude, 5-6 Coefficients, Delta 4 Repeat Count 4 Opcode (must be 0010b or 0011b or 0100b) 6 Amplitude MSBs (upper 3bit are exponent) 8 Pitch (00h=Noise) 3/6 Coeff B0 Bit4/1..6 unsigned ;\coeff pair 0 ;\ 5/6 Coeff F0 Bit3/2..7 signed ;/ ; 3/6 Coeff B1 Bit4/1..6 unsigned ;\coeff pair 1 ; opcode LOAD_56D, 5/6 Coeff F1 Bit3/2..7 signed ;/ ; and LOAD_56 only 3/6 Coeff B2 Bit4/1..6 unsigned ;\coeff pair 2 ; 5/6 Coeff F2 Bit3/2..7 signed ;/ ;/ 4/6 Coeff B3 Bit3/1..6 unsigned ;\coeff pair 3 6/7 Coeff F3 Bit2/1..7 signed ;/ 7/8 Coeff B4 Bit1/0..7 signed ;\coeff pair 4 6/8 Coeff F4 Bit2/0..7 signed ;/ (8) Coeff B5 Bit0..7 signed ;\coeff pair 5 ;\when EXTRA=1 only (8) Coeff F5 Bit0..7 signed ;/ ;/ 5 Amplitude Interpolation LSBs, unsigned ;\opcode LOAD_56D only 5 Pitch Interpolation LSBs, unsigned ;/ Sets the unspecified coefficients to 0. The "unsigned" B0,B1,B2,B3 values are zero-expanded from N bits to (N+1) bits, and are then copied to the upper (N+1) bits of the register. Opcode 0110b - SETMSB_23 - Load Amplitude, MSBs of 2 or 3 Coeffcients Opcode 0101b - SETMSB_3 - Load Amplitude, MSBs of 3 Coefficients Opcode 1010b - SETMSB_3P - Load Amplitude, MSBs of 3 Coefficients, Pitch Opcode 1100b - SETMSB_3D - Load Amplitude, MSBs of 3 Coefficients, Delta 4 Repeat Count 4 Opcode (must be 0101b or 0110b or 1010b or 1100b) 6 Amplitude MSBs (upper 3bit are exponent) [8] Pitch (00h=Noise) ;-Opcode SETMSB_3P only 5/6 New F0 MSBs signed ;\ 5/6 New F1 MSBs signed ; Opcode SETMSB_3/3P/3D only 5/6 New F2 MSBs signed ;/ 6/7 New F3 MSBs signed ;\ 6/8 New F4 MSBs signed ; Opcode SETMSB_23 only (8) New F5 MSBs signed (when EXTRA=1 only) ;/ (0) Set F5=0 and B5=0 (when EXTRA=0 only) [5] Amplitude Interpolation LSBs, unsigned ;\Opcode SETMSB_3D only [5] Pitch Interpolation LSBs, unsigned ;/ All other coefficient bits are unaffected (ie. all coefficients that aren't accessed by the specific opcode, as well as LSBs of accessed coefficients). Opcode 1001b - DELTA_56 - Add Delta to Amplitude, Pitch, 5 or 6 Coefficients Opcode 1011b - DELTA_23 - Add Delta to Amplitude, Pitch, 2 or 3 Coefficients 4 Repeat Count 4 Opcode (must be 1001b or 1011b) 4 Amplitude Interpolation 6 MSBs signed 5 Pitch Interpolation LSBs signed 3/4 B0 4,7 MSBs signed ;\ ;\ 3/4 F0 5,6 MSBs signed ;/ ; 3/4 B1 4,7 MSBs signed ;\ ; opcode DELTA_56 only 3/4 F1 5,6 MSBs signed ;/ ; 3/4 B2 4,7 MSBs signed ;\ ; 3/4 F2 5,6 MSBs signed ;/ ;/ 3/4 B3 5,7 MSBs signed ;\ 4/5 F3 6,7 MSBs signed ;/ 4/5 B4 x,8 MSBs signed ;\ <---- DELTA_56: x=6, and DELTA_23: x=7 (?) 4/5 F4 6,8 MSBs signed ;/ (5) B5 (8) MSBs signed ;\ ;\when EXTRA=1 only (5) F5 (8) MSBs signed ;/ ;/ Performs a delta update, adding small 2s complement numbers to a series of coefficients. The 2s complement updates for the various filter coefficients only update some of the MSBs -- the LSBs are unaffected. The exact bits which are updated are noted above. Normal 2s complement arithmetic is performed, and no protection is provided against overflow. Adding 1 to the largest value for a bit field wraps around to the smallest value for that bitfield. Notes: The delta update is applied only once (even if the repeat count is bigger than 1). The delta updates are applied to the 8-bit encoded forms of the coefficients, not the 10-bit decoded forms. The update to the amplitude register is a normal 2s complement update to the entire register. This means that any carry/borrow from the mantissa will change the value of the exponent. The update doesn't know anything about the format of that register. Program Counter and Stack Note As seen in the datasheets for external speech ROMs, the Program Counter & Stack seem to be part of the ROM (not of the microprocessor). So, when using external ROMs, one would theoretically have separate stacks for each ROM. NB. this explains why the Target values are reversed; apparently the ROMs use different bit-order (for memory addresses) than the microprocessor does for its own values (ie. the opcodes and voice-parameters). Credits The SP0256 opcodes were reverse engineered by Joe Zbiciak and Frank Palazzolo. Repeat Count = 0 According to Joe and Frank, a repeat count of zero "causes the instruction to not execute" (and not to fetch any of its following paramters, so the opcode becomes only 8bits long; or to fetch, but not apply them?), however, they've also mentioned that "conflicting documentation suggests there's more going on". XXX... Bit fields narrower than 8 bits are MSB justified unless specified otherwise, meaning that the least significant bits are the ones that are missing. These LSBs are filled with zeros. When updating filter coefficients with a delta-update, the microsequencer performs plain 2s-complement arithmetic on the 8-bit value in the coefficient register file. No attention is paid to the format of the register. Spectrum Sound Speech SP0256 Allophones/Words SP0256-AL2 Allophone List Num Name Example Funny Actual Num Name Example Funny Actual 00h PA1 PAUSE 10ms 6.4ms 20h /AW/ Out 370ms 254.8ms 01h PA2 PAUSE 30ms 25.6ms 21h /DD2/ Do 160ms 72.1ms 02h PA3 PAUSE 50ms 44.8ms 22h /GG3/ Wig 140ms 110.5ms 03h PA4 PAUSE 100ms 96.0ms 23h /VV/ Vest 190ms 127.4ms 04h PA5 PAUSE 200ms 198.4ms 24h /GG1/ Got 80ms 72.1ms 05h /OY/ Boy 420ms 291.2ms 25h /SH/ Ship 160ms 198.4ms 06h /AY/ Sky 260ms 172.9ms 26h /ZH/ Azure 190ms 134.1ms 07h /EH/ End 70ms 54.6ms 27h /RR2/ Brain 120ms 81.9ms 08h /KK3/ Comb 120ms 76.8ms 28h /FF/ Food 150ms 108.8ms 09h /PP/ Pow 210ms 147.2ms 29h /KK2/ Sky 190ms 134.4ms 0Ah /JH/ Dodge 140ms 98.4ms 2Ah /KK1/ Can't 160ms 115.2ms 0Bh /NN1/ Thin 140ms 172.9ms 2Bh /ZZ/ Zoo 210ms 148.6ms 0Ch /IH/ Sit 70ms 45.5ms 2Ch /NG/ Anchor 220ms 200.2ms 0Dh /TT2/ To 140ms 96.0ms 2Dh /LL/ Lake 110ms 81.9ms 0Eh /RR1/ Rural 170ms 127.4ms 2Eh /WW/ Wool 180ms 145.6ms 0Fh /AX/ Succeed 70ms 54.6ms 2Fh /XR/ Repair 360ms 245.7ms 10h /MM/ Milk 180ms 182.0ms 30h /WH/ Whig 200ms 145.2ms 11h /TT1/ Part 100ms 76.8ms 31h /YY1/ Yes 130ms 91.0ms 12h /DH1/ They 290ms 136.5ms 32h /CH/ Church 190ms 147.2ms 13h /IY/ See 250ms 172.9ms 33h /ER1/ Letter 160ms 109.2ms 14h /EY/ Beige 280ms 200.2ms 34h /ER2/ Fir 300ms 209.3ms 15h /DD1/ Could 70ms 45.5ms 35h /OW/ Beau 240ms 172.9ms 16h /UW1/ To 100ms 63.7ms 36h /DH2/ Bath 240ms 182.0ms 17h /AO/ Aught 100ms 72.8ms 37h /SS/ Vest 90ms 64.0ms 18h /AA/ Hot 100ms 63.7ms 38h /NN2/ No 190ms 136.5ms 19h /YY2/ Yes 180ms 127.4ms 39h /HH2/ Hoe 180ms 126.0ms 1Ah /AE/ Hat 120ms 81.9ms 3Ah /OR/ Store 330ms 236.6ms 1Bh /HH1/ He 130ms 89.6ms 3Bh /AR/ Alarm 290ms 200.2ms 1Ch /BB1/ Business 80ms 36.4ms 3Ch /YR/ Clear 350ms 245.7ms 1Dh /TH/ Thin 180ms 128.0ms 3Dh /GG2/ Guest 40ms 69.4ms 1Eh /UH/ Book 100ms 72.8ms 3Eh /EL/ Saddle 190ms 136.5ms 1Fh /UW2/ Food 260ms 172.9ms 3Fh /BB2/ Business 50ms 50.2ms Mind that completion of an allophone doesn't mute the voice generator (it'll keep repeating the end of the allophone until receiving a new allophone). To mute the voice generator, output a short pause (eg. PA1) after your last allophone. The "Funny" timings are from the SP0256-AL2 data sheet (these values are totally wrong). The "Actual" timings are calculated from the pitch/repeat values in the AL2 ROM (these values should be 100% correct, when clocked at 3.12MHz). <--------------- Currah Codes ---------------> Num ASCII Num ASCII Num ASCII Num ASCII 18h a 27h r 14h (aa)/(ay) 29h (ck) 1Ch b 37h s 13h (ee) 3Ch (ear) 08h c 11h t 06h (ii) 1Ah (eh) 15h d 0Fh u 35h (oo)/(eau) 33h (er) 07h e 23h v 3Fh (bb) 34h (err) 28h f 2Eh w 21h (dd) 2Ch (ng) 24h g - x "ks" 3Dh (gg) 3Ah (or) 1Bh h 31h y 22h (ggg) 16h (ou) 0Ch i 2Bh z 39h (hh) 1Fh (ouu) 0Ah j 3Eh (ii) 20h (ow) 2Ah k 36h N/A 38h (nn) 05h (oy) 2Dh l 00h EOL 0Eh (rr) 25h (sh) 10h m 01h ' 0Dh (tt) 1Dh (th) 0Bh n 02h N/A 19h (yy) 12h (dth) 17h o 03h SPACE 3Bh (ar) 1Eh (uh) 09h p 04h , 2Fh (aer) 30h (wh) - q "kw" 04hx2 . 32h (ch) 21h (zh) Other Allophone/Word Sets For curiosity, below are some other SP0256-xx variants (none of the known Spectrum devices is using that variants though). SP0256-012 Word List This chip is used in the "Intellivoice" expansion module for Mattel's Intellivision. 00h (SPB640 08h One 14h Thirteen 20h Seventy Speech 09h Two 15h Fourteen 21h Eighty FIFO) 0Ah Three 16h Fifteen 22h Ninety 01h pause4 0Bh Four 17h Sixteen 23h Hundred 02h pause3 0Ch Five 18h Seventeen 24h Thousand 03h pause2 0Dh Six 19h Eighteen 25h -teen 04h pause1 0Eh Seven 1Ah Nineteen 26h -ty 05h pause0 0Fh Eight 1Bh Twenty 27h Press 06h "Mattel 10h Nine 1Ch Thirty 28h Enter Electronics 11h Ten 1Dh Fourty 29h Or Presents" 12h Eleven 1Eh Fifty 2Ah And 07h Zero 13h Twelve 1Fh Sixty There isn't much known about the SPB640 FIFO, as far as I understand, it does have three functions: It can hold up to 64 word/allophone numbers (to be injected to A1..A8 pins of the SP0256), it can hold opcodes/parameters (to be injected to SER IN pin of the SP0256), and it includes a general purpose I/O port. SP0256-017 Word List 00h Oh 09h Nine 12h Eighteen 1Bh Hour 01h One 0Ah Ten 13h Nineteen 1Ch Minute 02h Two 0Bh Eleven 14h Twenty 1Dh Hundred Hour 03h Three 0Ch Twelve 15h Thirty 1Eh Good Morning 04h Four 0Dh Thirteen 16h Forty 1Fh Attention Please 05h Five 0Eh Fourteen 17h Fifty 20h Please Hurry 06h Six 0Fh Fifteen 18h It is 21h Melody A 07h Seven 10h Sixteen 19h A.M. 22h Melody B 08h Eight 11h Seventeen 1Ah P.M. 23h Melody C SP0256-019 (or rather SP0256B-019) Allophone/Word/Phrase List This chip is used in "The Voice", an expansion module for the Odyssey 2. The chip contains the following allophones and words: 80h..BFh Allophones (same as 00h..3Fh on SP0256-AL2) C0h "Enemy" C1h "All clear" C2h "Please" C3h "Get off" C4h "Open fire" C5h "Watch out" C6h "Mercy" C7h "Hit it" C8h "You blew it" C9h "Do it again" CAh "Incredible" FAh "U.F.O." FBh "Monster!" Not sure why bit7 is set in the codes (it should be written like so to the O2 I/O ports, but maybe the bit isn't actually passed to the SP0256 chip)? Additionally, the expansion module contains 3 built-in speech ROMs with sound effects and various words/phrases like "Amazing", "Come on", "Outch", etc. Moreover, Odyssey 2 game cartridges can contain up to 5 external speech ROMs. For details see "Odyssey 2 Technical Specs" from Daniel Boris. Spectrum Sound Speech SP0256 Pin-Outs SP0256 - Speech chip 1 GND 2 /RESET 3 ROM DISABLE 4 C1 5 C2 6 C3 7 VCC1 8 SBY 9 /LRQ 10 A8 11 A7 12 SER OUT 13 A6 14 A5 15 A4 16 A3 17 A2 18 A1 19 SE 20 /ALD 21 SER IN 22 TEST 23 VCC2 24 PWM OUT 25 /SBY RESET 26 ROM CLK 27 OSC1 28 OSC2 The oscillator should be 3.12MHz Allows to output sounds up to 5kHz (ie. the output is updated at 10kHz rate). The SP0256 is reportedly expandable to "491 K of ROM" (probably bullshit). The SP0256B is reportedly expandable to "480 K of ROM" (probably K=Kbits). The TEST pin of the SP0256 chip can be used (among others) to dump its internal ROM. Note: Details on TEST are found in the "SP0256B" datasheet - but not in the "SP0256" datasheet - not sure if the pin works identical for both chip types, nor if there's a difference between them at all.