280 lines
6.5 KiB
Verilog
280 lines
6.5 KiB
Verilog
module ukp(
|
|
clk25,
|
|
clkusb,
|
|
rst,
|
|
usb_en,
|
|
usb_dm_in,
|
|
usb_dm_out,
|
|
usb_dp_in,
|
|
usb_dp_out,
|
|
record_n,
|
|
kbd_adr,
|
|
kbd_data
|
|
);
|
|
input clk25;
|
|
input clkusb;
|
|
input rst;
|
|
input usb_dm_in;
|
|
input usb_dp_in;
|
|
input [3:0] kbd_adr;
|
|
output usb_en;
|
|
output usb_dm_out;
|
|
output usb_dp_out;
|
|
output record_n;
|
|
output [7:0] kbd_data;
|
|
|
|
parameter S_OPCODE = 0;
|
|
parameter S_LDI0 = 1;
|
|
parameter S_LDI1 = 2;
|
|
parameter S_B0 = 3;
|
|
parameter S_B1 = 4;
|
|
|
|
parameter I_LDI = 4'b0001;
|
|
parameter I_START = 4'b0010;
|
|
|
|
parameter I_OUT0 = 4'b0100;
|
|
parameter I_OUT1 = 4'b0101;
|
|
parameter I_OUT2 = 4'b0110;
|
|
parameter I_HZ = 4'b0111;
|
|
|
|
parameter I_BZ = 4'b1000;
|
|
parameter I_BC = 4'b1001;
|
|
parameter I_BNAK = 4'b1010;
|
|
parameter I_DJNZ = 4'b1011;
|
|
|
|
parameter I_TOGGLE = 4'b1100;
|
|
parameter I_IN = 4'b1101;
|
|
parameter I_WAIT = 4'b1110;
|
|
|
|
function sel4;
|
|
input [1:0] sel;
|
|
input [3:0] a;
|
|
case (sel)
|
|
2'b00: sel4 = a[3];
|
|
2'b01: sel4 = a[2];
|
|
2'b10: sel4 = a[1];
|
|
2'b11: sel4 = a[0];
|
|
endcase
|
|
endfunction
|
|
|
|
function [3:0] decode4;
|
|
input [1:0] sel;
|
|
input g;
|
|
if (g)
|
|
case (sel)
|
|
2'b00: decode4 = 4'b0001;
|
|
2'b01: decode4 = 4'b0010;
|
|
2'b10: decode4 = 4'b0100;
|
|
2'b11: decode4 = 4'b1000;
|
|
endcase
|
|
else decode4 = 4'b0000;
|
|
endfunction
|
|
|
|
wire [3:0] inst;
|
|
wire sample;
|
|
reg connected;
|
|
reg inst_ready;
|
|
reg g;
|
|
reg p;
|
|
reg m;
|
|
reg cond;
|
|
reg nak;
|
|
reg dm1;
|
|
reg bank;
|
|
reg record1;
|
|
reg [2:0] state;
|
|
reg [7:0] w;
|
|
reg [9:0] pc;
|
|
reg [2:0] timing;
|
|
reg [3:0] tmp;
|
|
reg [13:0] interval;
|
|
reg [5:0] bitadr;
|
|
reg [7:0] data;
|
|
|
|
ukprom ukprom(
|
|
.clk(clkusb),
|
|
.adr(pc),
|
|
.data(inst)
|
|
);
|
|
|
|
wire interval_cy = interval == 12001;
|
|
wire next = ~(state == S_OPCODE & (
|
|
~inst[3] & inst[2] & timing != 0 |
|
|
~inst[3] & ~inst[2] & inst[1] & usb_dm_in |
|
|
inst == 4'b1110 & ~interval_cy |
|
|
inst == 4'b1101 & (~sample | (usb_dp_in | usb_dm_in) & w != 1)
|
|
));
|
|
wire branch = state == S_B1 & cond;
|
|
wire record;
|
|
wire [7:0] map;
|
|
wire [3:0] keydata;
|
|
|
|
always @(posedge clkusb or posedge rst)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
connected <= 0;
|
|
inst_ready <= 0;
|
|
g <= 0;
|
|
p <= 0;
|
|
m <= 0;
|
|
cond <= 0;
|
|
nak <= 0;
|
|
dm1 <= 0;
|
|
bank <= 0;
|
|
record1 <= 0;
|
|
state <= 3'd0;
|
|
w <= 8'd0;
|
|
pc <= 10'd0;
|
|
timing <= 3'd0;
|
|
tmp <= 4'd0;
|
|
interval <= 14'd0;
|
|
bitadr <= 6'd0;
|
|
data <= 8'd0;
|
|
end
|
|
else
|
|
begin
|
|
if (inst_ready)
|
|
begin
|
|
if (state == S_OPCODE)
|
|
begin
|
|
// set LDI
|
|
if (inst == I_LDI) state <= S_LDI0;
|
|
|
|
// set connected
|
|
if (inst == I_TOGGLE) connected <= ~connected;
|
|
|
|
// handle USB outputs when timing is 0
|
|
if (~inst[3] & inst[2] & timing == 0)
|
|
begin
|
|
g <= ~inst[1] | ~inst[0];
|
|
p <= ~inst[1] & inst[0];
|
|
m <= inst[1] & ~inst[0];
|
|
end
|
|
|
|
// handle branching
|
|
if (inst[3] & ~inst[2])
|
|
begin
|
|
state <= S_B0;
|
|
cond <= sel4(inst[1:0], {~usb_dm_in, connected, nak, w != 1});
|
|
end
|
|
|
|
if (inst == 4'b1011 | inst == 4'b1101 & sample) w <= w - 1;
|
|
end
|
|
|
|
if (state == S_LDI0)
|
|
begin
|
|
w[3:0] <= inst;
|
|
state <= S_LDI1;
|
|
end
|
|
|
|
if (state == S_LDI1)
|
|
begin
|
|
w[7:4] <= inst;
|
|
state <= S_OPCODE;
|
|
end
|
|
|
|
if (state == S_B0)
|
|
begin
|
|
tmp <= inst;
|
|
state <= S_B1;
|
|
end
|
|
|
|
if (state == S_B1)
|
|
begin
|
|
state <= S_OPCODE;
|
|
end
|
|
|
|
if (next | branch)
|
|
begin
|
|
pc <= branch ? { inst, tmp, 2'b00 } : pc + 1;
|
|
inst_ready <= 0;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
inst_ready <= 1;
|
|
end
|
|
|
|
if (inst_ready & state == S_OPCODE & inst == 4'b0010)
|
|
begin
|
|
timing <= 0;
|
|
bitadr <= 0;
|
|
nak <= 1;
|
|
end
|
|
else
|
|
begin
|
|
timing <= timing + 1;
|
|
end
|
|
|
|
if (sample)
|
|
begin
|
|
if (bitadr == 8) nak <= usb_dm_in;
|
|
data[6:0] <= data[7:1];
|
|
data[7] <= dm1 ~^ usb_dm_in;
|
|
dm1 <= usb_dm_in;
|
|
bitadr <= bitadr + 1;
|
|
end
|
|
|
|
interval <= interval_cy ? 0 : interval + 1;
|
|
record1 <= record;
|
|
|
|
if (~record & record1)
|
|
begin
|
|
bank <= ~bank;
|
|
end
|
|
end
|
|
end
|
|
|
|
assign usb_dp = g ? p : 1'bZ;
|
|
assign usb_dm = g ? m : 1'bZ;
|
|
assign sample = inst_ready & state == S_OPCODE & inst == 4'b1101 & timing == 1;
|
|
assign record = connected & ~nak;
|
|
assign record_n = ~record;
|
|
|
|
keymap keymap(
|
|
.clk(clkusb),
|
|
.adr({ ~timing[0], data[6:0] }),
|
|
.data(map)
|
|
);
|
|
|
|
wire mod = bitadr == 24;
|
|
assign keydata = mod ? { data[0] | data[4], data[1] | data[5], data[2] | data[6], data[3] | data[7] } : decode4(map[1:0], record1);
|
|
|
|
wire [4:0] kbd_adr_in = record1 ? mod ? 5'b10001 : map[6:2] : interval[4:0];
|
|
|
|
ukpram my_ukpram(
|
|
.clk25(clk25),
|
|
.read_addr({~bank, kbd_adr}),
|
|
.r_en(1'b1),
|
|
.dout(kbd_data),
|
|
|
|
.clkusb(clkusb),
|
|
.write_addr({bank, kbd_adr_in}),
|
|
.w_en(
|
|
(~record1 | (mod | bitadr == 40 | bitadr == 48) & (timing == 0 | timing == 1)) &&
|
|
(~record1 | mod | map[7])
|
|
),
|
|
.din(keydata)
|
|
);
|
|
|
|
//RAMB4_S4_S8 keyboard(
|
|
//.WEA(~record1 | (mod | bitadr == 40 | bitadr == 48) & (timing == 0 | timing == 1)),
|
|
//.ENA(~record1 | mod | map[7]),
|
|
|
|
//.RSTA(1'b0),
|
|
//.CLKA(clk12),
|
|
//.ADDRA({ 4'b0000, bank, kbd_adr_in }),
|
|
//.DIA(keydata),
|
|
|
|
//.WEB(1'b0),
|
|
//.ENB(1'b1),
|
|
|
|
//.RSTB(1'b0),
|
|
//.CLKB(clk12),
|
|
//.ADDRB({ 4'b0000, ~bank, kbd_adr}),
|
|
//.DIB(8'h00),
|
|
//.DOB(kbd_data)
|
|
//);
|
|
endmodule
|