Oh, yeah, that’s a bit closer to what I had in mind … :). Thanks for the pointer! (and thanks Clifford!)
You have an awful lot of blocking assignments (=) in your code. I suspect a lot of them should be non-blocking assignments (<=). I suspect this is what is causing you to use so many resources, and arachne-pnr to take so long.
Nice tune, though.
I’ve just been looking into it a bit now - it seems like it’s the “flanger” effect that’s taking the lions share of the resources, and that, in turn, seems to be because its delay-line storage is not being inferred as a block RAM (I’m sure there’s a good reason for that, but I don’t know it at this point)…
I’ve just started trying to rewrite the flanger around a SB_RAM256x16 RAM block - ie. from the SiliconBlue library (the dual-port nature makes it ideal - It allows me to have separate read/write pointers), but it seems like yosys is unable to recognise it:
\SB_RAM256x16' referenced in module\flanger’ in cell `\delay_buffer’ is not part of the design.
After looking at the code here: https://github.com/YosysHQ/yosys/blob/master/techlibs/ice40/cells_sim.v. I wonder whether I need to use a SB_RAM40_4K block instead, and pass in READ_MODE and WRITE_MODE parameters.
Duly noted re: the blocking assignments too. I’m learning more about this as I go, and I’ll probably do an optimisation pass at some point to fix some of the atrocities I’ve been creating.
Yes, I get an explosion of resource usage, when BRAM is not used for memory. At least one case of that was caused by typo where I used a blocking assignment instead of a non-blocking one.
You should not need to use SB_RAM… block. Just put your RAM in a separate module, make sure it uses non-blocking assignments, has inputs for addresses, enable flags and data in, and an output for data out. It sometimes gets turned into registers if one a tiny amount of memory is accessed. It also must only have one write to memory.
There is quite a bit of code that I wrote a few months ago that I need to rewrite. I have been doing this since February when I got my myStorm board.
Hmm… that’s all interesting… I’m sure that I was breaking all of the rules, and I imagine yosys would have had a hell of a time unpicking what I was trying to do.
I’ve just added a commit which uses the SB_RAM block explicitly, and it seems to work okay for me locally… compile times have come way down, and from what I can see it now uses about 4,000 fewer cells, and 4,000 fewer wire-bits… It’s actually very impressive how much stuff you can fit in one of these devices - especially when you don’t abuse the hell out of it
That version builds much much faster.
In my tests I use the schemes suggested in appendix A of this document:
I did not have to instantiate the SB_RAM blocks,
yosys infers under this scheme that BRAM must be used.
Nice one! I forgot to mention I had that working… it took a little more reading the obscure parts of the MIDI spec than I expected, but the simpleuart code worked an absolute treat!
I am looking at extending your midi example to include the ability to vary the instrument in some way. Do you have ideas on how best to do this?
I was thinking of adding some rotary switches to vary some of the parameters of the voices, such as the waveform, decay, attack and sustain, a bit like a Moog synthesizer. But I saw that you had changed the voice module to one with fixed parameters for the midi example. Am I going to run out of resources if I add variable inputs to the voices?
Another possibility is to implement the patch midi commands and send them from a microprocessor, probably using a second uart. If I did that I might do it on my myStorm board as that has an arm processor and Arduino headers, so I could use the Gameduino 3 as the user interface. But I think I would prefer to try something simpler that I can use to play about with the instrument sound first. (I have the synthesizer running on myStorm).
Before @lukevalenty distracted me with his tile-based graphics ideas (heh, no hard feelings :)), I was thinking about maybe implementing some of the other MIDI commands to control the way things sound. Patch commands are one option, but as another example, my keyboard has a bunch of additional controls (pitch bender control, sliders, …) that can be configured to send MIDI messages, and I thought that it might be a bit more convenient to use those for parameter setting rather than needing to use a PC. I’d started to implement a state-variable filter (HP, LP, BP, NP) with variable cut-off - I thought that might be an easy first thing to try connecting up to a control.
I’m not sure about resources - I think it’s getting a little close at the moment - but that said, I think it’s using 8 voices, and that could be trimmed back to a smaller number if space gets tight.
Also, thanks for the links that you sent through on the github project :).
I’m interested in the PMOD idea that you suggested too - I think I might also build a PMOD module for the MIDI input. My current bread-board setup is a little bit … fragile… especially when put up against adversaries like my cat
Some boards such as the myStorm and icoBoard have multiple Pmod connections. The standard was developed by Digilent who make lots of different Pmods, and whose (non-icestorm) boards use them.
Single row Pmods can be plugged into a breadboard and used with the TinyFPGA. There are a few that I plan to try such as the Digilent microphone board. Double row Pmods or double-connector double-row Pmods (like the Digilent VGA Pmod) would need a PCB that you could plug the TinyFPGA into, and which would provide double-row Pmod connectors. I might make one of those. The Digilent VGA Pmod has 4-bits for each color.
I did not have a Midi keyboard, so I bought Rock Band 3 one, as they seem to be by far the cheapest ones that yoiu can get with a Midi out Din connector.
They do seem to have some limited ability to send other midi messages - see http://www.fakebitpolytechnic.com/wp-content/uploads/2013/07/rb3keyboardmidimanualv2.pdf.
I’ve actually just ordered a bunch of stuff from digilent - the VGA PMOD included… I guess the FPGA bug has really taken hold :-).
I tried a version with with the waveform (triangle, sawtooth, pulse, noise) set by switches. It just about had enough PLBs. I ran it on my BlackIce board as that has some built-in switches, but it should work on the TinyFPGA with switches or using breadboard wires a bit like mini patch cables to set pins 16-19 to GND or 3.3v.
It does vary the instrument in interesting ways, but noise is a bit overwhelming, and pulse combined with anything else makes the volume very low.
I now have a midi3 example, which is midi2 plus a rotary encoder for setting the pulse width. I can get a few more different sounds out of it:
Again I tested it on BlackIce with a homemade rotary encoder Pmod, but it should work on the TinyFPGA with the rotary encoder module connected by breadboard wire.
I have ordered some more rotary encoders, so I might make a panel with some switches and rotary encoders on it, in the style of a MiniMoog.
An audio synth board with a TinyFPGA BX socket would be very cool.
I have now added a midi4 example which has a second rotary dial for sustain. I had to cut the voices down to 6 to fit this in. I pulled your latest changes and incorporated them into midi3 and midi4.
What rotary controls are you using lawrie? I’d love to get some and have a play too.
I started mapping out the rotary controls on my MIDI keyboard today too - it turns out they’re mapped as B0 0E -> B0 15 messages, so I can now start building something to use them too… Today was a bit of a write-off with other things going on (hot-rodding the coffee machine amongst other things), but I’m hoping to get back into it tomorrow.