1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-01-27 12:21:44 +00:00

Initial MIDI support

This commit is contained in:
harbaum
2013-05-24 07:35:46 +00:00
parent da055eb07e
commit a8ef631b54
3 changed files with 136 additions and 44 deletions

View File

@@ -37,7 +37,13 @@ reg [FIFO_ADDR_BITS-1:0] writePout, readPout;
reg [13:0] readTimer;
reg ikbd_strobe_inD, ikbd_strobe_inD2;
reg data_read;
reg ikbd_cpu_data_read;
reg midi_cpu_data_read;
// the two control registers
reg [7:0] ikbd_cr;
reg [7:0] midi_cr;
always @(negedge clk) begin
if(reset)
readTimer <= 14'd0;
@@ -50,9 +56,15 @@ always @(negedge clk) begin
// read on ikbd data register
if(sel && ~ds && rw && (addr == 2'd1))
data_read <= 1'b1;
ikbd_cpu_data_read <= 1'b1;
else
data_read <= 1'b0;
ikbd_cpu_data_read <= 1'b0;
// read on midi data register
if(sel && ~ds && rw && (addr == 2'd3))
midi_cpu_data_read <= 1'b1;
else
midi_cpu_data_read <= 1'b0;
if(reset) begin
// reset read and write counters
@@ -65,7 +77,7 @@ always @(negedge clk) begin
writePin <= writePin + 4'd1;
end
if(data_read && dataInAvail) begin
if(ikbd_cpu_data_read && ikbd_rx_data_available) begin
readPin <= readPin + 4'd1;
// Some programs (e.g. bolo) need a pause between two ikbd bytes.
@@ -79,13 +91,14 @@ end
// ------------------ cpu interface --------------------
wire [7:0] rxd;
assign rxd = fifoIn[readPin];
wire ikbd_irq = ikbd_cr[7] && ikbd_rx_data_available;
wire dataInAvail;
assign dataInAvail = (readPin != writePin) && (readTimer == 0);
wire [7:0] ikbd_rx_data = fifoIn[readPin];
assign irq = dataInAvail;
wire ikbd_rx_data_available;
assign ikbd_rx_data_available = (readPin != writePin) && (readTimer == 0);
assign irq = ikbd_irq || midi_irq;
assign ikbd_data_out_available = (readPout != writePout);
assign ikbd_data_out = fifoOut[readPout];
@@ -103,35 +116,84 @@ always @(posedge clk) begin
readPout <= readPout + 4'd1;
end
always @(sel, ds, rw, addr, dataInAvail, rxd, midi_tx_empty) begin
always @(sel, ds, rw, addr, ikbd_rx_data_available, ikbd_rx_data, midi_rx_data_available, midi_tx_empty) begin
dout = 8'h00;
if(sel && ~ds && rw) begin
// keyboard acia read
if(addr == 2'd0) dout = 8'h02 | (dataInAvail?8'h81:8'h00); // status
if(addr == 2'd1) dout = rxd; // data
if(addr == 2'd0) dout = { ikbd_irq, 6'b000001, ikbd_rx_data_available };
if(addr == 2'd1) dout = ikbd_rx_data;
// midi acia read
if(addr == 2'd2) dout = { 6'b000000, midi_tx_empty, 1'b0} ; // status
if(addr == 2'd3) dout = 8'h00; // data
if(addr == 2'd2) dout = { midi_irq, 5'b00000, midi_tx_empty, midi_rx_data_available};
if(addr == 2'd3) dout = midi_rx_data;
end
end
// midi transmitter
assign midi_out = midi_tx_empty ? 1'b1: midi_tx_cnt[0];
wire midi_tx_empty = (midi_tx_cnt == 4'd0);
reg [7:0] midi_clk;
reg [3:0] midi_tx_cnt;
reg [9:0] midi_tx_data;
// ------------------------------ MIDI UART ---------------------------------
wire midi_irq = midi_cr[7] && midi_rx_data_available;
// MIDI runs at 31250bit/s which is exactly 1/256 of the 8Mhz system clock
// 8MHz/256 = 31250Hz -> MIDI bit rate
reg [7:0] midi_clk;
always @(posedge clk)
midi_clk <= midi_clk + 8'd1;
// --------------------------- midi receiver -----------------------------
reg [7:0] midi_rx_cnt; // bit + sub-bit cointer
reg [9:0] midi_rx_shift_reg; // shift register used during reception
reg [7:0] midi_rx_data;
reg midi_rx_data_available;
always @(negedge clk) begin
if(reset) begin
midi_rx_cnt <= 8'd0;
midi_rx_data_available <= 1'b0;
end else begin
if(midi_cpu_data_read)
midi_rx_data_available <= 1'b0; // read on midi data clears rx status
// 1/16 system clock == 16 times midi clock
if(midi_clk[3:0] == 4'd0) begin
// receiver not running
if(midi_rx_cnt == 0) begin
if(midi_in == 0) begin
// expecing 10 bits starting half a bit time from now
midi_rx_cnt <= { 4'd10, 4'd7 };
end
end else begin
// receiver is running
midi_rx_cnt <= midi_rx_cnt - 8'd1;
if(midi_rx_cnt[3:0] == 4'd0) begin
// in the middle of the bit -> shift new bit into msb
midi_rx_shift_reg <= { midi_in, midi_rx_shift_reg[9:1] };
end
// last bit received
if(midi_rx_cnt[7:0] == 8'd1) begin
// copy data into rx register
midi_rx_data <= midi_rx_shift_reg[8:1]; // pure data w/o start and stop bits
midi_rx_data_available <= 1'b1;
// todo: check data[0] for frame error (stop bit)
end
end
end
end
end
// --------------------------- midi transmitter -----------------------------
assign midi_out = midi_tx_empty ? 1'b1: midi_tx_data[0];
wire midi_tx_empty = (midi_tx_cnt == 4'd0);
reg [3:0] midi_tx_cnt;
reg [10:0] midi_tx_data;
always @(negedge clk) begin
if(midi_clk == 8'd0) begin
// shift down one bit, fill with 1 bits
midi_tx_data <= { 1'b1, midi_tx_data[9:1] };
midi_tx_data <= { 1'b1, midi_tx_data[10:1] };
// decreae transmit counter
if(midi_tx_cnt != 4'd0)
@@ -141,17 +203,33 @@ always @(negedge clk) begin
if(reset) begin
writePout <= 4'd0;
midi_tx_cnt <= 4'd0;
ikbd_cr <= 8'h00;
midi_cr <= 8'h00;
end else begin
// keyboard acia data register writes into buffer
if(sel && ~ds && ~rw && addr == 2'd1) begin
fifoOut[writePout] <= din;
writePout <= writePout + 4'd1;
end
if(sel && ~ds && ~rw) begin
// write to midi data register
if(sel && ~ds && ~rw && addr == 2'd1) begin
midi_tx_data <= { 1'b1, din, 1'b0 }; // 8N1, lsb first
midi_tx_cnt <= 4'd10; // 10 bits to go
// write to ikbd control register
if(addr == 2'd0)
ikbd_cr <= din;
// keyboard acia data register writes into buffer
if(addr == 2'd1) begin
fifoOut[writePout] <= din;
writePout <= writePout + 4'd1;
end
// write to midi control register
if(addr == 2'd2)
midi_cr <= din;
// write to midi data register
// we load the tx register with a 1 bit (idle state) in the lsb to make sure
// the tx line stays ad idle level until the transmission starts
if(addr == 2'd3) begin
midi_tx_data <= { 1'b1, din, 1'b0, 1'b1 }; // 8N1, lsb first
midi_tx_cnt <= 4'd11; // 10 bits to go
end
end
end
end

View File

@@ -1,6 +1,6 @@
<sld_project_info>
<project>
<hash md5_digest_80b="779a60292bd914e12e70"/>
<hash md5_digest_80b="729397cb6441cd319243"/>
</project>
<file_info/>
<hub_info ir_width="8" node_count="1"/>

View File

@@ -71,12 +71,14 @@ assign hsO = mono?hs:hsC;
// line buffer for scan doubler for color video modes
// the color modes have 80 words per line (320*4/16 or 640*2/16) and
// we need space for two lines -> 160 words
reg [15:0] sd_buffer [255:0];
reg [15:0] sd_buffer0 [63:0];
reg [15:0] sd_buffer1 [63:0];
reg [15:0] sd_buffer2 [63:0];
reg [15:0] sd_buffer3 [63:0];
reg [6:0] sd_wptr, sd_rptr;
reg [15:0] dataR;
// instance of video timing module for monochrome (72hz)
wire [9:0] vcnt_mono, hcnt_mono;
wire hs_mono, vs_mono, hmax_mono, vmax_mono;
@@ -169,7 +171,7 @@ always @(posedge clk) begin
hs <= mono?~hs_mono:hs_color;
vs <= mono?~vs_mono:vs_color;
end
reg [15:0] tx, tx0, tx1, tx2, tx3; // output shift registers
localparam BASE_ADDR = 23'h8000; // default video base address 0x010000
@@ -318,11 +320,14 @@ wire hsC = vcnt[0] && hs;
// create a read signal that's 16 clocks ahead of oe
assign read = (bus_cycle[3:2] == 0) && (hcnt < H_ACT) && (vcnt < V_ACT);
reg line;
always @(posedge clk) begin
if(reset) begin
vaddr <= _v_bas_ad;
end else begin
line <= vcnt[1];
// ---- scan doubler pointer handling -----
if(hmax) begin
// reset counters at and of each line
@@ -335,13 +340,17 @@ always @(posedge clk) begin
// ------------ memory fetch --------------
if(read) begin
if(bus_cycle == 3) begin
// 16bit buffer for direct mono generation
dataR <= data;
// two line buffer for scan doubling
sd_buffer[{!vcnt[1], sd_wptr}] <= data;
case(sd_wptr[1:0])
2'b00: sd_buffer0[{!line, sd_wptr[6:2]}] <= data;
2'b01: sd_buffer1[{!line, sd_wptr[6:2]}] <= data;
2'b10: sd_buffer2[{!line, sd_wptr[6:2]}] <= data;
2'b11: sd_buffer3[{!line, sd_wptr[6:2]}] <= data;
endcase
// increase scan doubler address
sd_wptr <= sd_wptr + 7'd1;
@@ -369,10 +378,10 @@ always @(posedge clk) begin
if(low) begin
if((hcnt < H_ACT) && (hcnt[4:0] == 5'b01110)) begin
// read words for all four planes
tx0 <= sd_buffer[{vcnt[1], sd_rptr+7'd0}];
tx1 <= sd_buffer[{vcnt[1], sd_rptr+7'd1}];
tx2 <= sd_buffer[{vcnt[1], sd_rptr+7'd2}];
tx3 <= sd_buffer[{vcnt[1], sd_rptr+7'd3}];
tx0 <= sd_buffer0[{line, sd_rptr[6:2]}];
tx1 <= sd_buffer1[{line, sd_rptr[6:2]}];
tx2 <= sd_buffer2[{line, sd_rptr[6:2]}];
tx3 <= sd_buffer3[{line, sd_rptr[6:2]}];
sd_rptr <= sd_rptr + 7'd4;
end else if(hcnt[0] == 1'b0) begin
// shift every second pixel
@@ -385,8 +394,13 @@ always @(posedge clk) begin
// med rez 640x200
if((hcnt < H_ACT) && (hcnt[3:0] == 4'b1111)) begin
// read words for all four planes
tx0 <= sd_buffer[{vcnt[1], sd_rptr+7'd0}];
tx1 <= sd_buffer[{vcnt[1], sd_rptr+7'd1}];
if(sd_rptr[1] == 1'b0) begin
tx0 <= sd_buffer0[{line, sd_rptr[6:2]}];
tx1 <= sd_buffer1[{line, sd_rptr[6:2]}];
end else begin
tx0 <= sd_buffer2[{line, sd_rptr[6:2]}];
tx1 <= sd_buffer3[{line, sd_rptr[6:2]}];
end
sd_rptr <= sd_rptr + 7'd2;
end else begin
// shift every pixel