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:
@@ -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
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user