diff --git a/src/nes2hdmi.sv b/src/nes2hdmi.sv index 53f2094..c227de2 100644 --- a/src/nes2hdmi.sv +++ b/src/nes2hdmi.sv @@ -55,7 +55,11 @@ module nes2hdmi ( wire [15:0] mem_portB_addr; logic [5:0] mem_portB_rdata; - + + logic initializing = 1; + logic [7:0] init_y = 0; + logic [7:0] init_x = 0; + // BRAM port A read/write always_ff @(posedge clk) begin if (mem_portA_we) begin @@ -66,27 +70,59 @@ module nes2hdmi ( // BRAM port B read always_ff @(posedge clk_pixel) begin mem_portB_rdata <= mem[mem_portB_addr]; -// mem_portB_rdata <= mem_portB_addr[13:8]; end initial begin $readmemb("background.txt", mem); - // $readmemb("nes_fb_testpattern_palette.txt", mem); end + localparam [0:65] LOGO [0:12] = '{ + 'b11110000110011111111001111001111111110000000000000000000000000000, + 'b11110000110011111111011111101111111110000000000000000000000000000, + 'b11111000110011100000011100100001110000000000000000000000000000000, + 'b11111000110011100000011100000001110000011111000111111100001111110, + 'b11011100110011111110001110000001110000110011100111001110011100111, + 'b11001110110011111110000111000001110000000011100110001110011000111, + 'b11001111110011000000000011100001110000111111100110001110111000111, + 'b11000111110011000000110011100001110001111111100110001110111000111, + 'b11000011110011111110111111100001100001110011100110001110011001111, + 'b11000011110011111110011111000001100000111111100110001110001111111, + 'b00000000000000000000000000000000000000000000000000000000000000111, + 'b00000000000000000000000000000000000000000000000000000000011001110, + 'b00000000000000000000000000000000000000000000000000000000011111100 + }; + // - // Data input + // Data input and initial background loading // logic [8:0] r_scanline; logic [8:0] r_cycle; always @(posedge clk) begin - r_scanline <= scanline; - r_cycle <= cycle; - mem_portA_we <= 1'b0; - if ((r_scanline != scanline || r_cycle != cycle) && scanline < 9'd240 && ~cycle[8]) begin - mem_portA_addr <= {scanline[7:0], cycle[7:0]}; - mem_portA_wdata <= color; - mem_portA_we <= 1'b1; + if (~resetn) begin + initializing <= 1; + init_y <= 0; + init_x <= 0; + mem_portA_we <= 0; + end else if (initializing) begin // setup background at initialization + init_x <= init_x + 1; + init_y <= init_x == 255 ? init_y + 1 : init_y; + if (init_y == 240) + initializing <= 0; + mem_portA_we <= 1; + mem_portA_addr <= {init_y, init_x}; + if (init_x >= 96 && init_x <= 160 && init_y >= 212 && init_y <= 224 && LOGO[init_y - 212][init_x - 96]) + mem_portA_wdata <= 4; // blue logo + else + mem_portA_wdata <= 13; // black + end else begin + r_scanline <= scanline; + r_cycle <= cycle; + mem_portA_we <= 1'b0; + if ((r_scanline != scanline || r_cycle != cycle) && scanline < 9'd240 && ~cycle[8]) begin + mem_portA_addr <= {scanline[7:0], cycle[7:0]}; + mem_portA_wdata <= color; + mem_portA_we <= 1'b1; + end end end diff --git a/src/nes_tang20k.v b/src/nes_tang20k.v index fd9872b..4995752 100644 --- a/src/nes_tang20k.v +++ b/src/nes_tang20k.v @@ -7,10 +7,10 @@ module NES_Tang20k( input sys_clk, - // input sys_resetn, - // input d7, - // Button S1 + + // Button S1 and pin 48 are both resets input s1, + input reset2, // UART input UART_RXD, @@ -70,7 +70,7 @@ reg [7:0] reset_cnt = 255; // reset for 255 cycles before start everything always @(posedge clk) begin reset_cnt <= reset_cnt == 0 ? 0 : reset_cnt - 1; if (reset_cnt == 0) - sys_resetn <= ~s1; + sys_resetn <= ~s1 & ~reset2; end `ifndef VERILATOR diff --git a/src/nestang.cst b/src/nestang.cst index a324986..451d6e6 100644 --- a/src/nestang.cst +++ b/src/nestang.cst @@ -4,8 +4,11 @@ IO_PORT "sys_clk" IO_TYPE=LVCMOS33 PULL_MODE=NONE; // IO_LOC "sys_resetn" T2; // IO_PORT "sys_resetn" PULL_MODE=NONE; +// S1 and pin 48 are both resets IO_LOC "s1" 88; IO_PORT "s1" PULL_MODE=NONE; +IO_LOC "reset2" 48; +IO_PORT "reset2" PULL_MODE=DOWN; // HDMI IO_LOC "tmds_clk_p" 33; diff --git a/src/usb_hid_host.v b/src/usb_hid_host.v index fa9a160..b3fa425 100644 --- a/src/usb_hid_host.v +++ b/src/usb_hid_host.v @@ -67,102 +67,112 @@ assign dbg_hid_report = {dat[7], dat[6], dat[5], dat[4], dat[3], dat[2], dat[1], reg valid = 0; // whether current gamepad report is valid always @(posedge usbclk) begin : process_in_data - data_rdy_r <= data_rdy; data_strobe_r <= data_strobe; - report <= 0; // ensure pulse - if (report == 1) begin - // clear mouse movement for later - mouse_dx <= 0; mouse_dy <= 0; - end - if(~data_rdy) rcvct <= 0; - else begin - if(data_strobe && ~data_strobe_r) begin // rising edge of ukp data strobe - dat[rcvct] <= ukpdat; + if (~usbrst_n) begin + valid <= 0; + report <= 0; + {game_l, game_r, game_u, game_d, game_a, game_b, game_x, game_y, game_sel, game_sta} <= 0; + end else begin + data_rdy_r <= data_rdy; data_strobe_r <= data_strobe; + report <= 0; // ensure pulse + if (report == 1) begin + // clear mouse movement for later + mouse_dx <= 0; mouse_dy <= 0; + end + if(~data_rdy) rcvct <= 0; + else begin + if(data_strobe && ~data_strobe_r) begin // rising edge of ukp data strobe + dat[rcvct] <= ukpdat; - if (typ == 1) begin // keyboard - case (rcvct) - 0: key_modifiers <= ukpdat; - 2: key1 <= ukpdat; - 3: key2 <= ukpdat; - 4: key3 <= ukpdat; - 5: key4 <= ukpdat; - endcase - end else if (typ == 2) begin // mouse - case (rcvct) - 0: mouse_btn <= ukpdat; - 1: mouse_dx <= ukpdat; - 2: mouse_dy <= ukpdat; - endcase - end else if (typ == 3) begin // gamepad - // A typical report layout: - // - d[3] is X axis (0: left, 255: right) - // - d[4] is Y axis - // - d[5][7:4] is buttons YBAX - // - d[6][5:4] is buttons START,SELECT - // Variations: - // - Some gamepads uses d[0] and d[1] for X and Y axis. - // - Some transmits a different set when d[0][1:0] is 2 (a dualshock adapater) - case (rcvct) - 0: begin - if (ukpdat[1:0] != 2'b10) begin - // for DualShock2 adapter, 2'b10 marks an irrelevant record - valid <= 1; - game_l <= 0; game_r <= 0; game_u <= 0; game_d <= 0; - end else - valid <= 0; - if (ukpdat==8'h00) {game_l, game_r} <= 2'b10; - if (ukpdat==8'hff) {game_l, game_r} <= 2'b01; - end - 1: begin - if (ukpdat==8'h00) {game_u, game_d} <= 2'b10; - if (ukpdat==8'hff) {game_u, game_d} <= 2'b01; - end - 3: if (valid) begin - if (ukpdat[7:6]==2'b00) {game_l, game_r} <= 2'b10; - if (ukpdat[7:6]==2'b11) {game_l, game_r} <= 2'b01; - end - 4: if (valid) begin - if (ukpdat[7:6]==2'b00) {game_u, game_d} <= 2'b10; - if (ukpdat[7:6]==2'b11) {game_u, game_d} <= 2'b01; - end - 5: if (valid) begin - game_x <= ukpdat[4]; - game_a <= ukpdat[5]; - game_b <= ukpdat[6]; - game_y <= ukpdat[7]; - end - 6: if (valid) begin - game_sel <= ukpdat[4]; - game_sta <= ukpdat[5]; + if (typ == 1) begin // keyboard + case (rcvct) + 0: key_modifiers <= ukpdat; + 2: key1 <= ukpdat; + 3: key2 <= ukpdat; + 4: key3 <= ukpdat; + 5: key4 <= ukpdat; + endcase + end else if (typ == 2) begin // mouse + case (rcvct) + 0: mouse_btn <= ukpdat; + 1: mouse_dx <= ukpdat; + 2: mouse_dy <= ukpdat; + endcase + end else if (typ == 3) begin // gamepad + // A typical report layout: + // - d[3] is X axis (0: left, 255: right) + // - d[4] is Y axis + // - d[5][7:4] is buttons YBAX + // - d[6][5:4] is buttons START,SELECT + // Variations: + // - Some gamepads uses d[0] and d[1] for X and Y axis. + // - Some transmits a different set when d[0][1:0] is 2 (a dualshock adapater) + case (rcvct) + 0: begin + if (ukpdat[1:0] != 2'b10) begin + // for DualShock2 adapter, 2'b10 marks an irrelevant record + valid <= 1; + game_l <= 0; game_r <= 0; game_u <= 0; game_d <= 0; + end else + valid <= 0; + if (ukpdat==8'h00) {game_l, game_r} <= 2'b10; + if (ukpdat==8'hff) {game_l, game_r} <= 2'b01; + end + 1: begin + if (ukpdat==8'h00) {game_u, game_d} <= 2'b10; + if (ukpdat==8'hff) {game_u, game_d} <= 2'b01; + end + 3: if (valid) begin + if (ukpdat[7:6]==2'b00) {game_l, game_r} <= 2'b10; + if (ukpdat[7:6]==2'b11) {game_l, game_r} <= 2'b01; + end + 4: if (valid) begin + if (ukpdat[7:6]==2'b00) {game_u, game_d} <= 2'b10; + if (ukpdat[7:6]==2'b11) {game_u, game_d} <= 2'b01; + end + 5: if (valid) begin + game_x <= ukpdat[4]; + game_a <= ukpdat[5]; + game_b <= ukpdat[6]; + game_y <= ukpdat[7]; + end + 6: if (valid) begin + game_sel <= ukpdat[4]; + game_sta <= ukpdat[5]; + end + endcase + // TODO: add any special handling if needed + // (using the detected controller type in 'dev') end - endcase - // TODO: add any special handling if needed - // (using the detected controller type in 'dev') + rcvct <= rcvct + 1; end - rcvct <= rcvct + 1; end + if(~data_rdy && data_rdy_r && typ != 0) // falling edge of ukp data ready + report <= 1; end - if(~data_rdy && data_rdy_r && typ != 0) // falling edge of ukp data ready - report <= 1; end reg save_delayed; reg connected_r; always @(posedge usbclk) begin : response_recognition - save_delayed <= save; - if (save) begin - regs[save_r] <= dat[save_b]; - end else if (save_delayed && ~save && save_r == 6) begin - // falling edge of save for bInterfaceProtocol - if (regs[4] == 3) begin // bInterfaceClass. 3: HID, other: non-HID - if (regs[5] == 1) // bInterfaceSubClass. 1: Boot device - typ <= regs[6] == 1 ? 1 : 2; // bInterfaceProtocol. 1: keyboard, 2: mouse - else - typ <= 3; // gamepad - end else - typ <= 0; + if (~usbrst_n) begin + typ <= 0; + end else begin + save_delayed <= save; + if (save) begin + regs[save_r] <= dat[save_b]; + end else if (save_delayed && ~save && save_r == 6) begin + // falling edge of save for bInterfaceProtocol + if (regs[4] == 3) begin // bInterfaceClass. 3: HID, other: non-HID + if (regs[5] == 1) // bInterfaceSubClass. 1: Boot device + typ <= regs[6] == 1 ? 1 : 2; // bInterfaceProtocol. 1: keyboard, 2: mouse + else + typ <= 3; // gamepad + end else + typ <= 0; + end + connected_r <= connected; + if (~connected & connected_r) typ <= 0; // clear device type on disconnect end - connected_r <= connected; - if (~connected & connected_r) typ <= 0; // clear device type on disconnect end endmodule @@ -226,7 +236,7 @@ module ukp( wire record; reg dmid; reg [23:0] conct; - assign conerr = conct[23] || ~usbrst_n; + assign conerr = conct[23]; // || ~usbrst_n; usb_hid_host_rom ukprom(.clk(usbclk), .adr(pc), .data(inst)); @@ -234,6 +244,7 @@ module ukp( if(~usbrst_n) begin pc <= 0; connected <= 0; cond <= 0; inst_ready <= 0; state <= S_OPCODE; timing <= 0; mbit <= 0; bitadr <= 0; nak <= 1; ug <= 0; + dpi <= usb_dp; dmi <= usb_dm; end else begin dpi <= usb_dp; dmi <= usb_dm; save <= 0; // ensure pulse diff --git a/tools/nes2img.py b/tools/nes2img.py index ed33dfe..ee615b0 100644 --- a/tools/nes2img.py +++ b/tools/nes2img.py @@ -50,10 +50,25 @@ def writeBackBinary(): png = os.path.join(os.path.dirname(__file__), 'back.png') with Image.open(png) as im: img = image2nes(im) + # find bounding box of logo + l=256 + r=0 + t=240 + b=0 with open(BIN, 'w') as bin_file: for i in range(240): # print image for debug for j in range(256): bin_file.write('{:06b}\n'.format(img[i][j])) + if img[i][j] != 13: + l = min(j, l) + r = max(j, r) + t = min(i, t) + b = max(i, b) + print('left={}, right={}, top={}, bottom={}'.format(l, r, t, b)) + for y in range(t, b+1): + for x in range(l, r+1): + print('{}'.format('1' if img[y][x] == 4 else '0'), end='') + print('') if BIN != '': # Just write background as binary file writeBackBinary()