├── README.md └── fpga-synth ├── README.rst ├── amps_filters.py ├── config.py ├── envgen.py ├── fpga-synth ├── BPC3011-Papilio_Pro-general.ucf ├── fpga-synth.xise ├── fpga_synth.v └── papilio.ucf ├── fpga.v ├── instrument ├── 555_Monostable.png ├── README.rst ├── body.py ├── musicbox.py ├── musicbox.xise ├── ppro.ucf ├── pslib.py ├── ramp.v └── simple_body.py ├── output_stage.py ├── param_loading.py ├── synth.py ├── tb_fpga.tf └── wavegen.py /README.md: -------------------------------------------------------------------------------- 1 | # Music projects 2 | 3 | These have been sprinkled around different repositories for a few years now. 4 | This is an attempt to bring them together. For now I'm just using git submodules 5 | but at some point I'd like to merge the histories in some not-too-messy way. 6 | Maybe keep the commits in chronological order if possible. 7 | 8 | Meanwhile I'm working on some new stuff, which is not in a submodule. 9 | -------------------------------------------------------------------------------- /fpga-synth/README.rst: -------------------------------------------------------------------------------- 1 | An FPGA-based synthesizer 2 | ========================= 3 | 4 | Back in the 1970s and 80s, I was interested in electronics and music synthesizers, and they were 5 | still a pretty big novelty. By that time, Bob Moog had already identified a collection of analog 6 | modules that could be set up like this to produce a very wide range of interesting, obviously 7 | synthetic musical noises. 8 | 9 | .. image:: http://www.headphone-amplifier.com/pro_light_sound_2008/images/pro_light_and%20_sound_2008_making_musik_analog_synthesizer1_600.jpg 10 | 11 | So a friend and I used to play with this stuff because his father had gotten him started with it, 12 | and then he'd gotten me interested (actually I guess my first impetus was the vinyl album "Switched 13 | On Bach"), and I knew some electronics so that was a welcome addition to his pool of knowledge on 14 | the subject. We had a good time and I built a few electronic musical instruments in college and 15 | immediately after, but then got too busy with my career to pursue it more. 16 | 17 | Fast-forward thirty years, and we have cheap 8- and 32-bit microcontrollers and powerful FPGAs. In 18 | my career as an electrical engineer I'd done some FPGA work, and it has occurred to me that the 19 | kinds of fixed-point arithmetic computations that FPGAs do well are the ones that would do the jobs 20 | of all those analog modules. So my hope/plan is to use a Papilio One or Papilio Pro FPGA board to 21 | make a synthesizer with very few analog parts. 22 | 23 | Getting back into this stuff after 15 years as a software engineer, there has been a bit of a learning 24 | curve. I don't have the resources of a large corporation supporting the FPGA development effort, I 25 | just have what I find online and can purchase mail-order. Sometimes the simulation acts one way and 26 | the chip acts another, so there's a good bit of floundering involved. Some of the early commits in 27 | this repo will be of stuff that just barely works or doesn't work at all, but that's why they call 28 | it a hobby. 29 | 30 | Hacking MyHDL 31 | ============= 32 | 33 | Installation on Ubuntu 10.04 (Lucid) 34 | ------------------------------------ 35 | 36 | :: 37 | 38 | sudo add-apt-repository ppa:balau82/ppa 39 | sudo apt-get update 40 | sudo apt-get install myhdl gtkwave verilog 41 | 42 | Making sure it works:: 43 | 44 | (cd /usr/share/doc/myhdl/examples/rs232; python test_rs232.py) 45 | 46 | Online manual: 47 | 48 | * http://www.myhdl.org/doc/0.6/manual/index.html 49 | 50 | Projects: 51 | 52 | * http://www.myhdl.org/doku.php/projects:intro 53 | * http://www.antfarm.org/blog/aaronf/2008/02/myhdl_a_brief_discussion_2.html 54 | * /usr/share/doc/myhdl/examples 55 | 56 | Installation on OSX 10.8.3 (Mountain Lion) 57 | ------------------------------------------ 58 | 59 | Download MyHDL from this website: http://sourceforge.net/projects/myhdl 60 | 61 | Then:: 62 | 63 | tar xfz Downloads/myhdl-0.7.tar.gz 64 | cd myhdl-0.7 65 | python setup.py build 66 | sudo python setup.py install 67 | 68 | Unpack the GTKWave zip in the /Applications directory: http://gtkwave.sourceforge.net/gtkwave.zip 69 | 70 | Add this to your .bash_profile:: 71 | 72 | export PATH=$PATH:/Applications/gtkwave.app/Contents/Resources/bin 73 | 74 | Add this line to your MyHDL source file:: 75 | 76 | Simulation(traceSignals(testBench)).run() 77 | 78 | This will produce a file called testBench.vcd, and now you just type:: 79 | 80 | gtkwave testBench.vcd 81 | 82 | Open up the device under test in the upper left, select signals you want to look at, and drag them 83 | over to the waveform display. Right-click on the signal name to choose a data format, including 84 | analog formats that show waveforms. 85 | 86 | The MyBlaze core 87 | ---------------- 88 | 89 | MyBlaze is a MyHDL implementation (LGPL) of the GCC-targetable MicroBlaze soft 90 | processor core which runs on Xilinx FPGAs. Some people have run MMU-less Linux 91 | on it, and it can also run FreeRTOS. 92 | 93 | * http://en.wikipedia.org/wiki/MicroBlaze 94 | * https://github.com/wware/myblaze 95 | * http://xilinx.wikidot.com/mb-gnu-tools 96 | * http://xilinx.wikidot.com/microblaze-linux 97 | * Here is a guy in Israel who has done a lot of Microblaze work: http://billauer.co.il/blog/category/fpga/ 98 | -------------------------------------------------------------------------------- /fpga-synth/amps_filters.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | 4 | from myhdl import Signal, delay, Simulation, always_comb, \ 5 | instance, intbv, bin, toVerilog, toVHDL, always, now, traceSignals 6 | from config import ( 7 | WHOLE, 8 | HALF, 9 | MASK, 10 | N, 11 | signed_bus, 12 | unsigned_bus, 13 | ) 14 | 15 | ######## 16 | 17 | def vca(clk, input_signed, input_unsigned, output_signed): 18 | a = signed_bus(18) 19 | b = unsigned_bus(18) 20 | ab = signed_bus(36) 21 | 22 | @always(clk.posedge) 23 | def get_inputs(): 24 | a.next = input_signed 25 | b.next = input_unsigned 26 | 27 | @always_comb 28 | def multiply(): 29 | ab.next = a * b 30 | 31 | @always_comb 32 | def drive_output(): 33 | output_signed.next = (ab >> N) 34 | 35 | return (get_inputs, multiply, drive_output) 36 | 37 | ######## 38 | 39 | def make_ios(): 40 | clk = Signal(False) 41 | input_signed = signed_bus(N) 42 | input_unsigned = unsigned_bus(N) 43 | output_signed = signed_bus(N) 44 | return (clk, input_signed, input_unsigned, output_signed) 45 | 46 | 47 | class TestVoltageControlledAmplifier(unittest.TestCase): 48 | 49 | def test_vca(self): 50 | 51 | def bench(): 52 | clk, input_signed, input_unsigned, output_signed = make_ios() 53 | 54 | v = vca(clk, input_signed, input_unsigned, output_signed) 55 | 56 | @instance 57 | def drive_stuff(): 58 | input_signed.next = 0 59 | input_unsigned.next = 0 60 | clk.next = 0 61 | yield delay(1) 62 | clk.next = 1 63 | yield delay(1) 64 | self.assertEqual(0, output_signed) 65 | 66 | input_signed.next = HALF - 1 67 | input_unsigned.next = MASK 68 | clk.next = 0 69 | yield delay(1) 70 | clk.next = 1 71 | yield delay(1) 72 | self.assertEqual(HALF - 2, output_signed) 73 | 74 | input_signed.next = -HALF 75 | input_unsigned.next = MASK 76 | clk.next = 0 77 | yield delay(1) 78 | clk.next = 1 79 | yield delay(1) 80 | self.assertEqual(-HALF, output_signed) 81 | 82 | return (v, drive_stuff) 83 | 84 | tb = bench() 85 | sim = Simulation(tb) 86 | sim.run() 87 | 88 | 89 | if __name__ == '__main__': 90 | if 'hdl' in sys.argv[1:]: 91 | clk, input_signed, input_unsigned, output_signed = make_ios() 92 | toVerilog(vca, clk, input_signed, input_unsigned, output_signed) 93 | else: 94 | suite = unittest.TestLoader().loadTestsFromTestCase(TestVoltageControlledAmplifier) 95 | unittest.TextTestRunner(verbosity=2).run(suite) 96 | -------------------------------------------------------------------------------- /fpga-synth/config.py: -------------------------------------------------------------------------------- 1 | from myhdl import Signal, delay, always_comb, instance, intbv, bin, always, now 2 | 3 | 4 | ######### General stuff ################ 5 | 6 | # Papilio board clocked at 32 MHz, audio rate is 40 kHz 7 | MHZ = 32 * 1000 * 1000 8 | SECOND = AUDIO_RATE = 40 * 1000 9 | 10 | DIVIDER = MHZ / AUDIO_RATE 11 | 12 | N = 14 13 | assert N < 18 # keep multiplier happy 14 | 15 | WHOLE = 1 << N 16 | MASK = WHOLE - 1 17 | HALF = 1 << (N - 1) 18 | QUARTER = 1 << (N - 2) 19 | 20 | PHASEWIDTH = 24 21 | 22 | LOADWIDTH = 4 23 | 24 | (RAMP, TRIANGLE, SQWAVE, NOISE) = range(4) 25 | 26 | def signed_bus(numbits): 27 | min = -(1 << (numbits - 1)) 28 | max = 1 << (numbits - 1) 29 | return Signal(intbv(0, min=min, max=max)) 30 | 31 | def unsigned_bus(numbits): 32 | return Signal(intbv(0)[numbits:]) 33 | 34 | def signed_to_unsigned(nbits, _in, _out): 35 | __out = unsigned_bus(nbits) 36 | @always(_in) 37 | def drive__out(): 38 | __out.next = _in + (1 << (nbits - 1)) 39 | @always(__out) 40 | def drive_out(): 41 | _out.next = __out 42 | return (drive__out, drive_out) 43 | 44 | def unsigned_to_signed(nbits, _in, _out): 45 | __out = signed_bus(nbits) 46 | @always(_in) 47 | def drive__out(): 48 | __out.next = _in - (1 << (nbits - 1)) 49 | @always(__out) 50 | def drive_out(): 51 | _out.next = __out 52 | return (drive__out, drive_out) 53 | 54 | 55 | ############## Simulation stuff ################ 56 | 57 | def compute_delta_phase(freq): 58 | ONE_HERTZ = 1. * (1 << PHASEWIDTH) / AUDIO_RATE 59 | return int(round(ONE_HERTZ * freq)) 60 | -------------------------------------------------------------------------------- /fpga-synth/envgen.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | import math 4 | from myhdl import Signal, delay, Simulation, always_comb, \ 5 | instance, intbv, bin, toVerilog, toVHDL, always, now, traceSignals 6 | from config import ( 7 | PHASEWIDTH, 8 | N, 9 | MASK, 10 | WHOLE, 11 | HALF, 12 | AUDIO_RATE, 13 | unsigned_bus 14 | ) 15 | 16 | FRACTION_BITS = 20 17 | LCOUNT_BITS = 6 18 | 19 | 20 | def lcounter(clk, lzero): 21 | lbits = unsigned_bus(LCOUNT_BITS) 22 | 23 | @always_comb 24 | def _output(): 25 | lzero.next = (lbits == 0) 26 | 27 | @always(clk.posedge) 28 | def count(): 29 | lbits.next = (lbits + 1) & ((1 << LCOUNT_BITS) - 1) 30 | 31 | return (_output, count) 32 | 33 | 34 | # states 35 | ATTACK, DECAY, RELEASE = range(3) 36 | 37 | # Clock this at the 40 kHz audio rate 38 | def state_machine(clk, keydown, threshold, state): 39 | _state = unsigned_bus(2) 40 | 41 | @always_comb 42 | def drive_outputs(): 43 | state.next = _state 44 | 45 | @always(clk.posedge) 46 | def transitions(): 47 | if not keydown: 48 | _state.next = RELEASE 49 | elif _state > RELEASE: 50 | _state.next = RELEASE 51 | elif _state == RELEASE and keydown: 52 | _state.next = ATTACK 53 | elif _state == ATTACK and threshold: 54 | _state.next = DECAY 55 | else: 56 | _state.next = _state 57 | 58 | return (drive_outputs, transitions) 59 | 60 | 61 | def make_sm_ios(): 62 | clk = Signal(False) 63 | keydown = Signal(False) 64 | threshold = Signal(False) 65 | state = unsigned_bus(2) 66 | return (clk, keydown, threshold, state) 67 | 68 | 69 | def exponential_target(state, sustain, target): 70 | 71 | @always_comb 72 | def choose_target(): 73 | if state == ATTACK: 74 | target.next = 2 << (N + FRACTION_BITS) 75 | elif state == DECAY: 76 | # Line up the MSbit of sustain with the MSbit for target 77 | target.next = sustain << (N + FRACTION_BITS - 4) 78 | else: # RELEASE 79 | target.next = 0 80 | 81 | return choose_target 82 | 83 | 84 | def exponential_generator(clk, reset, target, latch_dq, slope, qi): 85 | """ 86 | ATTACK: target = 2 << (N + FRACTION_BITS) 87 | DECAY: target = S << (N + FRACTION_BITS - 4) 88 | ^ the idea here is to left-shift S so its MSB lines up 89 | RELEASE: target = 0 90 | """ 91 | q = unsigned_bus(N + FRACTION_BITS + 2) 92 | dq = unsigned_bus(N + FRACTION_BITS + 2) 93 | sign_bit = Signal(False) 94 | 95 | @always(clk.posedge) 96 | def compute_dq(): 97 | if latch_dq and not reset: 98 | x = target - q 99 | if target >= q: 100 | sign_bit.next = False 101 | else: 102 | sign_bit.next = True 103 | x = -x 104 | 105 | if slope & 1: 106 | # divide by sqrt(2), approximately 107 | x = (x >> 1) + (x >> 3) + (x >> 4) 108 | 109 | dq.next = x >> (LCOUNT_BITS + 3 + (slope >> 1)) 110 | 111 | @always(clk.posedge) 112 | def update_q(): 113 | if reset: 114 | q.next = 0 115 | elif sign_bit: 116 | q.next = q - dq 117 | else: 118 | q.next = q + dq 119 | 120 | @always_comb 121 | def drive_qi_qf(): 122 | if (q >> FRACTION_BITS) > MASK: 123 | qi.next = MASK 124 | else: 125 | qi.next = q >> FRACTION_BITS 126 | 127 | return (compute_dq, update_q, drive_qi_qf) 128 | 129 | def make_expgen_ios(): 130 | clk = Signal(False) 131 | reset = Signal(False) 132 | target = unsigned_bus(N + FRACTION_BITS + 2) 133 | latch_dq = Signal(False) 134 | slope = unsigned_bus(4) 135 | qi = unsigned_bus(N) 136 | return (clk, reset, target, latch_dq, slope, qi) 137 | 138 | 139 | def adsr(clk, keydown, attack, sustain, decay, release, _out): 140 | reset = Signal(False) 141 | keydown1 = Signal(False) 142 | keydown2 = Signal(False) 143 | lzero = Signal(False) 144 | threshold = Signal(False) 145 | state = unsigned_bus(2) 146 | target = unsigned_bus(N + FRACTION_BITS + 2) 147 | latch_dq = Signal(False) 148 | slope = unsigned_bus(4) 149 | qi = unsigned_bus(N) 150 | 151 | @always_comb 152 | def combinatorial(): 153 | latch_dq.next = (keydown1 and not keydown2) or (keydown2 and not keydown1) or lzero 154 | threshold.next = (qi == MASK) 155 | _out.next = qi 156 | if state == ATTACK: 157 | slope.next = attack 158 | elif state == DECAY: 159 | slope.next = decay 160 | else: 161 | slope.next = release 162 | 163 | @always(clk.posedge) 164 | def synchronous(): 165 | keydown1.next = keydown 166 | keydown2.next = keydown1 167 | reset.next = 0 168 | 169 | sm = state_machine(clk, keydown, threshold, state) 170 | eg = exponential_generator(clk, reset, target, latch_dq, slope, qi) 171 | et = exponential_target(state, sustain, target) 172 | lc = lcounter(clk, lzero) 173 | 174 | return (sm, eg, et, lc, synchronous, combinatorial) 175 | 176 | def make_adsr_ios(): 177 | clk = Signal(False) 178 | keydown = Signal(False) 179 | attack = unsigned_bus(4) 180 | decay = unsigned_bus(4) 181 | sustain = unsigned_bus(4) 182 | release = unsigned_bus(4) 183 | _out = unsigned_bus(N) 184 | return (clk, keydown, attack, sustain, decay, release, _out) 185 | 186 | 187 | class TestEnvelopeGenerator(unittest.TestCase): 188 | 189 | def test_state_machine(self): 190 | 191 | def bench(): 192 | clk, keydown, threshold, state = make_sm_ios() 193 | sm = state_machine(clk, keydown, threshold, state) 194 | 195 | @instance 196 | def drive_stuff(): 197 | keydown.next = False 198 | threshold.next = False 199 | clk.next = 0 200 | yield delay(1) 201 | clk.next = 1 202 | yield delay(1) 203 | self.assertEqual(RELEASE, state) 204 | 205 | yield delay(1) 206 | keydown.next = True 207 | yield delay(1) 208 | clk.next = 0 209 | yield delay(1) 210 | clk.next = 1 211 | yield delay(1) 212 | self.assertEqual(ATTACK, state) 213 | 214 | threshold.next = True 215 | yield delay(1) 216 | 217 | clk.next = 0 218 | yield delay(1) 219 | clk.next = 1 220 | yield delay(1) 221 | 222 | self.assertEqual(DECAY, state) 223 | keydown.next = False 224 | yield delay(1) 225 | 226 | clk.next = 0 227 | yield delay(1) 228 | clk.next = 1 229 | yield delay(1) 230 | self.assertEqual(RELEASE, state) 231 | 232 | return (sm, drive_stuff) 233 | 234 | tb = bench() 235 | sim = Simulation(tb) 236 | sim.run() 237 | 238 | def test_exponential_generator(self): 239 | 240 | def bench(): 241 | clk, reset, target, latch_dq, slope, qi = make_expgen_ios() 242 | eg = exponential_generator(clk, reset, target, latch_dq, slope, qi) 243 | 244 | @instance 245 | def drive_stuff(): 246 | clk.next = 0 247 | reset.next = 1 248 | target.next = 0 249 | latch_dq.next = 0 250 | slope.next = 0 251 | yield delay(1) 252 | clk.next = 1 253 | yield delay(1) 254 | clk.next = 0 255 | yield delay(1) 256 | self.assertEqual(0, qi) 257 | reset.next = 0 258 | yield delay(1) 259 | clk.next = 1 260 | yield delay(1) 261 | clk.next = 0 262 | yield delay(1) 263 | target.next = 1 << N 264 | latch_dq.next = 1 265 | yield delay(1) 266 | clk.next = 1 # this rising edge sets dq 267 | yield delay(1) 268 | clk.next = 0 269 | yield delay(1) 270 | # target should now be a don't-care 271 | latch_dq.next = 0 272 | yield delay(1) 273 | clk.next = 1 # this rising edge increments q 274 | yield delay(1) 275 | clk.next = 0 276 | yield delay(1) 277 | self.assertEqual(1 << (N - LCOUNT_BITS - 3), qi) 278 | clk.next = 1 # this rising edge increments q 279 | yield delay(1) 280 | clk.next = 0 281 | yield delay(1) 282 | self.assertEqual(2 << (N - LCOUNT_BITS - 3), qi) 283 | target.next = 0 # let's try moving down now 284 | latch_dq.next = 1 285 | yield delay(1) 286 | clk.next = 1 # this rising edge sets dq, q keeps going 287 | yield delay(1) 288 | clk.next = 0 289 | yield delay(1) 290 | clk.next = 1 # this rising edge moves q down a little 291 | yield delay(1) 292 | clk.next = 0 293 | yield delay(1) 294 | # q will continue moving up for one more tick, while 295 | q_est = (3 << (N - LCOUNT_BITS - 3)) << FRACTION_BITS 296 | dq_est = q_est >> (LCOUNT_BITS + 3) 297 | q_est -= dq_est 298 | self.assertEqual(q_est >> FRACTION_BITS, qi) 299 | 300 | return (eg, drive_stuff) 301 | 302 | tb = bench() 303 | sim = Simulation(tb) 304 | sim.run() 305 | 306 | def test_lcounter(self): 307 | 308 | def bench(): 309 | clk = Signal(False) 310 | lzero = Signal(True) 311 | lc = lcounter(clk, lzero) 312 | 313 | @instance 314 | def drive_stuff(): 315 | clk.next = 0 316 | for j in range(2): 317 | for i in range((1 << LCOUNT_BITS) - 1): 318 | yield delay(1) 319 | clk.next = 1 320 | yield delay(1) 321 | clk.next = 0 322 | self.assertEqual(lzero, 0) 323 | yield delay(1) 324 | clk.next = 1 325 | yield delay(1) 326 | clk.next = 0 327 | self.assertEqual(lzero, 1) 328 | 329 | return (lc, drive_stuff) 330 | 331 | tb = bench() 332 | sim = Simulation(tb) 333 | sim.run() 334 | 335 | 336 | def simulate(): 337 | clk, keydown, attack, sustain, decay, release, _out = make_adsr_ios() 338 | _adsr = adsr(clk, keydown, attack, sustain, decay, release, _out) 339 | 340 | @instance 341 | def bench(): 342 | clk.next = 0 343 | keydown.next = 0 344 | attack.next = 8 345 | sustain.next = 8 346 | decay.next = 2 347 | release.next = 3 348 | for i in range(10000): 349 | yield delay(1) 350 | clk.next = 1 351 | yield delay(1) 352 | clk.next = 0 353 | keydown.next = 1 354 | for i in range(10000): 355 | yield delay(1) 356 | clk.next = 1 357 | yield delay(1) 358 | clk.next = 0 359 | keydown.next = 0 360 | for i in range(10000): 361 | yield delay(1) 362 | clk.next = 1 363 | yield delay(1) 364 | clk.next = 0 365 | 366 | return (bench, _adsr) 367 | 368 | 369 | if __name__ == '__main__': 370 | if 'hdl' in sys.argv[1:]: 371 | clk, keydown, attack, sustain, decay, release, _out = make_adsr_ios() 372 | toVerilog(adsr, clk, keydown, attack, sustain, decay, release, _out) 373 | elif 'sim' in sys.argv[1:]: 374 | Simulation(traceSignals(simulate)).run() 375 | else: 376 | suite = unittest.TestLoader().loadTestsFromTestCase(TestEnvelopeGenerator) 377 | unittest.TextTestRunner(verbosity=2).run(suite) 378 | -------------------------------------------------------------------------------- /fpga-synth/fpga-synth/BPC3011-Papilio_Pro-general.ucf: -------------------------------------------------------------------------------- 1 | # UCF file for the Papilio Pro board 2 | # Generated by pin_converter, written by Kevin Lindsey 3 | # https://github.com/thelonious/papilio_pins/tree/development/pin_converter 4 | 5 | # Main board wing pin [] to FPGA pin Pxx map 6 | # -------C------- -------B------- -------A------- 7 | # [GND] [C00] P114 [GND] [B00] P99 P100 [A15] 8 | # [2V5] [C01] P115 [2V5] [B01] P97 P98 [A14] 9 | # [3V3] [C02] P116 [3V3] [B02] P92 P93 [A13] 10 | # [5V0] [C03] P117 [5V0] [B03] P87 P88 [A12] 11 | # [C04] P118 [B04] P84 P85 [A11] [5V0] 12 | # [C05] P119 [B05] P82 P83 [A10] [3V3] 13 | # [C06] P120 [B06] P80 P81 [A09] [2V5] 14 | # [C07] P121 [B07] P78 P79 [A08] [GND] 15 | # [GND] [C08] P123 [GND] [B08] P74 P75 [A07] 16 | # [2V5] [C09] P124 [2V5] [B09] P95 P67 [A06] 17 | # [3V3] [C10] P126 [3V3] [B10] P62 P66 [A05] 18 | # [5V0] [C11] P127 [5V0] [B11] P59 P61 [A04] 19 | # [C12] P131 [B12] P57 P58 [A03] [5V0] 20 | # [C13] P132 [B13] P55 P56 [A02] [3V3] 21 | # [C14] P133 [B14] P50 P51 [A01] [2V5] 22 | # [C15] P134 [B15] P47 P48 [A00] [GND] 23 | 24 | ## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration. 25 | CONFIG PROHIBIT=P144; 26 | CONFIG PROHIBIT=P69; 27 | CONFIG PROHIBIT=P60; 28 | 29 | NET CLK LOC="P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK 30 | NET RX LOC="P101" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # RX 31 | NET TX LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX 32 | NET A(0) LOC="P48" | IOSTANDARD=LVTTL; # A0 33 | NET A(1) LOC="P51" | IOSTANDARD=LVTTL; # A1 34 | NET A(2) LOC="P56" | IOSTANDARD=LVTTL; # A2 35 | NET A(3) LOC="P58" | IOSTANDARD=LVTTL; # A3 36 | NET A(4) LOC="P61" | IOSTANDARD=LVTTL; # A4 37 | NET A(5) LOC="P66" | IOSTANDARD=LVTTL; # A5 38 | NET A(6) LOC="P67" | IOSTANDARD=LVTTL; # A6 39 | NET A(7) LOC="P75" | IOSTANDARD=LVTTL; # A7 40 | NET A(8) LOC="P79" | IOSTANDARD=LVTTL; # A8 41 | NET A(9) LOC="P81" | IOSTANDARD=LVTTL; # A9 42 | NET A(10) LOC="P83" | IOSTANDARD=LVTTL; # A10 43 | NET A(11) LOC="P85" | IOSTANDARD=LVTTL; # A11 44 | NET A(12) LOC="P88" | IOSTANDARD=LVTTL; # A12 45 | NET A(13) LOC="P93" | IOSTANDARD=LVTTL; # A13 46 | NET A(14) LOC="P98" | IOSTANDARD=LVTTL; # A14 47 | NET A(15) LOC="P100" | IOSTANDARD=LVTTL; # A15 48 | NET B(0) LOC="P99" | IOSTANDARD=LVTTL; # B0 49 | NET B(1) LOC="P97" | IOSTANDARD=LVTTL; # B1 50 | NET B(2) LOC="P92" | IOSTANDARD=LVTTL; # B2 51 | NET B(3) LOC="P87" | IOSTANDARD=LVTTL; # B3 52 | NET B(4) LOC="P84" | IOSTANDARD=LVTTL; # B4 53 | NET B(5) LOC="P82" | IOSTANDARD=LVTTL; # B5 54 | NET B(6) LOC="P80" | IOSTANDARD=LVTTL; # B6 55 | NET B(7) LOC="P78" | IOSTANDARD=LVTTL; # B7 56 | NET B(8) LOC="P74" | IOSTANDARD=LVTTL; # B8 57 | NET B(9) LOC="P95" | IOSTANDARD=LVTTL; # B9 58 | NET B(10) LOC="P62" | IOSTANDARD=LVTTL; # B10 59 | NET B(11) LOC="P59" | IOSTANDARD=LVTTL; # B11 60 | NET B(12) LOC="P57" | IOSTANDARD=LVTTL; # B12 61 | NET B(13) LOC="P55" | IOSTANDARD=LVTTL; # B13 62 | NET B(14) LOC="P50" | IOSTANDARD=LVTTL; # B14 63 | NET B(15) LOC="P47" | IOSTANDARD=LVTTL; # B15 64 | NET C(0) LOC="P114" | IOSTANDARD=LVTTL; # C0 65 | NET C(1) LOC="P115" | IOSTANDARD=LVTTL; # C1 66 | NET C(2) LOC="P116" | IOSTANDARD=LVTTL; # C2 67 | NET C(3) LOC="P117" | IOSTANDARD=LVTTL; # C3 68 | NET C(4) LOC="P118" | IOSTANDARD=LVTTL; # C4 69 | NET C(5) LOC="P119" | IOSTANDARD=LVTTL; # C5 70 | NET C(6) LOC="P120" | IOSTANDARD=LVTTL; # C6 71 | NET C(7) LOC="P121" | IOSTANDARD=LVTTL; # C7 72 | NET C(8) LOC="P123" | IOSTANDARD=LVTTL; # C8 73 | NET C(9) LOC="P124" | IOSTANDARD=LVTTL; # C9 74 | NET C(10) LOC="P126" | IOSTANDARD=LVTTL; # C10 75 | NET C(11) LOC="P127" | IOSTANDARD=LVTTL; # C11 76 | NET C(12) LOC="P131" | IOSTANDARD=LVTTL; # C12 77 | NET C(13) LOC="P132" | IOSTANDARD=LVTTL; # C13 78 | NET C(14) LOC="P133" | IOSTANDARD=LVTTL; # C14 79 | NET C(15) LOC="P134" | IOSTANDARD=LVTTL; # C15 80 | NET SDRAM_ADDR(0) LOC="P140" | IOSTANDARD=LVTTL; # SDRAM_ADDR0 81 | NET SDRAM_ADDR(1) LOC="P139" | IOSTANDARD=LVTTL; # SDRAM_ADDR1 82 | NET SDRAM_ADDR(2) LOC="P138" | IOSTANDARD=LVTTL; # SDRAM_ADDR2 83 | NET SDRAM_ADDR(3) LOC="P137" | IOSTANDARD=LVTTL; # SDRAM_ADDR3 84 | NET SDRAM_ADDR(4) LOC="P46" | IOSTANDARD=LVTTL; # SDRAM_ADDR4 85 | NET SDRAM_ADDR(5) LOC="P45" | IOSTANDARD=LVTTL; # SDRAM_ADDR5 86 | NET SDRAM_ADDR(6) LOC="P44" | IOSTANDARD=LVTTL; # SDRAM_ADDR6 87 | NET SDRAM_ADDR(7) LOC="P43" | IOSTANDARD=LVTTL; # SDRAM_ADDR7 88 | NET SDRAM_ADDR(8) LOC="P41" | IOSTANDARD=LVTTL; # SDRAM_ADDR8 89 | NET SDRAM_ADDR(9) LOC="P40" | IOSTANDARD=LVTTL; # SDRAM_ADDR9 90 | NET SDRAM_ADDR(10) LOC="P141" | IOSTANDARD=LVTTL; # SDRAM_ADDR10 91 | NET SDRAM_ADDR(11) LOC="P35" | IOSTANDARD=LVTTL; # SDRAM_ADDR11 92 | NET SDRAM_ADDR(12) LOC="P34" | IOSTANDARD=LVTTL; # SDRAM_ADDR12 93 | NET SDRAM_DATA(0) LOC="P9" | IOSTANDARD=LVTTL; # SDRAM_DATA0 94 | NET SDRAM_DATA(1) LOC="P10" | IOSTANDARD=LVTTL; # SDRAM_DATA1 95 | NET SDRAM_DATA(2) LOC="P11" | IOSTANDARD=LVTTL; # SDRAM_DATA2 96 | NET SDRAM_DATA(3) LOC="P12" | IOSTANDARD=LVTTL; # SDRAM_DATA3 97 | NET SDRAM_DATA(4) LOC="P14" | IOSTANDARD=LVTTL; # SDRAM_DATA4 98 | NET SDRAM_DATA(5) LOC="P15" | IOSTANDARD=LVTTL; # SDRAM_DATA5 99 | NET SDRAM_DATA(6) LOC="P16" | IOSTANDARD=LVTTL; # SDRAM_DATA6 100 | NET SDRAM_DATA(7) LOC="P8" | IOSTANDARD=LVTTL; # SDRAM_DATA7 101 | NET SDRAM_DATA(8) LOC="P21" | IOSTANDARD=LVTTL; # SDRAM_DATA8 102 | NET SDRAM_DATA(9) LOC="P22" | IOSTANDARD=LVTTL; # SDRAM_DATA9 103 | NET SDRAM_DATA(10) LOC="P23" | IOSTANDARD=LVTTL; # SDRAM_DATA10 104 | NET SDRAM_DATA(11) LOC="P24" | IOSTANDARD=LVTTL; # SDRAM_DATA11 105 | NET SDRAM_DATA(12) LOC="P26" | IOSTANDARD=LVTTL; # SDRAM_DATA12 106 | NET SDRAM_DATA(13) LOC="P27" | IOSTANDARD=LVTTL; # SDRAM_DATA13 107 | NET SDRAM_DATA(14) LOC="P29" | IOSTANDARD=LVTTL; # SDRAM_DATA14 108 | NET SDRAM_DATA(15) LOC="P30" | IOSTANDARD=LVTTL; # SDRAM_DATA15 109 | NET SDRAM_DQML LOC="P7" | IOSTANDARD=LVTTL; # SDRAM_DQML 110 | NET SDRAM_DQMH LOC="P17" | IOSTANDARD=LVTTL; # SDRAM_DQMH 111 | NET SDRAM_BA(0) LOC="P143" | IOSTANDARD=LVTTL; # SDRAM_BA0 112 | NET SDRAM_BA(1) LOC="P142" | IOSTANDARD=LVTTL; # SDRAM_BA1 113 | NET SDRAM_nWE LOC="P6" | IOSTANDARD=LVTTL; # SDRAM_nWE 114 | NET SDRAM_nCAS LOC="P5" | IOSTANDARD=LVTTL; # SDRAM_nCAS 115 | NET SDRAM_nRAS LOC="P2" | IOSTANDARD=LVTTL; # SDRAM_nRAS 116 | NET SDRAM_CS LOC="P1" | IOSTANDARD=LVTTL; # SDRAM_CS 117 | NET SDRAM_CLK LOC="P32" | IOSTANDARD=LVTTL; # SDRAM_CLK 118 | NET SDRAM_CKE LOC="P33" | IOSTANDARD=LVTTL; # SDRAM_CKE 119 | NET LED1 LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW; # LED1 120 | NET JTAG_TMS LOC="P107" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TMS 121 | NET JTAG_TCK LOC="P109" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TCK 122 | NET JTAG_TDI LOC="P110" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDI 123 | NET JTAG_TDO LOC="P106" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDO 124 | NET FLASH_CS LOC="P38" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CS 125 | NET FLASH_CK LOC="P70" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CK 126 | NET FLASH_SI LOC="P64" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_SI 127 | NET FLASH_SO LOC="P65" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # FLASH_SO 128 | -------------------------------------------------------------------------------- /fpga-synth/fpga-synth/fpga-synth.xise: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 |
385 | -------------------------------------------------------------------------------- /fpga-synth/fpga-synth/fpga_synth.v: -------------------------------------------------------------------------------- 1 | // File: fpga_synth.v 2 | // Generated by MyHDL 0.7 3 | // Date: Tue May 14 22:37:36 2013 4 | 5 | 6 | `timescale 1ns/10ps 7 | 8 | module fpga_synth ( 9 | clk, 10 | param_data, 11 | param_clk, 12 | audio_req, 13 | audio_ack, 14 | dac_bit 15 | ); 16 | 17 | 18 | input clk; 19 | input [3:0] param_data; 20 | input param_clk; 21 | output audio_req; 22 | wire audio_req; 23 | input audio_ack; 24 | output dac_bit; 25 | reg dac_bit; 26 | 27 | reg audio_tick; 28 | reg [23:0] param_counter; 29 | reg [13:0] _output; 30 | reg [15:0] audio_counter; 31 | reg areq_bit; 32 | reg param_tick; 33 | wire [13:0] dsig_interp_result; 34 | reg [17:0] dsig_vc_estimate; 35 | reg [35:0] dsig_sum_of_products; 36 | reg [22:0] dsig__interp_interp_step; 37 | reg dsig__interp_direction; 38 | reg [22:0] dsig__interp_interp_data; 39 | reg [4:0] dsig__interp_rm_counter; 40 | reg [13:0] dsig__interp_delay_1; 41 | reg dsig__interp_rm_tick; 42 | 43 | 44 | 45 | 46 | 47 | always @(posedge clk) begin: FPGA_SYNTH_AUDIO_SAMPLE_RATE 48 | if ((audio_counter >= (800 - 1))) begin 49 | audio_counter <= 0; 50 | audio_tick <= 1'b1; 51 | end 52 | else begin 53 | audio_counter <= (audio_counter + 1); 54 | audio_tick <= 1'b0; 55 | end 56 | end 57 | 58 | 59 | always @(posedge clk) begin: FPGA_SYNTH_PARAM_SAMPLE_RATE 60 | if ((param_counter >= (32000 - 1))) begin 61 | param_counter <= 0; 62 | param_tick <= 1'b1; 63 | end 64 | else begin 65 | param_counter <= (param_counter + 1); 66 | param_tick <= 1'b0; 67 | end 68 | end 69 | 70 | 71 | always @(posedge param_tick) begin: FPGA_SYNTH_BIG_DUMB_SQUARE_WAVE 72 | areq_bit <= (!areq_bit); 73 | if (areq_bit) begin 74 | areq_bit <= 1'b0; 75 | _output <= 0; 76 | end 77 | else begin 78 | areq_bit <= 1'b1; 79 | _output <= 16383; 80 | end 81 | end 82 | 83 | 84 | 85 | assign audio_req = areq_bit; 86 | 87 | 88 | always @(posedge clk) begin: FPGA_SYNTH_DSIG__INTERP_DO_STUFF 89 | if (((dsig__interp_rm_counter == 0) || (dsig__interp_rm_counter == 3) || (dsig__interp_rm_counter == 6) || (dsig__interp_rm_counter == 9) || (dsig__interp_rm_counter == 11) || (dsig__interp_rm_counter == 14) || (dsig__interp_rm_counter == 17) || (dsig__interp_rm_counter == 20) || (dsig__interp_rm_counter == 23))) begin 90 | dsig__interp_rm_tick <= 1'b0; 91 | end 92 | else begin 93 | dsig__interp_rm_tick <= 1'b1; 94 | end 95 | if ((dsig__interp_rm_counter >= 24)) begin 96 | dsig__interp_rm_counter <= 0; 97 | end 98 | else begin 99 | dsig__interp_rm_counter <= (dsig__interp_rm_counter + 1); 100 | end 101 | if (audio_tick) begin 102 | dsig__interp_delay_1 <= _output; 103 | dsig__interp_interp_data <= (dsig__interp_delay_1 << 9); 104 | if ((_output > dsig__interp_delay_1)) begin 105 | dsig__interp_direction <= 1'b1; 106 | dsig__interp_interp_step <= (_output - dsig__interp_delay_1); 107 | end 108 | else begin 109 | dsig__interp_direction <= 1'b0; 110 | dsig__interp_interp_step <= (dsig__interp_delay_1 - _output); 111 | end 112 | end 113 | else if (dsig__interp_rm_tick) begin 114 | if (dsig__interp_direction) begin 115 | dsig__interp_interp_data <= (dsig__interp_interp_data + dsig__interp_interp_step); 116 | end 117 | else begin 118 | dsig__interp_interp_data <= (dsig__interp_interp_data - dsig__interp_interp_step); 119 | end 120 | end 121 | end 122 | 123 | 124 | 125 | assign dsig_interp_result = (dsig__interp_interp_data >>> 9); 126 | 127 | 128 | always @(posedge clk) begin: FPGA_SYNTH_DSIG_DO_STUFF 129 | dac_bit <= (dsig_interp_result > (dsig_sum_of_products >>> 18)); 130 | dsig_vc_estimate <= (dsig_sum_of_products >>> 18); 131 | end 132 | 133 | 134 | always @(dac_bit, dsig_vc_estimate) begin: FPGA_SYNTH_DSIG_MULTIPLY 135 | if (dac_bit) begin 136 | dsig_sum_of_products = ((818 << 14) + (261326 * dsig_vc_estimate)); 137 | end 138 | else begin 139 | dsig_sum_of_products = (261326 * dsig_vc_estimate); 140 | end 141 | end 142 | 143 | endmodule 144 | -------------------------------------------------------------------------------- /fpga-synth/fpga-synth/papilio.ucf: -------------------------------------------------------------------------------- 1 | # UCF file for the Papilio Pro board 2 | # Generated by pin_converter, written by Kevin Lindsey 3 | # https://github.com/thelonious/papilio_pins/tree/development/pin_converter 4 | 5 | # Main board wing pin [] to FPGA pin Pxx map 6 | # -------C------- -------B------- -------A------- 7 | # [GND] [C00] P114 [GND] [B00] P99 P100 [A15] 8 | # [2V5] [C01] P115 [2V5] [B01] P97 P98 [A14] 9 | # [3V3] [C02] P116 [3V3] [B02] P92 P93 [A13] 10 | # [5V0] [C03] P117 [5V0] [B03] P87 P88 [A12] 11 | # [C04] P118 [B04] P84 P85 [A11] [5V0] 12 | # [C05] P119 [B05] P82 P83 [A10] [3V3] 13 | # [C06] P120 [B06] P80 P81 [A09] [2V5] 14 | # [C07] P121 [B07] P78 P79 [A08] [GND] 15 | # [GND] [C08] P123 [GND] [B08] P74 P75 [A07] 16 | # [2V5] [C09] P124 [2V5] [B09] P95 P67 [A06] 17 | # [3V3] [C10] P126 [3V3] [B10] P62 P66 [A05] 18 | # [5V0] [C11] P127 [5V0] [B11] P59 P61 [A04] 19 | # [C12] P131 [B12] P57 P58 [A03] [5V0] 20 | # [C13] P132 [B13] P55 P56 [A02] [3V3] 21 | # [C14] P133 [B14] P50 P51 [A01] [2V5] 22 | # [C15] P134 [B15] P47 P48 [A00] [GND] 23 | 24 | ## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration. 25 | CONFIG PROHIBIT=P144; 26 | CONFIG PROHIBIT=P69; 27 | CONFIG PROHIBIT=P60; 28 | 29 | # Crystal Clock - use 32MHz onboard oscillator 30 | NET "clk" LOC = "P94" | IOSTANDARD = LVCMOS25 | PERIOD = 31.25ns ; 31 | NET "param_data<0>" LOC = "P48" | PULLUP ; 32 | NET "param_data<1>" LOC = "P51" | PULLUP ; 33 | NET "param_data<2>" LOC = "P56" | PULLUP ; 34 | NET "param_data<3>" LOC = "P58" | PULLUP ; 35 | NET "param_clk" LOC = "P61" | PULLUP ; 36 | NET "audio_req" LOC = "P66" | PULLUP ; 37 | NET "audio_ack" LOC = "P67" | PULLUP ; 38 | NET "dac_bit" LOC = "P75"; 39 | # NET "reset" LOC = "P79" | PULLDOWN ; 40 | 41 | #NET CLK LOC="P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK 42 | #NET RX LOC="P101" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # RX 43 | #NET TX LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX 44 | #NET A(0) LOC="P48" | IOSTANDARD=LVTTL; # A0 45 | #NET A(1) LOC="P51" | IOSTANDARD=LVTTL; # A1 46 | #NET A(2) LOC="P56" | IOSTANDARD=LVTTL; # A2 47 | #NET A(3) LOC="P58" | IOSTANDARD=LVTTL; # A3 48 | #NET A(4) LOC="P61" | IOSTANDARD=LVTTL; # A4 49 | #NET A(5) LOC="P66" | IOSTANDARD=LVTTL; # A5 50 | #NET A(6) LOC="P67" | IOSTANDARD=LVTTL; # A6 51 | #NET A(7) LOC="P75" | IOSTANDARD=LVTTL; # A7 52 | #NET A(8) LOC="P79" | IOSTANDARD=LVTTL; # A8 53 | #NET A(9) LOC="P81" | IOSTANDARD=LVTTL; # A9 54 | #NET A(10) LOC="P83" | IOSTANDARD=LVTTL; # A10 55 | #NET A(11) LOC="P85" | IOSTANDARD=LVTTL; # A11 56 | #NET A(12) LOC="P88" | IOSTANDARD=LVTTL; # A12 57 | #NET A(13) LOC="P93" | IOSTANDARD=LVTTL; # A13 58 | #NET A(14) LOC="P98" | IOSTANDARD=LVTTL; # A14 59 | #NET A(15) LOC="P100" | IOSTANDARD=LVTTL; # A15 60 | #NET B(0) LOC="P99" | IOSTANDARD=LVTTL; # B0 61 | #NET B(1) LOC="P97" | IOSTANDARD=LVTTL; # B1 62 | #NET B(2) LOC="P92" | IOSTANDARD=LVTTL; # B2 63 | #NET B(3) LOC="P87" | IOSTANDARD=LVTTL; # B3 64 | #NET B(4) LOC="P84" | IOSTANDARD=LVTTL; # B4 65 | #NET B(5) LOC="P82" | IOSTANDARD=LVTTL; # B5 66 | #NET B(6) LOC="P80" | IOSTANDARD=LVTTL; # B6 67 | #NET B(7) LOC="P78" | IOSTANDARD=LVTTL; # B7 68 | #NET B(8) LOC="P74" | IOSTANDARD=LVTTL; # B8 69 | #NET B(9) LOC="P95" | IOSTANDARD=LVTTL; # B9 70 | #NET B(10) LOC="P62" | IOSTANDARD=LVTTL; # B10 71 | #NET B(11) LOC="P59" | IOSTANDARD=LVTTL; # B11 72 | #NET B(12) LOC="P57" | IOSTANDARD=LVTTL; # B12 73 | #NET B(13) LOC="P55" | IOSTANDARD=LVTTL; # B13 74 | #NET B(14) LOC="P50" | IOSTANDARD=LVTTL; # B14 75 | #NET B(15) LOC="P47" | IOSTANDARD=LVTTL; # B15 76 | #NET C(0) LOC="P114" | IOSTANDARD=LVTTL; # C0 77 | #NET C(1) LOC="P115" | IOSTANDARD=LVTTL; # C1 78 | #NET C(2) LOC="P116" | IOSTANDARD=LVTTL; # C2 79 | #NET C(3) LOC="P117" | IOSTANDARD=LVTTL; # C3 80 | #NET C(4) LOC="P118" | IOSTANDARD=LVTTL; # C4 81 | #NET C(5) LOC="P119" | IOSTANDARD=LVTTL; # C5 82 | #NET C(6) LOC="P120" | IOSTANDARD=LVTTL; # C6 83 | #NET C(7) LOC="P121" | IOSTANDARD=LVTTL; # C7 84 | #NET C(8) LOC="P123" | IOSTANDARD=LVTTL; # C8 85 | #NET C(9) LOC="P124" | IOSTANDARD=LVTTL; # C9 86 | #NET C(10) LOC="P126" | IOSTANDARD=LVTTL; # C10 87 | #NET C(11) LOC="P127" | IOSTANDARD=LVTTL; # C11 88 | #NET C(12) LOC="P131" | IOSTANDARD=LVTTL; # C12 89 | #NET C(13) LOC="P132" | IOSTANDARD=LVTTL; # C13 90 | #NET C(14) LOC="P133" | IOSTANDARD=LVTTL; # C14 91 | #NET C(15) LOC="P134" | IOSTANDARD=LVTTL; # C15 92 | #NET SDRAM_ADDR(0) LOC="P140" | IOSTANDARD=LVTTL; # SDRAM_ADDR0 93 | #NET SDRAM_ADDR(1) LOC="P139" | IOSTANDARD=LVTTL; # SDRAM_ADDR1 94 | #NET SDRAM_ADDR(2) LOC="P138" | IOSTANDARD=LVTTL; # SDRAM_ADDR2 95 | #NET SDRAM_ADDR(3) LOC="P137" | IOSTANDARD=LVTTL; # SDRAM_ADDR3 96 | #NET SDRAM_ADDR(4) LOC="P46" | IOSTANDARD=LVTTL; # SDRAM_ADDR4 97 | #NET SDRAM_ADDR(5) LOC="P45" | IOSTANDARD=LVTTL; # SDRAM_ADDR5 98 | #NET SDRAM_ADDR(6) LOC="P44" | IOSTANDARD=LVTTL; # SDRAM_ADDR6 99 | #NET SDRAM_ADDR(7) LOC="P43" | IOSTANDARD=LVTTL; # SDRAM_ADDR7 100 | #NET SDRAM_ADDR(8) LOC="P41" | IOSTANDARD=LVTTL; # SDRAM_ADDR8 101 | #NET SDRAM_ADDR(9) LOC="P40" | IOSTANDARD=LVTTL; # SDRAM_ADDR9 102 | #NET SDRAM_ADDR(10) LOC="P141" | IOSTANDARD=LVTTL; # SDRAM_ADDR10 103 | #NET SDRAM_ADDR(11) LOC="P35" | IOSTANDARD=LVTTL; # SDRAM_ADDR11 104 | #NET SDRAM_ADDR(12) LOC="P34" | IOSTANDARD=LVTTL; # SDRAM_ADDR12 105 | #NET SDRAM_DATA(0) LOC="P9" | IOSTANDARD=LVTTL; # SDRAM_DATA0 106 | #NET SDRAM_DATA(1) LOC="P10" | IOSTANDARD=LVTTL; # SDRAM_DATA1 107 | #NET SDRAM_DATA(2) LOC="P11" | IOSTANDARD=LVTTL; # SDRAM_DATA2 108 | #NET SDRAM_DATA(3) LOC="P12" | IOSTANDARD=LVTTL; # SDRAM_DATA3 109 | #NET SDRAM_DATA(4) LOC="P14" | IOSTANDARD=LVTTL; # SDRAM_DATA4 110 | #NET SDRAM_DATA(5) LOC="P15" | IOSTANDARD=LVTTL; # SDRAM_DATA5 111 | #NET SDRAM_DATA(6) LOC="P16" | IOSTANDARD=LVTTL; # SDRAM_DATA6 112 | #NET SDRAM_DATA(7) LOC="P8" | IOSTANDARD=LVTTL; # SDRAM_DATA7 113 | #NET SDRAM_DATA(8) LOC="P21" | IOSTANDARD=LVTTL; # SDRAM_DATA8 114 | #NET SDRAM_DATA(9) LOC="P22" | IOSTANDARD=LVTTL; # SDRAM_DATA9 115 | #NET SDRAM_DATA(10) LOC="P23" | IOSTANDARD=LVTTL; # SDRAM_DATA10 116 | #NET SDRAM_DATA(11) LOC="P24" | IOSTANDARD=LVTTL; # SDRAM_DATA11 117 | #NET SDRAM_DATA(12) LOC="P26" | IOSTANDARD=LVTTL; # SDRAM_DATA12 118 | #NET SDRAM_DATA(13) LOC="P27" | IOSTANDARD=LVTTL; # SDRAM_DATA13 119 | #NET SDRAM_DATA(14) LOC="P29" | IOSTANDARD=LVTTL; # SDRAM_DATA14 120 | #NET SDRAM_DATA(15) LOC="P30" | IOSTANDARD=LVTTL; # SDRAM_DATA15 121 | #NET SDRAM_DQML LOC="P7" | IOSTANDARD=LVTTL; # SDRAM_DQML 122 | #NET SDRAM_DQMH LOC="P17" | IOSTANDARD=LVTTL; # SDRAM_DQMH 123 | #NET SDRAM_BA(0) LOC="P143" | IOSTANDARD=LVTTL; # SDRAM_BA0 124 | #NET SDRAM_BA(1) LOC="P142" | IOSTANDARD=LVTTL; # SDRAM_BA1 125 | #NET SDRAM_nWE LOC="P6" | IOSTANDARD=LVTTL; # SDRAM_nWE 126 | #NET SDRAM_nCAS LOC="P5" | IOSTANDARD=LVTTL; # SDRAM_nCAS 127 | #NET SDRAM_nRAS LOC="P2" | IOSTANDARD=LVTTL; # SDRAM_nRAS 128 | #NET SDRAM_CS LOC="P1" | IOSTANDARD=LVTTL; # SDRAM_CS 129 | #NET SDRAM_CLK LOC="P32" | IOSTANDARD=LVTTL; # SDRAM_CLK 130 | #NET SDRAM_CKE LOC="P33" | IOSTANDARD=LVTTL; # SDRAM_CKE 131 | #NET LED1 LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW; # LED1 132 | #NET JTAG_TMS LOC="P107" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TMS 133 | #NET JTAG_TCK LOC="P109" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TCK 134 | #NET JTAG_TDI LOC="P110" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDI 135 | #NET JTAG_TDO LOC="P106" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDO 136 | #NET FLASH_CS LOC="P38" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CS 137 | #NET FLASH_CK LOC="P70" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CK 138 | #NET FLASH_SI LOC="P64" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_SI 139 | #NET FLASH_SO LOC="P65" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # FLASH_SO 140 | -------------------------------------------------------------------------------- /fpga-synth/fpga.v: -------------------------------------------------------------------------------- 1 | // File: fpga.v 2 | // Generated by MyHDL 0.7 3 | // Date: Thu May 30 00:30:01 2013 4 | 5 | 6 | `timescale 1ns/10ps 7 | 8 | module fpga ( 9 | fastclk, 10 | reset, 11 | param_data, 12 | param_clk, 13 | audio_req, 14 | audio_ack, 15 | dac_bit 16 | ); 17 | 18 | 19 | input fastclk; 20 | input reset; 21 | input [3:0] param_data; 22 | input param_clk; 23 | input audio_req; 24 | input audio_ack; 25 | output dac_bit; 26 | wire dac_bit; 27 | 28 | reg [3:0] _release; 29 | reg [13:0] threshold; 30 | reg [23:0] input_driver_count; 31 | reg [1:0] select; 32 | reg [3:0] decay; 33 | reg [3:0] attack; 34 | reg [3:0] sustain; 35 | reg [9:0] aclk_counter; 36 | reg keydown; 37 | reg clk; 38 | reg [23:0] delta_phase; 39 | reg signed [13:0] wavgen_output; 40 | wire signed [13:0] drivers_3_interp_result; 41 | reg drivers_3_dac_bit_internal; 42 | reg [13:0] drivers_3_interp_result_unsigned; 43 | reg [15:0] drivers_3_vc_estimate; 44 | reg [31:0] drivers_3_sum_of_products; 45 | reg [13:0] drivers_3_things_4___out; 46 | reg signed [29:0] drivers_3_things_0_interp_step; 47 | reg signed [29:0] drivers_3_things_0_interp_data; 48 | reg signed [13:0] drivers_3_things_0_delay_1; 49 | wire signed [13:0] drivers_3_things_0_x; 50 | reg [12:0] drivers_2_noise_register_13; 51 | reg [23:0] drivers_2_phase_counter; 52 | reg [15:0] drivers_2_noise_register_16; 53 | 54 | 55 | 56 | 57 | 58 | always @(posedge fastclk, posedge reset) begin: FPGA_DRIVERS_0 59 | if (reset) begin 60 | aclk_counter <= 0; 61 | clk <= 1'b1; 62 | end 63 | else if ((aclk_counter >= 800)) begin 64 | aclk_counter <= 0; 65 | clk <= 1'b1; 66 | end 67 | else begin 68 | aclk_counter <= (aclk_counter + 1); 69 | clk <= 1'b0; 70 | end 71 | end 72 | 73 | 74 | always @(posedge clk, posedge reset) begin: FPGA_DRIVE_INPUTS 75 | attack <= 3; 76 | decay <= 5; 77 | sustain <= 8; 78 | _release <= 0; 79 | delta_phase <= 184549; 80 | select <= 1; 81 | threshold <= 8192; 82 | keydown <= 0; 83 | if (reset) begin 84 | keydown <= 0; 85 | input_driver_count <= 0; 86 | end 87 | else if ((input_driver_count >= (5 * 40000))) begin 88 | keydown <= 0; 89 | input_driver_count <= 0; 90 | end 91 | else if ((input_driver_count < (2 * 40000))) begin 92 | keydown <= 1; 93 | input_driver_count <= (input_driver_count + 1); 94 | end 95 | else begin 96 | keydown <= 0; 97 | input_driver_count <= (input_driver_count + 1); 98 | end 99 | end 100 | 101 | 102 | always @(posedge clk, posedge reset) begin: FPGA_DRIVERS_2_WAVEFORMS 103 | if (reset) begin 104 | drivers_2_noise_register_16 <= 123; 105 | drivers_2_noise_register_13 <= 1787; 106 | drivers_2_phase_counter <= 0; 107 | wavgen_output <= 0; 108 | end 109 | else begin 110 | if ((drivers_2_noise_register_16 == 0)) begin 111 | drivers_2_noise_register_16 <= 123; 112 | end 113 | else if (((((drivers_2_noise_register_16 ^ (drivers_2_noise_register_16 >>> 2)) ^ (drivers_2_noise_register_16 >>> 3)) ^ (drivers_2_noise_register_16 >>> 5)) & 1)) begin 114 | drivers_2_noise_register_16 <= ((1 << 15) + (drivers_2_noise_register_16 >>> 1)); 115 | end 116 | else begin 117 | drivers_2_noise_register_16 <= (drivers_2_noise_register_16 >>> 1); 118 | end 119 | if ((drivers_2_noise_register_13 == 0)) begin 120 | drivers_2_noise_register_13 <= 1787; 121 | end 122 | else if (((((drivers_2_noise_register_13 ^ (drivers_2_noise_register_13 >>> 1)) ^ (drivers_2_noise_register_13 >>> 2)) ^ (drivers_2_noise_register_13 >>> 5)) & 1)) begin 123 | drivers_2_noise_register_13 <= ((1 << 12) + (drivers_2_noise_register_13 >>> 1)); 124 | end 125 | else begin 126 | drivers_2_noise_register_13 <= (drivers_2_noise_register_13 >>> 1); 127 | end 128 | if (((drivers_2_phase_counter + delta_phase) >= (1 << 24))) begin 129 | drivers_2_phase_counter <= ((drivers_2_phase_counter + delta_phase) - (1 << 24)); 130 | end 131 | else begin 132 | drivers_2_phase_counter <= (drivers_2_phase_counter + delta_phase); 133 | end 134 | case (select) 135 | 'h0: begin 136 | wavgen_output <= ((drivers_2_phase_counter - 8388608) >>> 10); 137 | end 138 | 'h1: begin 139 | if ((drivers_2_phase_counter < 8388608)) begin 140 | wavgen_output <= ((drivers_2_phase_counter - 4194304) >>> 9); 141 | end 142 | else begin 143 | wavgen_output <= ((12582912 - drivers_2_phase_counter) >>> 9); 144 | end 145 | end 146 | 'h2: begin 147 | if ((drivers_2_phase_counter > (threshold << (24 - 14)))) begin 148 | wavgen_output <= (16383 - 8192); 149 | end 150 | else begin 151 | wavgen_output <= (-8192); 152 | end 153 | end 154 | default: begin 155 | wavgen_output <= (((drivers_2_noise_register_16 ^ drivers_2_noise_register_13) & 16383) - 8192); 156 | end 157 | endcase 158 | end 159 | end 160 | 161 | 162 | always @(posedge fastclk, posedge reset) begin: FPGA_DRIVERS_3_THINGS_0_DO_STUFF 163 | if (reset) begin 164 | drivers_3_things_0_delay_1 <= 0; 165 | drivers_3_things_0_interp_data <= 0; 166 | drivers_3_things_0_interp_step <= 0; 167 | end 168 | else begin 169 | if (clk) begin 170 | drivers_3_things_0_interp_data <= (drivers_3_things_0_delay_1 << 16); 171 | drivers_3_things_0_delay_1 <= wavgen_output; 172 | drivers_3_things_0_interp_step <= ((((((((drivers_3_things_0_x << 12) + (drivers_3_things_0_x << 10)) + (drivers_3_things_0_x << 6)) + (drivers_3_things_0_x << 5)) + (drivers_3_things_0_x << 4)) + (drivers_3_things_0_x << 3)) + (drivers_3_things_0_x << 1)) + drivers_3_things_0_x); 173 | end 174 | else if (((drivers_3_things_0_interp_data + drivers_3_things_0_interp_step) < -536870912)) begin 175 | drivers_3_things_0_interp_data <= -536870912; 176 | end 177 | else if (((drivers_3_things_0_interp_data + drivers_3_things_0_interp_step) >= 536870912)) begin 178 | drivers_3_things_0_interp_data <= (536870912 - 1); 179 | end 180 | else begin 181 | drivers_3_things_0_interp_data <= (drivers_3_things_0_interp_data + drivers_3_things_0_interp_step); 182 | end 183 | end 184 | end 185 | 186 | 187 | 188 | assign drivers_3_things_0_x = (wavgen_output - drivers_3_things_0_delay_1); 189 | assign drivers_3_interp_result = $signed(drivers_3_things_0_interp_data >>> 16); 190 | 191 | 192 | 193 | assign dac_bit = drivers_3_dac_bit_internal; 194 | 195 | 196 | always @(posedge fastclk, posedge reset) begin: FPGA_DRIVERS_3_DO_STUFF 197 | if (reset) begin 198 | drivers_3_dac_bit_internal <= 0; 199 | drivers_3_vc_estimate <= (1 << 15); 200 | end 201 | else begin 202 | drivers_3_dac_bit_internal <= (drivers_3_interp_result_unsigned > (drivers_3_sum_of_products >>> (32 - 14))); 203 | drivers_3_vc_estimate <= (drivers_3_sum_of_products >>> 16); 204 | end 205 | end 206 | 207 | 208 | always @(drivers_3_dac_bit_internal, drivers_3_vc_estimate) begin: FPGA_DRIVERS_3_MULTIPLY 209 | if (drivers_3_dac_bit_internal) begin 210 | if (((13400823 + (65332 * drivers_3_vc_estimate)) >= (1 << 32))) begin 211 | drivers_3_sum_of_products = ((1 << 32) - 1); 212 | end 213 | else begin 214 | drivers_3_sum_of_products = (13400823 + (65332 * drivers_3_vc_estimate)); 215 | end 216 | end 217 | else begin 218 | drivers_3_sum_of_products = (65332 * drivers_3_vc_estimate); 219 | end 220 | end 221 | 222 | 223 | always @(drivers_3_interp_result) begin: FPGA_DRIVERS_3_THINGS_4_DRIVE__OUT 224 | drivers_3_things_4___out <= (drivers_3_interp_result + (1 << (14 - 1))); 225 | end 226 | 227 | 228 | always @(drivers_3_things_4___out) begin: FPGA_DRIVERS_3_THINGS_4_DRIVE_OUT 229 | drivers_3_interp_result_unsigned <= drivers_3_things_4___out; 230 | end 231 | 232 | endmodule 233 | -------------------------------------------------------------------------------- /fpga-synth/instrument/555_Monostable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wware/fpga-synth/4d5eadcf3c092baa03ca7508b388afbe2783aef3/fpga-synth/instrument/555_Monostable.png -------------------------------------------------------------------------------- /fpga-synth/instrument/README.rst: -------------------------------------------------------------------------------- 1 | An electronic musical instrument 2 | ================================ 3 | 4 | The stuff below is the thinking I was doing a few months back. Then I had the 5 | idea of making a FPGA board for either the Raspberry Pi or Beaglebone Black 6 | which would be a sort of audio coprocessor, with stereo 14-bit serial ADCs and 7 | DACs, with a sort of DSP-ish instruction set, and the hardware for the board 8 | mostly following the hardware on the Papilio Pro. So I noodled around with that 9 | idea, and realized that in order to make it generally programmable with a lot 10 | of hardware parallelism was to have an impossibly large crossbar switch. So 11 | that idea is shelved for later, and I'm back to specifically a music 12 | synthesizer. 13 | 14 | I foresook the Raspberry Pi because I had been reading about how impoverished 15 | it is for GPIO pins, and I figured that would be horrible for trying to get 16 | parameters and control signals in and out of the FPGA. But now I'm inclined to 17 | think that SPI should be fast enough, so I'm going down that route for a while. 18 | 19 | Meanwhile I'm also planning to rework the Python/MyHDL code a bit. I want to 20 | give more thought to design for testability, both in the design phase (when 21 | "test" means unit tests and simulations) and in silico (when "test" might mean 22 | something more like halting all the clocks and pulling out information via 23 | JTAG). 24 | 25 | Earlier thoughts 26 | ---------------- 27 | 28 | The ultimate goal of the FPGA synthesizer work is to build a self-contained 29 | electronic musical instrument. When I first started thinking about it at in my 30 | twenties, I envisioned building it into a piece of PVC tubing four or five long 31 | which would be held like a cello. 32 | 33 | When I discovered that Sparkfun sells a somewhat novel sound transducer (one 34 | large_ and one small_), I reconsidered the physical design to be something more 35 | like a lute or guitar. Given the limits of my carpentry skills, I'm planning on 36 | a tetrahedral body made of 1/4" plywood where one corner of the tetrahedron is 37 | all right angles, to limit the number of strange angles I need to deal with. 38 | It should be possible to cut out the plywood triangles easily on a laser cutter 39 | at `danger!awesome`_. They now offer `DIY cutting`_ if you take a safety class, 40 | which is potentially worthwhile. 41 | 42 | The sounding hole (or on a lute, the rosette) will be a `Sierpinski triangle`_ 43 | design, scaled to be similar to the triangle forming the playing surface, and 44 | situated symmetrically on that surface. 45 | 46 | .. _`large`: https://www.sparkfun.com/products/10975 47 | .. _`small`: https://www.sparkfun.com/products/10917 48 | .. _`danger!awesome`: http://www.dangerawesome.co/ 49 | .. _`DIY cutting`: http://www.dangerawesome.co/2013/03/diy-lasering/ 50 | .. _`Sierpinski triangle`: http://en.wikipedia.org/wiki/Sierpinski_triangle 51 | 52 | The touch-sensitive keyboard 53 | ---------------------------- 54 | 55 | In college I built a very cool touch-sensitive keyboard that scanned the keys 56 | watching for the capacitance of the human body. I've since learned that I can 57 | detect a light or heavy touch by seeing a smaller or larger capacitance, and it 58 | is easily translated into a measurable pulse width. I'm planning on either a 59 | three-octave 37-key keyboard or a four-octave 49-key keyboard. Each key is 60 | connected to one pin of a CD4051_ analog multiplexer, and only one of the 61 | CD4051s is enabled at a time, so each key is scanned individually. A short 62 | low-going pulse is applied to the trigger input of a `555 timer IC`_ in 63 | `monostable mode`_ and its threshold and discharge pins are tied to a pull-up resistor, and 64 | routed through the CD4051 to one of the keys. When you touch the key, it 65 | behaves like a capacitor to ground, increasing the output pulse width. The more 66 | firmly you touch the key, the bigger the pulse width. The trigger pulse needs 67 | to be shorter than the shortest expected RC time constant. Building the circuit 68 | on a `solderless breadboard`_ with a 100K pull-up, I see a pulse width of 4 69 | microseconds when not touching it, and about 12 microseconds when touching it 70 | firmly. This indicates a parasitic capacitance on the breadboard of about 360 71 | picofarads, and a total of about 1000 picofarads when touching firmly. I can 72 | get a lower parasitic capacitance by replacing the breadboard with something 73 | sparser. The touch capacitance will change a bit when protecting the copper key 74 | with a layer of sealant_. I don't want the copper turning green after a few 75 | months or years of playing. I'm going to need to physically mock up a key to 76 | study realistic conditions, including putting on the sealant. 77 | 78 | The time period is measured by a CPLD_ (which pulses the 555 and controls the 79 | CD4051s), probably `this one`_ since it's powerful, affordable, and is already on 80 | a breakout board. It has 256 macrocells so it can hang onto all the key codes 81 | while scanning, and the RPi can fetch them later. (There has been `some FPGA 82 | work`_ done with the Raspberry Pi.) Pulse widths can be encoded into just two or 83 | three bits per key, and the RPi can notice how quickly the pulse width 84 | increases, and convert that to a `MIDI key velocity`_. 85 | 86 | The keyboard_ will be comprised of short lengths of 14-AWG solid bare copper 87 | electrical wire running along the surface of the PVC in the pattern shown at 88 | right. To make the case look as good as possible, I'll drill the holes for the 89 | wire before I paint the PVC. Then put in the wires, then apply the sealant. 90 | 91 | Monostable mode for the 555 92 | --------------------------- 93 | 94 | .. image:: 555_Monostable.png 95 | :alt: 555 schematic 96 | 97 | Keyboard layout 98 | --------------- 99 | 100 | .. image:: http://upload.wikimedia.org/wikipedia/en/0/0b/Wware-rotated-keyboard-small.png 101 | :alt: Keyboard layout 102 | 103 | .. _`CD4051`: http://www.datasheetcatalog.org/datasheets/208/109138_DS.pdf 104 | .. _`555 timer IC`: http://en.wikipedia.org/wiki/555_timer_IC 105 | .. _`monostable mode`: http://en.wikipedia.org/wiki/555_timer_IC#Monostable 106 | .. _`solderless breadboard`: http://en.wikipedia.org/wiki/Breadboard#Solderless_breadboard 107 | .. _`sealant`: http://www.krylon.com/products/make_it_last_clear_sealer/ 108 | .. _`CPLD`: http://en.wikipedia.org/wiki/Complex_programmable_logic_device 109 | .. _`this one`: http://www.digikey.com/product-detail/en/LC4256ZE-B-EVN/220-1146-ND/2641947 110 | .. _`some FPGA work`: http://www.raspberrypi.org/phpBB3/viewtopic.php?t=9085&p=173976 111 | .. _`MIDI key velocity`: http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/noteon.htm 112 | .. _`keyboard`: http://en.wikipedia.org/wiki/Musical_keyboard 113 | -------------------------------------------------------------------------------- /fpga-synth/instrument/body.py: -------------------------------------------------------------------------------- 1 | import pslib 2 | 3 | page = pslib.PostscriptPage() 4 | 5 | A = 24 6 | B = 12 7 | 8 | SQRT2 = 2 ** 0.5 9 | 10 | C = (A**2 - 0.5 * B**2)**.5 + B / SQRT2 11 | D = (A**2 - B**2)**.5 12 | 13 | page.add_polygon(pslib.Point(0, B / SQRT2), 14 | pslib.Point(B / SQRT2, 0), 15 | pslib.Point(B * SQRT2, B / SQRT2)) 16 | 17 | page.add_polygon(pslib.Point(0, B / SQRT2), 18 | pslib.Point(B, B / SQRT2), 19 | pslib.Point(B, D + B / SQRT2)) 20 | 21 | page.add_polygon(pslib.Point(2 * B, B / SQRT2), 22 | pslib.Point(B, B / SQRT2), 23 | pslib.Point(B, D + B / SQRT2)) 24 | 25 | a = pslib.Point(2 * B, B / SQRT2) 26 | b = pslib.Point(2 * B - B / SQRT2, C) 27 | c = pslib.Point(2 * B + B / SQRT2, C) 28 | d = pslib.Point.average(a, b, c) 29 | 30 | page.add_polygon(a, b, c) 31 | 32 | h = 0.4 33 | a1 = h * a + (1 - h) * d 34 | b1 = h * b + (1 - h) * d 35 | c1 = h * c + (1 - h) * d 36 | 37 | apply(page.add_paths, pslib.sierpinski(a1, b1, c1, depth=3, gap=0.5)) 38 | 39 | page.transform(pslib.PS_SPACE.rescale(0.2).translate(pslib.Point(1, 1))).render() 40 | -------------------------------------------------------------------------------- /fpga-synth/instrument/musicbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """\ 4 | MyHDL code for music-box mode of the FPGA synthesizer 5 | 6 | Usage: 7 | PROG [options] 8 | 9 | Options: 10 | -s --sim run a simulation 11 | -h --hdl generate Verilog 12 | -t --unit-test run unit tests 13 | """ 14 | 15 | import docopt 16 | import sys 17 | from myhdl import * 18 | 19 | options = docopt.docopt(__doc__.replace('PROG', sys.argv[0])) 20 | 21 | 22 | def genclocks(clk, clk40, clk2): 23 | """ 24 | Given a 32 MHz clock, generate clocks at 40 kHz and 2 Hz. 25 | """ 26 | counter1 = Signal(intbv(0)[10:]) 27 | counter2 = Signal(intbv(0)[15:]) 28 | 29 | @always(clk.posedge) 30 | def foo(): 31 | if counter1 >= 799: 32 | clk40.next = 1 33 | counter1.next = 0 34 | if counter2 >= 19999: 35 | counter2.next = 0 36 | clk2.next = 0 37 | elif counter2 == 1: 38 | counter2.next = counter2 + 1 39 | clk2.next = 1 40 | else: 41 | counter2.next = counter2 + 1 42 | clk2.next = 0 43 | else: 44 | counter1.next = counter1 + 1 45 | clk40.next = 0 46 | clk2.next = 0 47 | 48 | return foo 49 | 50 | 51 | # Calculate dphase values for the white piano keys for 3 octaves, not 52 | # including the highest C. 53 | if sys.argv[1:2] == ['calculate']: 54 | k = (440. * (1<<24) / 40000) / (2 ** 0.75) 55 | j = 0 56 | for octave in range(3): 57 | for i in (0, 2, 4, 5, 7, 9, 11): 58 | p = 12.0 * octave + i 59 | count = (2.0 ** (p / 12)) * k 60 | print j, int(count + 0.5) 61 | j += 1 62 | sys.exit(0) 63 | 64 | 65 | def get_freq(clk, pitch, freq): 66 | """ 67 | Using dphase values above, map pitch (as an index of the white piano keys) 68 | to dphase value, from middle C to the C two octaves higher. 69 | """ 70 | @always(clk.posedge) 71 | def foo(): 72 | if pitch == 0: 73 | freq.next = 109734 74 | elif pitch == 1: 75 | freq.next = 123172 76 | elif pitch == 2: 77 | freq.next = 138256 78 | elif pitch == 3: 79 | freq.next = 146477 80 | elif pitch == 4: 81 | freq.next = 164415 82 | elif pitch == 5: 83 | freq.next = 184549 84 | elif pitch == 6: 85 | freq.next = 207150 86 | elif pitch == 7: 87 | freq.next = 219467 88 | elif pitch == 8: 89 | freq.next = 246344 90 | elif pitch == 9: 91 | freq.next = 276512 92 | elif pitch == 10: 93 | freq.next = 292954 94 | elif pitch == 11: 95 | freq.next = 328830 96 | elif pitch == 12: 97 | freq.next = 369099 98 | elif pitch == 13: 99 | freq.next = 414299 100 | elif pitch == 14: 101 | freq.next = 438935 102 | else: 103 | freq.next = 0 104 | return foo 105 | 106 | 107 | def voice(clk, clk40, keydn, dphase, _out): 108 | ampl = Signal(intbv(0)[14:]) 109 | phase = Signal(intbv(0)[24:]) 110 | twave = Signal(intbv(0)[14:]) 111 | 112 | @always(clk.posedge) 113 | def piece1(): 114 | if keydn: 115 | ampl.next = 16383 116 | if clk40: 117 | if ampl > 0: 118 | ampl.next = ampl - 1 119 | phase.next = (phase + dphase) & ((1 << 24) - 1) 120 | if (phase & (1 << 23)) != 0: 121 | twave.next = ((1 << 24) - 1 - phase) >> 9 122 | else: 123 | twave.next = phase >> 9 124 | # ampl is unsigned, twave is signed. This is how you multiply a 125 | # signed int by an unsigned int to get a signed result. 126 | _out.next = ((((1<<14) - 1 - ampl) << 13) + ampl * twave) >> 14 127 | 128 | return piece1 129 | 130 | 131 | def dacwriter(clk, clk40, dac_data, dacbit, cs_active): 132 | dac_counter = Signal(intbv(0)[4:]) 133 | dac_data_latched = Signal(intbv(0)[14:]) 134 | 135 | @always_comb 136 | def drive_dacbit(): 137 | if dac_counter < 14: 138 | dacbit.next = ((dac_data_latched >> (13 - dac_counter)) & 1) != 0 139 | else: 140 | dacbit.next = 0 141 | 142 | @always(clk.posedge) 143 | def count(): 144 | if clk40: 145 | dac_counter.next = 0 146 | cs_active.next = 1 147 | dac_data_latched.next = dac_data 148 | elif dac_counter < 16: 149 | if dac_counter == 15: 150 | cs_active.next = 0 151 | dac_counter.next = (dac_counter + 1) & 15 152 | 153 | return (count, drive_dacbit) 154 | 155 | 156 | def tune(clk, clk40, clk2, dphase1, dphase2, dphase3, keydn1, keydn2, keydn3): 157 | pitch1, pitch2, pitch3 = [Signal(intbv(0)[5:]) for i in range(3)] 158 | tunestep = Signal(intbv(0)[4:]) 159 | 160 | f1 = get_freq(clk, pitch1, dphase1) 161 | f2 = get_freq(clk, pitch2, dphase2) 162 | f3 = get_freq(clk, pitch3, dphase3) 163 | 164 | @always(clk.posedge) 165 | def foo(): 166 | if clk2: 167 | if tunestep == 0: 168 | pitch1.next = 0 169 | keydn1.next = 1 170 | pitch2.next = 4 171 | keydn2.next = 1 172 | pitch3.next = 9 173 | keydn3.next = 1 174 | elif tunestep == 1: 175 | pitch1.next = 2 176 | keydn1.next = 1 177 | elif tunestep == 2: 178 | pitch1.next = 4 179 | keydn1.next = 1 180 | elif tunestep == 3: 181 | pitch1.next = 0 182 | keydn1.next = 1 183 | pitch2.next = 5 184 | keydn2.next = 1 185 | pitch3.next = 10 186 | keydn3.next = 1 187 | elif tunestep == 4: 188 | pitch1.next = 3 189 | keydn1.next = 1 190 | elif tunestep == 5: 191 | pitch1.next = 5 192 | keydn1.next = 1 193 | elif tunestep == 6: 194 | pitch1.next = 1 195 | keydn1.next = 1 196 | pitch2.next = 6 197 | keydn2.next = 1 198 | pitch3.next = 11 199 | keydn3.next = 1 200 | elif tunestep == 7: 201 | pitch1.next = 4 202 | keydn1.next = 1 203 | elif tunestep == 8: 204 | pitch1.next = 6 205 | keydn1.next = 1 206 | elif tunestep == 9: 207 | pitch1.next = 7 208 | keydn1.next = 1 209 | pitch2.next = 9 210 | keydn2.next = 1 211 | pitch3.next = 11 212 | keydn3.next = 1 213 | 214 | if tunestep < 12: 215 | tunestep.next = tunestep + 1 216 | else: 217 | tunestep.next = 0 218 | else: 219 | keydn1.next = 0 220 | keydn2.next = 0 221 | keydn3.next = 0 222 | 223 | @always(clk) 224 | def foo2(): 225 | pitch1.next = 0 226 | keydn1.next = 1 227 | pitch2.next = 7 228 | keydn2.next = 1 229 | pitch3.next = 16 230 | keydn3.next = 1 231 | 232 | return (foo, f1, f2, f3) 233 | 234 | 235 | def fpga(clk, out_a, out_b, out_c, out_d): 236 | clk40 = Signal(False) 237 | clk2 = Signal(False) 238 | cs_active = Signal(False) 239 | outb_internal = Signal(False) 240 | _out = Signal(intbv(0)[14:]) 241 | _out1, _out2, _out3 = [Signal(intbv(0)[14:]) for i in range(3)] 242 | dphase1, dphase2, dphase3 = [Signal(intbv(0)[24:]) for i in range(3)] 243 | keydn1, keydn2, keydn3 = [Signal(False) for i in range(3)] 244 | 245 | g = genclocks(clk, clk40, clk2) 246 | dw = dacwriter(clk, clk40, _out, outb_internal, cs_active) 247 | t = tune(clk, clk40, clk2, dphase1, dphase2, dphase3, keydn1, keydn2, keydn3) 248 | 249 | v1 = voice(clk, clk40, keydn1, dphase1, _out1) 250 | v2 = voice(clk, clk40, keydn2, dphase2, _out2) 251 | v3 = voice(clk, clk40, keydn3, dphase3, _out3) 252 | 253 | @always_comb 254 | def out_acd(): 255 | #_out.next = (_out1 + _out2 + _out3) >> 2 256 | _out.next = (_out1 >> 2) + (_out2 >> 2) + (_out3 >> 2) 257 | out_b.next = outb_internal 258 | out_a.next = 0 259 | out_c.next = not clk 260 | out_d.next = not cs_active 261 | 262 | return (g, dw, t, out_acd, v1, v2, v3) 263 | 264 | 265 | def simulate(): 266 | out_a, out_b, out_c, out_d = [Signal(False) for i in range(4)] 267 | clk = Signal(False) 268 | _fpga = fpga(clk, out_a, out_b, out_c, out_d) 269 | 270 | @instance 271 | def bench(): 272 | clk.next = 0 273 | for i in range(1000000): 274 | yield delay(1) 275 | clk.next = 1 276 | yield delay(1) 277 | clk.next = 0 278 | 279 | return (bench, _fpga) 280 | 281 | 282 | if options['--hdl']: 283 | out_a, out_b, out_c, out_d = [Signal(False) for i in range(4)] 284 | clk = Signal(False) 285 | toVerilog(fpga, clk, out_a, out_b, out_c, out_d) 286 | 287 | if options['--sim']: 288 | Simulation(traceSignals(simulate)).run() 289 | 290 | if options['--unit-test']: 291 | raise Exception('not implemented yet') 292 | -------------------------------------------------------------------------------- /fpga-synth/instrument/musicbox.xise: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 |
365 | -------------------------------------------------------------------------------- /fpga-synth/instrument/ppro.ucf: -------------------------------------------------------------------------------- 1 | # UCF file for the Papilio Pro board 2 | # Generated by pin_converter, written by Kevin Lindsey 3 | # https://github.com/thelonious/papilio_pins/tree/development/pin_converter 4 | 5 | # Main board wing pin [] to FPGA pin Pxx map 6 | # -------C------- -------B------- -------A------- 7 | # [GND] [C00] P114 [GND] [B00] P99 P100 [A15] 8 | # [2V5] [C01] P115 [2V5] [B01] P97 P98 [A14] 9 | # [3V3] [C02] P116 [3V3] [B02] P92 P93 [A13] 10 | # [5V0] [C03] P117 [5V0] [B03] P87 P88 [A12] 11 | # [C04] P118 [B04] P84 P85 [A11] [5V0] 12 | # [C05] P119 [B05] P82 P83 [A10] [3V3] 13 | # [C06] P120 [B06] P80 P81 [A09] [2V5] 14 | # [C07] P121 [B07] P78 P79 [A08] [GND] 15 | # [GND] [C08] P123 [GND] [B08] P74 P75 [A07] 16 | # [2V5] [C09] P124 [2V5] [B09] P95 P67 [A06] 17 | # [3V3] [C10] P126 [3V3] [B10] P62 P66 [A05] 18 | # [5V0] [C11] P127 [5V0] [B11] P59 P61 [A04] 19 | # [C12] P131 [B12] P57 P58 [A03] [5V0] 20 | # [C13] P132 [B13] P55 P56 [A02] [3V3] 21 | # [C14] P133 [B14] P50 P51 [A01] [2V5] 22 | # [C15] P134 [B15] P47 P48 [A00] [GND] 23 | 24 | ## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration. 25 | CONFIG PROHIBIT=P144; 26 | CONFIG PROHIBIT=P69; 27 | CONFIG PROHIBIT=P60; 28 | 29 | NET CLK LOC="P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK 30 | #NET RX LOC="P101" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # RX 31 | #NET TX LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX 32 | NET out_a LOC="P48" | IOSTANDARD=LVTTL; # A0 33 | NET out_b LOC="P51" | IOSTANDARD=LVTTL; # A1 34 | NET out_c LOC="P56" | IOSTANDARD=LVTTL; # A2 35 | NET out_d LOC="P58" | IOSTANDARD=LVTTL; # A3 36 | #NET A(0) LOC="P48" | IOSTANDARD=LVTTL; # A0 37 | #NET A(1) LOC="P51" | IOSTANDARD=LVTTL; # A1 38 | #NET A(2) LOC="P56" | IOSTANDARD=LVTTL; # A2 39 | #NET A(3) LOC="P58" | IOSTANDARD=LVTTL; # A3 40 | #NET A(4) LOC="P61" | IOSTANDARD=LVTTL; # A4 41 | #NET A(5) LOC="P66" | IOSTANDARD=LVTTL; # A5 42 | #NET A(6) LOC="P67" | IOSTANDARD=LVTTL; # A6 43 | #NET A(7) LOC="P75" | IOSTANDARD=LVTTL; # A7 44 | #NET A(8) LOC="P79" | IOSTANDARD=LVTTL; # A8 45 | #NET A(9) LOC="P81" | IOSTANDARD=LVTTL; # A9 46 | #NET A(10) LOC="P83" | IOSTANDARD=LVTTL; # A10 47 | #NET A(11) LOC="P85" | IOSTANDARD=LVTTL; # A11 48 | #NET A(12) LOC="P88" | IOSTANDARD=LVTTL; # A12 49 | #NET A(13) LOC="P93" | IOSTANDARD=LVTTL; # A13 50 | #NET A(14) LOC="P98" | IOSTANDARD=LVTTL; # A14 51 | #NET A(15) LOC="P100" | IOSTANDARD=LVTTL; # A15 52 | #NET B(0) LOC="P99" | IOSTANDARD=LVTTL; # B0 53 | #NET B(1) LOC="P97" | IOSTANDARD=LVTTL; # B1 54 | #NET B(2) LOC="P92" | IOSTANDARD=LVTTL; # B2 55 | #NET B(3) LOC="P87" | IOSTANDARD=LVTTL; # B3 56 | #NET B(4) LOC="P84" | IOSTANDARD=LVTTL; # B4 57 | #NET B(5) LOC="P82" | IOSTANDARD=LVTTL; # B5 58 | #NET B(6) LOC="P80" | IOSTANDARD=LVTTL; # B6 59 | #NET B(7) LOC="P78" | IOSTANDARD=LVTTL; # B7 60 | #NET B(8) LOC="P74" | IOSTANDARD=LVTTL; # B8 61 | #NET B(9) LOC="P95" | IOSTANDARD=LVTTL; # B9 62 | #NET B(10) LOC="P62" | IOSTANDARD=LVTTL; # B10 63 | #NET B(11) LOC="P59" | IOSTANDARD=LVTTL; # B11 64 | #NET B(12) LOC="P57" | IOSTANDARD=LVTTL; # B12 65 | #NET B(13) LOC="P55" | IOSTANDARD=LVTTL; # B13 66 | #NET B(14) LOC="P50" | IOSTANDARD=LVTTL; # B14 67 | #NET B(15) LOC="P47" | IOSTANDARD=LVTTL; # B15 68 | #NET C(0) LOC="P114" | IOSTANDARD=LVTTL; # C0 69 | #NET C(1) LOC="P115" | IOSTANDARD=LVTTL; # C1 70 | #NET C(2) LOC="P116" | IOSTANDARD=LVTTL; # C2 71 | #NET C(3) LOC="P117" | IOSTANDARD=LVTTL; # C3 72 | #NET C(4) LOC="P118" | IOSTANDARD=LVTTL; # C4 73 | #NET C(5) LOC="P119" | IOSTANDARD=LVTTL; # C5 74 | #NET C(6) LOC="P120" | IOSTANDARD=LVTTL; # C6 75 | #NET C(7) LOC="P121" | IOSTANDARD=LVTTL; # C7 76 | #NET C(8) LOC="P123" | IOSTANDARD=LVTTL; # C8 77 | #NET C(9) LOC="P124" | IOSTANDARD=LVTTL; # C9 78 | #NET C(10) LOC="P126" | IOSTANDARD=LVTTL; # C10 79 | #NET C(11) LOC="P127" | IOSTANDARD=LVTTL; # C11 80 | #NET C(12) LOC="P131" | IOSTANDARD=LVTTL; # C12 81 | #NET C(13) LOC="P132" | IOSTANDARD=LVTTL; # C13 82 | #NET C(14) LOC="P133" | IOSTANDARD=LVTTL; # C14 83 | #NET C(15) LOC="P134" | IOSTANDARD=LVTTL; # C15 84 | #NET SDRAM_ADDR(0) LOC="P140" | IOSTANDARD=LVTTL; # SDRAM_ADDR0 85 | #NET SDRAM_ADDR(1) LOC="P139" | IOSTANDARD=LVTTL; # SDRAM_ADDR1 86 | #NET SDRAM_ADDR(2) LOC="P138" | IOSTANDARD=LVTTL; # SDRAM_ADDR2 87 | #NET SDRAM_ADDR(3) LOC="P137" | IOSTANDARD=LVTTL; # SDRAM_ADDR3 88 | #NET SDRAM_ADDR(4) LOC="P46" | IOSTANDARD=LVTTL; # SDRAM_ADDR4 89 | #NET SDRAM_ADDR(5) LOC="P45" | IOSTANDARD=LVTTL; # SDRAM_ADDR5 90 | #NET SDRAM_ADDR(6) LOC="P44" | IOSTANDARD=LVTTL; # SDRAM_ADDR6 91 | #NET SDRAM_ADDR(7) LOC="P43" | IOSTANDARD=LVTTL; # SDRAM_ADDR7 92 | #NET SDRAM_ADDR(8) LOC="P41" | IOSTANDARD=LVTTL; # SDRAM_ADDR8 93 | #NET SDRAM_ADDR(9) LOC="P40" | IOSTANDARD=LVTTL; # SDRAM_ADDR9 94 | #NET SDRAM_ADDR(10) LOC="P141" | IOSTANDARD=LVTTL; # SDRAM_ADDR10 95 | #NET SDRAM_ADDR(11) LOC="P35" | IOSTANDARD=LVTTL; # SDRAM_ADDR11 96 | #NET SDRAM_ADDR(12) LOC="P34" | IOSTANDARD=LVTTL; # SDRAM_ADDR12 97 | #NET SDRAM_DATA(0) LOC="P9" | IOSTANDARD=LVTTL; # SDRAM_DATA0 98 | #NET SDRAM_DATA(1) LOC="P10" | IOSTANDARD=LVTTL; # SDRAM_DATA1 99 | #NET SDRAM_DATA(2) LOC="P11" | IOSTANDARD=LVTTL; # SDRAM_DATA2 100 | #NET SDRAM_DATA(3) LOC="P12" | IOSTANDARD=LVTTL; # SDRAM_DATA3 101 | #NET SDRAM_DATA(4) LOC="P14" | IOSTANDARD=LVTTL; # SDRAM_DATA4 102 | #NET SDRAM_DATA(5) LOC="P15" | IOSTANDARD=LVTTL; # SDRAM_DATA5 103 | #NET SDRAM_DATA(6) LOC="P16" | IOSTANDARD=LVTTL; # SDRAM_DATA6 104 | #NET SDRAM_DATA(7) LOC="P8" | IOSTANDARD=LVTTL; # SDRAM_DATA7 105 | #NET SDRAM_DATA(8) LOC="P21" | IOSTANDARD=LVTTL; # SDRAM_DATA8 106 | #NET SDRAM_DATA(9) LOC="P22" | IOSTANDARD=LVTTL; # SDRAM_DATA9 107 | #NET SDRAM_DATA(10) LOC="P23" | IOSTANDARD=LVTTL; # SDRAM_DATA10 108 | #NET SDRAM_DATA(11) LOC="P24" | IOSTANDARD=LVTTL; # SDRAM_DATA11 109 | #NET SDRAM_DATA(12) LOC="P26" | IOSTANDARD=LVTTL; # SDRAM_DATA12 110 | #NET SDRAM_DATA(13) LOC="P27" | IOSTANDARD=LVTTL; # SDRAM_DATA13 111 | #NET SDRAM_DATA(14) LOC="P29" | IOSTANDARD=LVTTL; # SDRAM_DATA14 112 | #NET SDRAM_DATA(15) LOC="P30" | IOSTANDARD=LVTTL; # SDRAM_DATA15 113 | #NET SDRAM_DQML LOC="P7" | IOSTANDARD=LVTTL; # SDRAM_DQML 114 | #NET SDRAM_DQMH LOC="P17" | IOSTANDARD=LVTTL; # SDRAM_DQMH 115 | #NET SDRAM_BA(0) LOC="P143" | IOSTANDARD=LVTTL; # SDRAM_BA0 116 | #NET SDRAM_BA(1) LOC="P142" | IOSTANDARD=LVTTL; # SDRAM_BA1 117 | #NET SDRAM_nWE LOC="P6" | IOSTANDARD=LVTTL; # SDRAM_nWE 118 | #NET SDRAM_nCAS LOC="P5" | IOSTANDARD=LVTTL; # SDRAM_nCAS 119 | #NET SDRAM_nRAS LOC="P2" | IOSTANDARD=LVTTL; # SDRAM_nRAS 120 | #NET SDRAM_CS LOC="P1" | IOSTANDARD=LVTTL; # SDRAM_CS 121 | #NET SDRAM_CLK LOC="P32" | IOSTANDARD=LVTTL; # SDRAM_CLK 122 | #NET SDRAM_CKE LOC="P33" | IOSTANDARD=LVTTL; # SDRAM_CKE 123 | #NET LED1 LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW; # LED1 124 | #NET JTAG_TMS LOC="P107" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TMS 125 | #NET JTAG_TCK LOC="P109" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TCK 126 | #NET JTAG_TDI LOC="P110" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDI 127 | #NET JTAG_TDO LOC="P106" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDO 128 | #NET FLASH_CS LOC="P38" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CS 129 | #NET FLASH_CK LOC="P70" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CK 130 | #NET FLASH_SI LOC="P64" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_SI 131 | #NET FLASH_SO LOC="P65" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # FLASH_SO 132 | -------------------------------------------------------------------------------- /fpga-synth/instrument/pslib.py: -------------------------------------------------------------------------------- 1 | # Python code to generate Postscript 2 | # http://www.physics.emory.edu/~weeks/graphics/howtops1.html 3 | # http://mahi.ucsd.edu/shearer/COMPCLASS/post.txt 4 | 5 | import sys 6 | 7 | 8 | class Point: 9 | def __init__(self, x=0., y=0.): 10 | self.x = x 11 | self.y = y 12 | 13 | def __repr__(self): 14 | return '(%f, %f)' % (self.x, self.y) 15 | 16 | def transform(self, xfm): 17 | return Point(xfm.scale * (self.x + xfm.origin.x), xfm.scale * (self.y + xfm.origin.y)) 18 | 19 | def moveto(self, stream): 20 | stream.write('%f %f moveto ' % (self.x, self.y)) 21 | 22 | def lineto(self, stream): 23 | stream.write('%f %f lineto ' % (self.x, self.y)) 24 | 25 | def __add__(self, other): 26 | return Point(self.x + other.x, self.y + other.y) 27 | 28 | def __sub__(self, other): 29 | return Point(self.x - other.x, self.y - other.y) 30 | 31 | def length(self): 32 | return (self.x * self.x + self.y * self.y) ** .5 33 | 34 | def dist(self, other): 35 | return (self - other).length() 36 | 37 | def __rmul__(self, other): 38 | if isinstance(other, Point): 39 | # dot product 40 | return self.x * other.x + self.y * other.y 41 | else: 42 | # scaling 43 | return Point(self.x * other, self.y * other) 44 | 45 | def parallel(self, other): 46 | # find the component of this 2-vector parallel to the arg 2-vector 47 | return ((self * other) / (other * other)) * other 48 | 49 | def perpendicular(self, other): 50 | # find the component of this 2-vector perpendicular to the arg 2-vector 51 | return self - self.parallel(other) 52 | 53 | def normal(self): 54 | return (1. / (self * self) ** .5) * self 55 | 56 | @classmethod 57 | def average(klas, *points): 58 | sum = klas() 59 | for p in points: 60 | sum = sum + p 61 | return (1. / len(points)) * sum 62 | 63 | 64 | class Transformation: 65 | def __init__(self, scale, origin): 66 | self.scale = scale 67 | self.origin = origin 68 | 69 | def rescale(self, x): 70 | return Transformation(x * self.scale, self.origin) 71 | 72 | def translate(self, offset): 73 | return Transformation(self.scale, self.origin + offset) 74 | 75 | 76 | class Path: 77 | def __init__(self, *points): 78 | self.points = points 79 | 80 | def __repr__(self): 81 | return '<' + self.__class__.__name__ + ' ' + repr(self.points) + '>' 82 | 83 | def transform(self, xfm): 84 | return apply(Path, tuple([p.transform(xfm) for p in self.points])) 85 | 86 | def render(self, stream): 87 | stream.write('newpath ') 88 | self.points[0].moveto(stream) 89 | for p in self.points[1:]: 90 | p.lineto(stream) 91 | stream.write('stroke\n') 92 | 93 | 94 | class Hole: 95 | def __init__(self, center, radius): 96 | self.center = center 97 | self.radius = radius 98 | 99 | def transform(self, xfm): 100 | return Hole(self.center.transform(xfm), xfm.scale * self.radius) 101 | 102 | def render(self, stream): 103 | stream.write('newpath ') 104 | stream.write('%f %f %f 0 360 arc stroke\n' % (self.center.x, self.center.y, self.radius)) 105 | 106 | 107 | class Polygon(Path): 108 | def __init__(self, *points): 109 | self.points = list(points) + [points[0]] 110 | 111 | 112 | class PostscriptPage: 113 | def __init__(self): 114 | self.paths = [] 115 | 116 | def transform(self, xfm): 117 | page = PostscriptPage() 118 | page.paths = [path.transform(xfm) for path in self.paths] 119 | return page 120 | 121 | def add_path(self, path): 122 | self.paths.append(path) 123 | 124 | def add_paths(self, *paths): 125 | [self.paths.append(path) for path in paths] 126 | 127 | def add_polygon(self, *points): 128 | self.paths.append(apply(Polygon, points)) 129 | 130 | def render(self, stream=sys.stdout): 131 | # compute bounding box 132 | xmin = ymin = 1.e20 133 | xmax = ymax = -1.e20 134 | for path in self.paths: 135 | if isinstance(path, Path): 136 | for p in path.points: 137 | xmin = min(xmin, p.x) 138 | xmax = max(xmax, p.x) 139 | ymin = min(ymin, p.y) 140 | ymax = max(ymax, p.y) 141 | elif isinstance(path, Hole): 142 | x, y, r = path.center.x, path.center.y, path.radius 143 | xmin = min(xmin, x - r) 144 | xmax = max(xmax, x + r) 145 | ymin = min(ymin, y - r) 146 | ymax = max(ymax, y + r) 147 | stream.write('%!PS-Adobe-3.0 EPSF-3.0\n') 148 | # llx lly urx ury 149 | stream.write('%%BoundingBox: %f %f %f %f\n' % (xmin, ymin, xmax, ymax)) 150 | [path.render(stream) for path in self.paths] 151 | stream.write('showpage\n') 152 | 153 | 154 | def sierpinski(p1, p2, p3, gap=0., depth=5, minsize=0.): 155 | if depth <= 0: 156 | return [] 157 | if p1.dist(p2) < minsize and p1.dist(p3) < minsize and p2.dist(p3) < minsize: 158 | return [] 159 | def edgepoint(u, v, w, gap=gap): 160 | h = 0.5 * gap * (w - u).perpendicular(v - u).normal() 161 | return Point.average(u, v) + h 162 | a, b, c = Point.average(p2, p3), Point.average(p1, p3), Point.average(p1, p2) 163 | return [ 164 | Polygon(edgepoint(p1, p2, p3), edgepoint(p2, p3, p1), edgepoint(p3, p1, p2)) 165 | ] + \ 166 | sierpinski(p1, b, c, gap, depth-1, minsize) + \ 167 | sierpinski(a, p2, c, gap, depth-1, minsize) + \ 168 | sierpinski(a, b, p3, gap, depth-1, minsize) 169 | 170 | 171 | 172 | PS_SPACE = Transformation(72, Point()) # PS is 72 DPI 173 | -------------------------------------------------------------------------------- /fpga-synth/instrument/ramp.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module foo( 4 | clk, 5 | out_a, 6 | out_b, 7 | out_c, 8 | out_d 9 | ); 10 | 11 | input clk; 12 | output out_a; // A0 13 | output out_b; // A1 14 | output out_c; // A2 15 | output out_d; // A3 16 | wire out_a; 17 | wire out_b; 18 | wire out_c; 19 | wire out_d; 20 | 21 | reg [9:0] fast_counter; 22 | reg [6:0] ramp_counter; 23 | reg [4:0] dac_counter; 24 | reg [14:0] dac_data; 25 | reg cs_active; 26 | wire clk_slow; 27 | assign clk_slow = fast_counter == 0; 28 | assign out_c = !clk; 29 | assign out_b = ((dac_data >> (13 - dac_counter)) & 1) && (dac_counter < 14); 30 | assign out_d = !cs_active; 31 | assign out_a = 0; 32 | 33 | always @(posedge clk) begin 34 | 35 | // the ramp is generated by counting up on each clk_slow tick 36 | // 7 bits => 31.25 kHz / (2**7) = 244-ish Hz, a little below middle C 37 | if (clk_slow) begin 38 | ramp_counter <= ramp_counter + 1; 39 | end 40 | 41 | // clk_slow is 32 MHz divided by 1024, or 31.25 kHz 42 | fast_counter <= fast_counter + 1; 43 | 44 | // on each clk_slow tick, send a sample to the serial 14-bit DAC 45 | if (clk_slow) begin 46 | dac_counter <= 0; 47 | cs_active <= 1; 48 | end else if (dac_counter < 16) begin 49 | if (dac_counter == 15) begin 50 | dac_data <= (ramp_counter << 6) + (1 << 12); 51 | cs_active <= 0; 52 | end 53 | dac_counter <= dac_counter + 1; 54 | end 55 | end 56 | 57 | endmodule 58 | -------------------------------------------------------------------------------- /fpga-synth/instrument/simple_body.py: -------------------------------------------------------------------------------- 1 | # Simplified body, this is just two parallel triangles 2 | 3 | import pslib 4 | 5 | A = 24 6 | B = 16 7 | 8 | page = pslib.PostscriptPage() 9 | 10 | a = pslib.Point(0, 0) 11 | b = pslib.Point(B, 0) 12 | c = pslib.Point(B / 2, A) 13 | d = pslib.Point.average(a, b, c) 14 | 15 | page.add_polygon(a, b, c) 16 | 17 | h = 0.4 18 | a1 = h * a + (1 - h) * d 19 | b1 = h * b + (1 - h) * d 20 | c1 = h * c + (1 - h) * d 21 | 22 | def keyboard(): 23 | holes = [] 24 | m, n = 0.7, 0.375 25 | m, n = 0.7, 0.4 26 | for (a, blo, bhi) in ((0, 1, 7), (1, 0, 12), (2, 5, 17), (3, 10, 22), (4, 15, 21)): 27 | for b in range(blo, bhi): 28 | x = 14 + m * a - n * b 29 | y = 1.5 + m * b + n * a 30 | holes.append(pslib.Hole(pslib.Point(x, y), 0.1)) 31 | return holes 32 | 33 | [page.add_path(h) for h in keyboard()] 34 | 35 | apply(page.add_paths, pslib.sierpinski(a1, b1, c1, depth=3, gap=0.4)) 36 | 37 | # here's the back 38 | # a = pslib.Point(3 * B / 2, A) 39 | # page.add_polygon(a, b, c) 40 | 41 | # page.transform(pslib.PS_SPACE.rescale(0.35)).render() 42 | page.transform(pslib.PS_SPACE).render() 43 | -------------------------------------------------------------------------------- /fpga-synth/output_stage.py: -------------------------------------------------------------------------------- 1 | import math 2 | import unittest 3 | import sys 4 | 5 | from myhdl import Signal, delay, Simulation, always_comb, \ 6 | instance, intbv, bin, toVerilog, toVHDL, always, now, traceSignals 7 | from config import ( 8 | MHZ, 9 | N, 10 | WHOLE, 11 | MASK, 12 | HALF, 13 | unsigned_bus, 14 | signed_bus, 15 | signed_to_unsigned, 16 | unsigned_to_signed 17 | ) 18 | 19 | """ 20 | Make A a 32-bit number. Make B 16 bits, and vc_estimate 16 bits. Then the sum of 21 | A+B*vc_estimate will be 32 bits, clipped to (1<<32)-1 and take 22 | the upper 16 bits for the next value of vc_estimate. Get dac_bit by comparing 23 | vc_estimate with (target << 2). 24 | """ 25 | 26 | DT = 1./MHZ 27 | R = 1000 28 | C = 0.01e-6 29 | ALPHA = math.exp(-DT / (R * C)) 30 | A = int(round((1. - ALPHA) * (1 << 32))) 31 | B = int(round(ALPHA * (1 << 16))) 32 | 33 | 34 | # fastclk is the 32 MHz clock to the FPGA 35 | # clk is the audio-rate clock at 40 kHz, which is high for one fastclk period 36 | def interpolator(fastclk, clk, reset, input_data, interp_out): 37 | 38 | # There are 800 fastclk periods during each clk period, so on each fastclk we want to 39 | # advance 1/800th from the previous sound sample to the current sample. 800 is pretty 40 | # close to (1<<22) divided by 5243, so we can compute a delta by multiplying the 41 | # difference between samples by 5243, which is easy because it's constant and not too 42 | # many non-zero bits. By accumulating this difference and right-shifting 22 bits, we 43 | # arrive almost exactly where we want to end up after 800 accumulations. 44 | 45 | FRACTION_BITS = 16 46 | delay_1 = signed_bus(N) 47 | x = signed_bus(N) 48 | interp_step = signed_bus(N + FRACTION_BITS) 49 | interp_data = signed_bus(N + FRACTION_BITS) 50 | 51 | @always(fastclk.posedge, reset.posedge) 52 | def do_stuff(): 53 | if reset: 54 | delay_1.next = 0 55 | interp_data.next = 0 56 | interp_step.next = 0 57 | else: 58 | if clk: 59 | interp_data.next = delay_1 << FRACTION_BITS 60 | delay_1.next = input_data 61 | # multiply by 5243 in binary 62 | interp_step.next = (x << 12) + (x << 10) + (x << 6) + (x << 5) + \ 63 | (x << 4) + (x << 3) + (x << 1) + x 64 | elif (interp_data + interp_step) < interp_data.min: 65 | interp_data.next = interp_data.min 66 | elif (interp_data + interp_step) >= interp_data.max: 67 | interp_data.next = interp_data.max - 1 68 | else: 69 | interp_data.next = interp_data + interp_step 70 | 71 | @always_comb 72 | def rightshift_for_output(): 73 | x.next = input_data - delay_1 74 | interp_out.next = interp_data >> FRACTION_BITS 75 | 76 | return (do_stuff, rightshift_for_output) 77 | 78 | 79 | def delta_sigma_dac(fastclk, clk, reset, input_data, dac_bit): 80 | 81 | interp_result = signed_bus(N) 82 | interp_result_unsigned = unsigned_bus(N) 83 | # the input of the Xilinx multiplier is an 18-bit factor 84 | vc_estimate = unsigned_bus(16) 85 | # the output of the Xilinx multiplier is a 36-bit product 86 | sum_of_products = unsigned_bus(32) 87 | dac_bit_internal = Signal(False) 88 | 89 | @always_comb 90 | def drive_dac_bit(): 91 | dac_bit.next = dac_bit_internal 92 | 93 | @always(fastclk.posedge, reset.posedge) 94 | def do_stuff(): 95 | # sum_of_products is the next value for vc_estimate, with lots of fraction 96 | # bits. vc_estimate already has fraction bits beyond N. All these fraction 97 | # bits are helpful in keeping out audible artifacts. 98 | if reset: 99 | dac_bit_internal.next = 0 100 | vc_estimate.next = 1 << 15 101 | else: 102 | dac_bit_internal.next = interp_result_unsigned > (sum_of_products >> (32 - N)) 103 | vc_estimate.next = sum_of_products >> 16 104 | 105 | @always_comb 106 | def multiply(): 107 | if dac_bit_internal: 108 | if A + (B * vc_estimate) >= (1 << 32): 109 | sum_of_products.next = (1 << 32) - 1 110 | else: 111 | sum_of_products.next = A + (B * vc_estimate) 112 | else: 113 | sum_of_products.next = B * vc_estimate 114 | 115 | things = [ 116 | # Interpolation is a huge help with anti-aliasing. 117 | interpolator(fastclk, clk, reset, input_data, interp_result), 118 | drive_dac_bit, 119 | do_stuff, 120 | multiply, 121 | signed_to_unsigned(N, interp_result, interp_result_unsigned) 122 | ] 123 | return things 124 | 125 | def make_dsig_ios(): 126 | fastclk = Signal(False) 127 | clk = Signal(False) 128 | input_data = signed_bus(N) 129 | dac_bit = Signal(False) 130 | return (fastclk, clk, input_data, dac_bit) 131 | 132 | 133 | class TestOutputStage(unittest.TestCase): 134 | pass # TODO write some tests 135 | 136 | 137 | def simulate(): 138 | fastclk, clk, input_data, dac_bit = make_dsig_ios() 139 | dsig = delta_sigma_dac(fastclk, clk, input_data, dac_bit) 140 | 141 | @instance 142 | def bench(): 143 | fastclk.next = 0 144 | clk.next = 0 145 | input_data.next = 0 146 | yield delay(1) 147 | for j in range(100): 148 | for i in range(800): 149 | fastclk.next = 1 150 | yield delay(1) 151 | fastclk.next = 0 152 | yield delay(1) 153 | input_data.next = input_data + 50 154 | fastclk.next = 1 155 | clk.next = 1 156 | yield delay(1) 157 | fastclk.next = 0 158 | yield delay(1) 159 | clk.next = 0 160 | 161 | return (bench, dsig) 162 | 163 | 164 | if __name__ == '__main__': 165 | if 'hdl' in sys.argv[1:]: 166 | fastclk, clk, input_data, dac_bit = make_dsig_ios() 167 | toVerilog(dsig, fastclk, clk, input_data, dac_bit) 168 | elif 'sim' in sys.argv[1:]: 169 | Simulation(traceSignals(simulate)).run() 170 | else: 171 | suite = unittest.TestLoader().loadTestsFromTestCase(TestOutputStage) 172 | unittest.TextTestRunner(verbosity=2).run(suite) 173 | -------------------------------------------------------------------------------- /fpga-synth/param_loading.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import math 3 | import sys 4 | from myhdl import Signal, delay, Simulation, always_comb, \ 5 | instance, intbv, bin, toVerilog, toVHDL, always, now, traceSignals 6 | 7 | def get_nibbles(n): 8 | return [Signal(intbv(0)[4:]) for i in range(n)] 9 | 10 | 11 | def bitfields(source, *args): 12 | retval = [] 13 | 14 | def make_f(source, offset, len, signal): 15 | @always_comb 16 | def f(): 17 | signal.next = (source >> offset) & ((1 << len) - 1) 18 | return f 19 | 20 | for offset, len, signal in args: 21 | retval.append(make_f(source, offset, len, signal)) 22 | return retval 23 | 24 | class DaisyChain: 25 | 26 | ''' 27 | This works a bit like JTAG except that it's a four-bit-wide bus. There are two 28 | clocks, pclk and outclk. Pclk advances the nibbles along the daisy chain, and 29 | outclk clocks them all simultaneously to the output latches. 30 | ''' 31 | 32 | @classmethod 33 | def set_up_clocks(cls, pclk, outclk): 34 | cls.pclk = pclk 35 | cls.outclk = outclk 36 | 37 | def __init__(self, pdata_in): 38 | self.pdata_in = pdata_in 39 | 40 | def _param_nibble(self, out, pdata_out): 41 | pdata_in = self.pdata_in 42 | self.pdata_in = pdata_out 43 | q = Signal(intbv(0)[4:]) 44 | r = Signal(intbv(0)[4:]) 45 | 46 | @always(self.pclk.posedge) 47 | def f(): 48 | q.next = pdata_in 49 | 50 | @always(self.outclk.posedge) 51 | def g(): 52 | r.next = q 53 | 54 | @always_comb 55 | def h(): 56 | pdata_out.next = q 57 | out.next = r 58 | 59 | return (f, g, h) 60 | 61 | def param_8(self, out, pdata_out): 62 | a = Signal(intbv(0)[4:]) 63 | b = Signal(intbv(0)[4:]) 64 | q = Signal(intbv(0)[4:]) 65 | 66 | nibble0 = self._param_nibble(a, q) 67 | nibble1 = self._param_nibble(b, pdata_out) 68 | 69 | @always_comb 70 | def f(): 71 | out.next = (a << 4) | b 72 | 73 | return (f, nibble0, nibble1) 74 | 75 | def param_16(self, out, pdata_out, limit_bits=16): 76 | a = Signal(intbv(0)[8:]) 77 | b = Signal(intbv(0)[8:]) 78 | q = Signal(intbv(0)[4:]) 79 | pa = self.param_8(a, q) 80 | pb = self.param_8(b, pdata_out) 81 | 82 | @always_comb 83 | def f(): 84 | out.next = ((a << 8) | b) & ((1 << limit_bits) - 1) 85 | 86 | return (pa, pb, f) 87 | 88 | def param_24(self, out, pdata_out): 89 | a = Signal(intbv(0)[16:]) 90 | b = Signal(intbv(0)[8:]) 91 | q = Signal(intbv(0)[4:]) 92 | pa = self.param_16(a, q) 93 | pb = self.param_8(b, pdata_out) 94 | 95 | @always_comb 96 | def f(): 97 | out.next = (a << 8) | b 98 | 99 | return (pa, pb, f) 100 | 101 | def param_32(self, out, pdata_out): 102 | a = Signal(intbv(0)[16:]) 103 | b = Signal(intbv(0)[16:]) 104 | q = Signal(intbv(0)[4:]) 105 | pa = self.param_16(a, q) 106 | pb = self.param_16(b, pdata_out) 107 | 108 | @always_comb 109 | def f(): 110 | out.next = (a << 16) | b 111 | 112 | return (pa, pb, f) 113 | 114 | 115 | def param_clock_driver(byte_sequence, pclk, period): 116 | 117 | ''' 118 | Helpful for writing tests. 119 | ''' 120 | 121 | NUM_NIBBLES = len(byte_sequence) * 2 122 | 123 | @instance 124 | def clock_driver(): 125 | for i in range(NUM_NIBBLES): 126 | pclk.next = 0 127 | yield delay(period / 2) 128 | pclk.next = 1 129 | yield delay(period / 2) 130 | pclk.next = 0 # 80 131 | 132 | return clock_driver 133 | 134 | def daisy_chain_driver(byte_sequence, pdata, outclk, period): 135 | 136 | ''' 137 | Helpful for writing tests. 138 | ''' 139 | 140 | @instance 141 | def pdata_driver(): 142 | for x in byte_sequence: 143 | pdata.next = x & 0xF 144 | yield delay(period) 145 | pdata.next = (x >> 4) & 0xF 146 | yield delay(period) 147 | yield delay(period / 2) 148 | outclk.next = 1 149 | yield delay(period / 2) 150 | outclk.next = 0 151 | yield delay(2 * period) 152 | pdata.next = 0 153 | 154 | return pdata_driver 155 | 156 | 157 | ################ 158 | 159 | def test_bench(): 160 | 161 | # these are clock and input signals for the whole daisychain 162 | pclk = Signal(False) 163 | pdata = Signal(intbv(0)[4:]) 164 | outclk = Signal(False) 165 | DaisyChain.set_up_clocks(pclk, outclk) 166 | 167 | # these are the parameters driven by the daisychain 168 | result1 = Signal(intbv(0)[8:]) 169 | result2 = Signal(intbv(0)[24:]) 170 | result3 = Signal(intbv(0)[32:]) 171 | 172 | param_bytes = ( 173 | 0x26, # result3, little-endian 174 | 0x59, 175 | 0x41, 176 | 0x31, 177 | 0x21, # result2, little-endian 178 | 0x43, 179 | 0x65, 180 | 0x87) # result 1 181 | 182 | # daisychain links 183 | a, b, c = get_nibbles(3) 184 | chain = DaisyChain(pdata) 185 | 186 | r = ( 187 | chain.param_8(result1, a), 188 | chain.param_24(result2, b), 189 | chain.param_32(result3, c), 190 | param_clock_driver(param_bytes, pclk, 10), 191 | daisy_chain_driver(param_bytes, pdata, outclk, 10), 192 | ) 193 | return r 194 | 195 | if __name__ == '__main__': 196 | Simulation(traceSignals(test_bench)).run() 197 | -------------------------------------------------------------------------------- /fpga-synth/synth.py: -------------------------------------------------------------------------------- 1 | # MyHDL code for a Moog-style synth done in DSP on a Xilinx FPGA 2 | 3 | import unittest 4 | import sys 5 | from myhdl import Signal, delay, Simulation, always_comb, \ 6 | instance, intbv, bin, toVerilog, toVHDL, always, now, traceSignals 7 | 8 | from wavegen import waveform_generator, make_wavgen_ios 9 | from param_loading import ( 10 | get_nibbles, 11 | DaisyChain, 12 | bitfields, 13 | daisy_chain_driver, 14 | param_clock_driver 15 | ) 16 | from output_stage import delta_sigma_dac 17 | from amps_filters import vca 18 | from envgen import adsr 19 | from config import ( 20 | MHZ, 21 | AUDIO_RATE, 22 | DIVIDER, 23 | N, 24 | WHOLE, 25 | HALF, 26 | MASK, 27 | SECOND, 28 | compute_delta_phase, 29 | unsigned_bus, 30 | signed_bus, 31 | signed_to_unsigned, 32 | unsigned_to_signed 33 | ) 34 | 35 | 36 | A_ABOVE_MIDDLE_C = compute_delta_phase(440) 37 | DELTA_PHASE = A_ABOVE_MIDDLE_C 38 | 39 | 40 | def make_fpga_ios(): 41 | fastclk = Signal(False) 42 | reset = Signal(False) 43 | param_data = unsigned_bus(4) 44 | param_clk = Signal(False) 45 | audio_req = Signal(False) 46 | audio_ack = Signal(False) 47 | dac_bit = Signal(True) 48 | return (fastclk, reset, param_data, param_clk, audio_req, audio_ack, dac_bit) 49 | 50 | 51 | def fpga(fastclk, reset, param_data, param_clk, audio_req, audio_ack, dac_bit): 52 | 53 | aclk_counter = unsigned_bus(10) 54 | clk = Signal(False) 55 | 56 | # audio rate clock 57 | @always(fastclk.posedge, reset.posedge) 58 | def drive_audio_clock(): 59 | if reset: 60 | aclk_counter.next = 0 61 | clk.next = True 62 | elif aclk_counter >= 800: 63 | aclk_counter.next = 0 64 | clk.next = True 65 | else: 66 | aclk_counter.next = aclk_counter + 1 67 | clk.next = False 68 | 69 | ignored, ignored2, select, threshold, delta_phase, wavgen_output = make_wavgen_ios() 70 | 71 | keydown = Signal(False) 72 | select = unsigned_bus(2) 73 | attack = unsigned_bus(4) 74 | decay = unsigned_bus(4) 75 | sustain = unsigned_bus(4) 76 | _release = unsigned_bus(4) 77 | amplitude = unsigned_bus(N) 78 | _output = signed_bus(N) 79 | 80 | # more bits than we really need, 18 bits would give 6.5536 seconds 81 | input_driver_count = unsigned_bus(24) 82 | 83 | @always(clk.posedge, reset.posedge) 84 | def drive_inputs(): 85 | attack.next = 3 86 | decay.next = 5 87 | sustain.next = 8 88 | _release.next = 0 89 | delta_phase.next = DELTA_PHASE 90 | select.next = 1 91 | threshold.next = HALF 92 | keydown.next = 0 93 | if reset: 94 | keydown.next = 0 95 | input_driver_count.next = 0 96 | elif input_driver_count >= 5 * SECOND: 97 | keydown.next = 0 98 | input_driver_count.next = 0 99 | elif input_driver_count < 2 * SECOND: 100 | keydown.next = 1 101 | input_driver_count.next = input_driver_count + 1 102 | else: 103 | keydown.next = 0 104 | input_driver_count.next = input_driver_count + 1 105 | 106 | drivers = [ 107 | drive_audio_clock, 108 | drive_inputs, 109 | waveform_generator(clk, reset, select, threshold, delta_phase, wavgen_output), 110 | # adsr(clk, reset, keydown, attack, decay, sustain, _release, amplitude), 111 | # vca(fastclk, reset, wavgen_output, amplitude, _output), 112 | delta_sigma_dac(fastclk, clk, reset, wavgen_output, dac_bit), 113 | ] 114 | return drivers 115 | 116 | def simulate(): 117 | 118 | # don't make the simulation take all day 119 | global SECOND, DELTA_PHASE 120 | SECOND = 200 121 | DELTA_PHASE = compute_delta_phase(1000) 122 | 123 | fastclk, reset, param_data, param_clk, audio_req, audio_ack, dac_bit = make_fpga_ios() 124 | 125 | @instance 126 | def bench(): 127 | fastclk.next = 0 128 | reset.next = 0 129 | param_data.next = 0 130 | param_clk.next = 0 131 | audio_req.next = 0 132 | audio_ack.next = 0 133 | yield delay(1) 134 | reset.next = 1 135 | yield delay(1) 136 | reset.next = 0 137 | # for i in range(8 * SECOND * 32000000 / 40000): 138 | for i in range(SECOND * 32000000 / 40000): 139 | yield delay(1) 140 | fastclk.next = 1 141 | yield delay(1) 142 | fastclk.next = 0 143 | 144 | stuff = [ 145 | bench, 146 | fpga(fastclk, reset, param_data, param_clk, audio_req, audio_ack, dac_bit) 147 | ] 148 | return stuff 149 | 150 | 151 | class TestFpga(unittest.TestCase): 152 | # TODO write tests 153 | pass 154 | 155 | 156 | if __name__ == '__main__': 157 | if 'hdl' in sys.argv[1:]: 158 | fastclk, reset, param_data, param_clk, audio_req, audio_ack, dac_bit = make_fpga_ios() 159 | toVerilog(fpga, fastclk, reset, param_data, param_clk, audio_req, audio_ack, dac_bit) 160 | elif 'sim' in sys.argv[1:]: 161 | Simulation(traceSignals(simulate)).run() 162 | else: 163 | suite = unittest.TestLoader().loadTestsFromTestCase(TestFpga) 164 | unittest.TextTestRunner(verbosity=2).run(suite) 165 | -------------------------------------------------------------------------------- /fpga-synth/tb_fpga.tf: -------------------------------------------------------------------------------- 1 | module tb_fpga; 2 | 3 | reg fastclk; 4 | reg reset; 5 | reg [3:0] param_data; 6 | reg param_clk; 7 | reg audio_req; 8 | reg audio_ack; 9 | wire dac_bit; 10 | 11 | initial begin 12 | fastclk <= 0; 13 | reset <= 0; 14 | param_data <= 0; 15 | param_clk <= 0; 16 | audio_req <= 0; 17 | audio_ack <= 0; 18 | #10 reset <= 1; 19 | #50 reset <= 0; 20 | #20 repeat (2500000) begin 21 | #25 fastclk <= 1; 22 | #25 fastclk <= 0; 23 | end 24 | end 25 | 26 | fpga dut( 27 | fastclk, 28 | reset, 29 | param_data, 30 | param_clk, 31 | audio_req, 32 | audio_ack, 33 | dac_bit 34 | ); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /fpga-synth/wavegen.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | from myhdl import Signal, delay, Simulation, always_comb, \ 4 | instance, intbv, bin, toVerilog, toVHDL, always, now, traceSignals 5 | from config import ( 6 | PHASEWIDTH, 7 | N, 8 | HALF, 9 | MASK, 10 | RAMP, 11 | TRIANGLE, 12 | SQWAVE, 13 | NOISE, 14 | unsigned_bus, 15 | signed_bus 16 | ) 17 | from math import log 18 | 19 | def log2(x): 20 | if x < 0: 21 | return (False, log(-1.0 * x) / log(2.0)) 22 | else: 23 | return (True, log(1.0 * x) / log(2.0)) 24 | 25 | # Ramp wave, triangle wave, PW-modulated square wave, or noise 26 | # Clock this at the 40 kHz audio rate 27 | def waveform_generator(clk, reset, select, threshold, delta_phase, _output): 28 | 29 | NOISEWIDTH16 = 16 # depends on polynomial 30 | NOISEWIDTH13 = 13 31 | HALFPHASE = 1 << (PHASEWIDTH - 1) 32 | QUARTERPHASE = 1 << (PHASEWIDTH - 2) 33 | THREEQUARTERPHASE = HALFPHASE + QUARTERPHASE 34 | TRIANGLESHIFT = (PHASEWIDTH - N) - 1 35 | RAMPSHIFT = PHASEWIDTH - N 36 | 37 | phase_counter = unsigned_bus(PHASEWIDTH) 38 | noise_register_16 = unsigned_bus(NOISEWIDTH16) 39 | noise_register_13 = unsigned_bus(NOISEWIDTH13) 40 | 41 | @always(clk.posedge, reset.posedge) 42 | def waveforms(): 43 | if reset: 44 | noise_register_16.next = 123 45 | noise_register_13.next = 1787 46 | phase_counter.next = 0 47 | _output.next = 0 48 | else: 49 | if noise_register_16 == 0: 50 | noise_register_16.next = 123 51 | elif (noise_register_16 ^ (noise_register_16 >> 2) ^ 52 | (noise_register_16 >> 3) ^ (noise_register_16 >> 5)) & 1: 53 | noise_register_16.next = (1 << 15) + (noise_register_16 >> 1) 54 | else: 55 | noise_register_16.next = (noise_register_16 >> 1) 56 | 57 | if noise_register_13 == 0: 58 | noise_register_13.next = 1787 59 | elif (noise_register_13 ^ (noise_register_13 >> 1) ^ 60 | (noise_register_13 >> 2) ^ (noise_register_13 >> 5)) & 1: 61 | noise_register_13.next = (1 << 12) + (noise_register_13 >> 1) 62 | else: 63 | noise_register_13.next = (noise_register_13 >> 1) 64 | 65 | if phase_counter + delta_phase >= (1 << PHASEWIDTH): 66 | phase_counter.next = phase_counter + delta_phase - (1 << PHASEWIDTH) 67 | else: 68 | phase_counter.next = phase_counter + delta_phase 69 | 70 | if select == RAMP: 71 | _output.next = (phase_counter - HALFPHASE) >> RAMPSHIFT 72 | elif select == TRIANGLE: 73 | if phase_counter < HALFPHASE: 74 | _output.next = (phase_counter - QUARTERPHASE) >> TRIANGLESHIFT 75 | else: 76 | _output.next = \ 77 | (THREEQUARTERPHASE - phase_counter) >> TRIANGLESHIFT 78 | elif select == SQWAVE: 79 | if phase_counter > (threshold << (PHASEWIDTH - N)): 80 | _output.next = MASK - HALF 81 | else: 82 | _output.next = -HALF 83 | else: # NOISE 84 | _output.next = \ 85 | ((noise_register_16 ^ noise_register_13) & MASK) - HALF 86 | 87 | return waveforms 88 | 89 | def make_wavgen_ios(): 90 | clk = Signal(False) 91 | reset = Signal(False) 92 | select = unsigned_bus(2) 93 | threshold = unsigned_bus(N) 94 | delta_phase = unsigned_bus(PHASEWIDTH) 95 | _output = signed_bus(N) 96 | return (clk, reset, select, threshold, delta_phase, _output) 97 | 98 | 99 | class TestWaveformGenerator(unittest.TestCase): 100 | 101 | def test_ramp(self): 102 | pass 103 | 104 | def test_triangle(self): 105 | pass 106 | 107 | def test_square_wave(self): 108 | pass 109 | 110 | def test_noise(self): 111 | pass 112 | 113 | 114 | def simulate(): 115 | from config import DELTA_PHASE 116 | clk, reset, select, threshold, delta_phase, _output = make_wavgen_ios() 117 | wavgen = waveform_generator(clk, reset, select, threshold, delta_phase, _output) 118 | 119 | @instance 120 | def bench(): 121 | clk.next = 0 122 | yield delay(1) 123 | reset.next = 1 124 | yield delay(1) 125 | reset.next = 0 126 | select.next = RAMP 127 | delta_phase.next = DELTA_PHASE 128 | threshold.next = HALF 129 | for i in range(1000): 130 | yield delay(1) 131 | clk.next = 1 132 | yield delay(1) 133 | clk.next = 0 134 | select.next = TRIANGLE 135 | for i in range(1000): 136 | yield delay(1) 137 | clk.next = 1 138 | yield delay(1) 139 | clk.next = 0 140 | select.next = SQWAVE 141 | for i in range(1000): 142 | yield delay(1) 143 | clk.next = 1 144 | yield delay(1) 145 | clk.next = 0 146 | select.next = NOISE 147 | for i in range(1000): 148 | yield delay(1) 149 | clk.next = 1 150 | yield delay(1) 151 | clk.next = 0 152 | 153 | return (bench, wavgen) 154 | 155 | 156 | if __name__ == '__main__': 157 | if 'hdl' in sys.argv[1:]: 158 | clk, reset, select, threshold, delta_phase, _output = make_wavgen_ios() 159 | toVerilog(waveform_generator, clk, reset, select, threshold, delta_phase, _output) 160 | elif 'sim' in sys.argv[1:]: 161 | Simulation(traceSignals(simulate)).run() 162 | else: 163 | suite = unittest.TestLoader().loadTestsFromTestCase(TestEnvelopeGenerator) 164 | unittest.TextTestRunner(verbosity=2).run(suite) 165 | --------------------------------------------------------------------------------