Commit 0e92c044 authored by Christian Fibich's avatar Christian Fibich
Browse files

icoBoard + PI script

parent 6515cea0
module spi2bus_top(input clock, input reset, input ss, input mosi, input sck,
output [7:0] mon_data,
output mon_ena,
output [15:0] int_address, // address bus to register file
output [7:0] int_wr_data, // write data to register file
output int_write); // write control to register file
wire [7:0] rx_data; // data byte received
wire new_rx_data; // signs that a new byte was received
spi_rx spi_rx1 (.clock(clock), .reset(reset), .mosi(mosi), .sck(sck), .ss(ss), .rxdata(rx_data), .rxen(new_rx_data));
assign mon_ena = new_rx_data;
assign mon_data = rx_data;
// uart parser instance
uart_parser #(16) uart_parser1
(
.clock(clock), .reset(reset),
.rx_data(rx_data), .new_rx_data(new_rx_data),
.tx_data(), .new_tx_data(), .tx_busy(0),
.int_address(int_address), .int_wr_data(int_wr_data), .int_write(int_write),
.int_rd_data(0), .int_read(),
.int_req(), .int_gnt(1)
);
endmodule
module spi_rx (input clock, input reset, input mosi, input sck, input ss, output [7:0] rxdata, output reg rxen);
reg [2:0] sck_syncd;
reg [2:0] ss_syncd;
reg [2:0] data_cnt;
reg [7:0] data;
assign rxdata = data;
always @(posedge clock or posedge reset)
begin
if (reset) begin
sck_syncd <= 3'b0;
ss_syncd <= 3'b111;
end else begin
sck_syncd <= {sck_syncd[1:0], sck};
ss_syncd <= {ss_syncd[1:0], ss};
end
end
always @(posedge clock or posedge reset)
begin
if (reset) begin
rxen <= 1'b0;
data <= 8'b0;
data_cnt <= 3'b0;
end else begin
rxen <= 1'b0;
if (ss_syncd[2:1] == 2'b1) begin
data <= 8'b0;
data_cnt <= 4'b0;
end else begin
if (sck_syncd[2:1] == 2'b01) begin
data <= {data[6:0],mosi};
data_cnt <= data_cnt + 1;
if (data_cnt == 3'b111) begin
rxen <= 1'b1;
end
end
end
end
end
endmodule
.PHONY : all clean prog
LOGIN=pi@10.42.0.176
ROOT_DIR=../../
all : prog
audio.blif: *.v $(ROOT_DIR)/hdl/uart2bus/*.v $(ROOT_DIR)/hdl/usynth/*.v
yosys -v4 -l synth.log -p 'synth_ice40 -top hx8k_audio_top -blif $@' $^
audio.asc: audio.blif audio.pcf
arachne-pnr -d 8k -o audio.asc -p audio.pcf audio.blif -P ct256
audio.bin: audio.asc
icepack audio.asc audio.bin
prog : audio.bin
scp ../../tools/midi-pi.py $(LOGIN):/tmp
scp ../../midi-best/beet27m1.mid $(LOGIN):/tmp
scp audio.bin $(LOGIN):/tmp && ssh $(LOGIN) 'icoprog -p < /tmp/audio.bin'
clean :
rm audio.blif audio.asc
module hx8k_audio_top #(parameter NUM_VOICES = 3, parameter WAVEFORM = 0) ( input clock_in_100,
input sck,
input mosi,
input ss,
output gain, // 1: 6dB, 0: 12dB
output shutdown, // 1: on, 0: off
output [7:0] led,
output pwm);
reg [NUM_VOICES*16-1:0] freq;
reg [NUM_VOICES*16-1:0] a;
reg [NUM_VOICES*16-1:0] d;
reg [NUM_VOICES*16-1:0] s;
reg [NUM_VOICES*16-1:0] r;
assign shutdown = 1'b1;
assign gain = 1'b1;
wire locked;
wire reset;
reg [2:0] reset_sync;
wire clock;
reg [7:0] led_reg;
wire mon_ena;
wire [7:0] mon_led;
reg [7:0] i;
reg [NUM_VOICES-1:0] play_note;
reg [NUM_VOICES-1:0] envelope;
reg [NUM_VOICES-1:0] enable;
reg [NUM_VOICES*8-1:0] freq_l;
reg [NUM_VOICES*8-1:0] a_l;
reg [NUM_VOICES*8-1:0] d_l;
reg [NUM_VOICES*8-1:0] s_l;
reg [NUM_VOICES*8-1:0] r_l;
pll clkgen (.clock_in(clock_in_100),.clock_out(clock),.locked(locked));
initial
reset_sync <= 3'b1;
always @(posedge clock or negedge locked) begin
if (!locked) begin
reset_sync <= 3'b1;
end else begin
reset_sync <= {reset_sync[1:0],1'b0};
end
end
assign reset = reset_sync[2];
usynth #(.NUM_VOICES(NUM_VOICES), .WAVEFORM(WAVEFORM)) syn
(.clock(clock), .ce25(1), .reset(reset),
.play_note(play_note[NUM_VOICES-1:0]),
.enable(enable[NUM_VOICES-1:0]),
.freq(freq[NUM_VOICES*16-1:0]),
.pwm(pwm),
.a(a[NUM_VOICES*16-1:0]),
.d(d[NUM_VOICES*16-1:0]),
.s(s[NUM_VOICES*16-1:0]),
.r(r[NUM_VOICES*16-1:0]),
.envelope(envelope[NUM_VOICES-1:0]));
wire [15:0] address;
wire [7:0] data;
wire wr;
spi2bus_top i_spi (.clock(clock),.reset(reset),
.mosi(mosi),.ss(ss),.sck(sck),
.int_address(address),
.int_wr_data(data),
.int_write(wr),
.mon_data(mon_led),
.mon_ena(mon_ena));
assign led = led_reg;
//assign led = {5'b0, sck, mosi, ss};
//assign led = led_reg;
always @(posedge(clock) or posedge(reset))
begin
if (reset) begin
led_reg <= 8'hff;
for (i=0;i<NUM_VOICES;i=i+1) begin
freq_l[i*8+:8] <= 0;
a_l[i*8+:8] <= 0;
d_l[i*8+:8] <= 0;
s_l[i*8+:8] <= 0;
r_l[i*8+:8] <= 0;
freq [i*16+:16] <= 440;
a[i*16+:16] <= 16'h400;
d[i*16+:16] <= 16'h400;
s[i*16+:16] <= 16'h8000;
r[i*16+:16] <= 16'h0100;
enable <= 0;
play_note <= 0;
envelope <= 0;
end
end else begin
if (mon_ena)
led_reg <= mon_led;
if (wr)
if (address > 16'hFF) begin
enable[address[3:0]] <= data[0];
play_note[address[3:0]] <= data[1];
envelope[address[3:0]] <= data[2];
end else begin
case (address[3:0])
4'h0: freq_l[address[7:4]*8 +:8] <= data;
4'h1: freq [address[7:4]*16+:16] <= {data, freq_l[address[7:4]*8+:8]};
4'h2: a_l [address[7:4]*8 +:8] <= data;
4'h3: a [address[7:4]*16+:16] <= {data, a_l[address[7:4]*8 +:8]};
4'h4: d_l [address[7:4]*8 +:8] <= data;
4'h5: d [address[7:4]*16+:16] <= {data, d_l[address[7:4]*8 +:8]};
4'h6: s_l [address[7:4]*8 +:8] <= data;
4'h7: s [address[7:4]*16+:16] <= {data, s_l[address[7:4]*8 +:8]};
4'h8: r_l [address[7:4]*8 +:8] <= data;
4'h9: r [address[7:4]*16+:16] <= {data, r_l[address[7:4]*8 +:8]};
default : play_note <= play_note;
endcase
end
end
end
endmodule
/**
* PLL configuration
*
* This Verilog module was generated automatically
* using the icepll tool from the IceStorm project.
* Use at your own risk.
*
* Given input frequency: 100.000 MHz
* Requested output frequency: 24.000 MHz
* Achieved output frequency: 23.958 MHz
*/
module pll(
input clock_in,
output clock_out,
output locked
);
SB_PLL40_CORE #(
.FEEDBACK_PATH("SIMPLE"),
.DIVR(4'b0010), // DIVR = 2
.DIVF(7'b0010110), // DIVF = 22
.DIVQ(3'b101), // DIVQ = 5
.FILTER_RANGE(3'b011) // FILTER_RANGE = 3
) uut (
.LOCK(locked),
.RESETB(1'b1),
.BYPASS(1'b0),
.REFERENCECLK(clock_in),
.PLLOUTCORE(clock_out),
);
endmodule
#!/usr/bin/env python2
import mido
import serial
import sys
import time
import signal
import spidev
def get_first_voice(voices,note=None):
for i in range(0,len(voices)):
if voices[i] == note:
return i
return None
def set_freq(port,voice,freq):
write(port,0x10*(voice),[freq%256,freq/256])
def set_adsr(port,voice,a,d,s,r):
write(port,0x10*(voice)+2,[a%256,a/256,d%256,d/256,s%256,s/256,r%256,r/256])
def note_on(port,voice):
write(port,0x100+voice,[7])
def note_off(port,voice):
write(port,0x100+voice,[5])
def freq(note):
return (2.0**((note - 69)/12.0))*440.0;
def sigint_handler(num,frame):
for v in range(0,8):
note_off(port,v)
port.close()
sys.exit(0)
def write(port,address,bytes):
cmd = [0, # Binary Mode
0x21] # Write Command + ACK
if address > 65535:
raise ValueError("Out of address space")
if len(bytes) > 256:
raise ValueError("Too many bytes")
data = list(cmd);
data.append(address / 256)
data.append(address % 256)
size = min(256,len(bytes))
data.append(size % 256)
payload = bytes
data.extend(payload)
port.xfer(data,32000,1000,8)
time.sleep(0.01)
return True
if __name__=="__main__":
if len(sys.argv) != 2:
print "Usage: %s <MIDI FILE>" % sys.argv[0]
sys.exit(-1)
try:
port = spidev.SpiDev()
port.open(0,1)
except Exception as e:
port.close()
sys.stderr.write("Port cannot be opened: %s\n", str(e))
sys.exit(-1)
signal.signal(signal.SIGINT,sigint_handler)
voices = [None]*8
#write(port,0x100,[5]*8) # Voices on + envelope
for v in range(0,8):
note_off(port,v)
set_freq(port,v,440)
set_adsr(port,v,0x400,0x400,0x4000,0x100)
mid = mido.MidiFile(sys.argv[1])
for msg in mid.play():
if msg.type == "note_on":
if (msg.velocity > 0):
idx = get_first_voice(voices,None)
if idx is None:
print "WARN: no free voices"
else:
voices[idx] = msg.note
set_freq(port,idx,int(freq(msg.note)))
note_on(port,idx)
print "%d on (%d hz)" % (idx, int(freq(msg.note)))
else:
idx = get_first_voice(voices,msg.note)
if idx is None:
print "WARN: no note assigned"
else:
voices[idx] = None
print "%d off" % idx
note_off(port,idx)
#time.sleep(msg.time)
elif msg.type == "note_off":
idx = get_first_voice(voices,msg.note)
if idx is None:
print "WARN: no note assigned"
else:
voices[idx] = None
print "%d off" % idx
note_off(port,idx)
#time.sleep(msg.time)
port.close()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment