verilog-apple-one/rtl/ukp/ukp.v

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