From 3e9857f0d77adbfc6485f8929a8026e7f5d37b11 Mon Sep 17 00:00:00 2001 From: Stefan Voss <75468830+vossstef@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:55:01 +0200 Subject: [PATCH] enhanement (#92) --- README.md | 28 +- build_tm138k.tcl | 4 + build_tn20k.tcl | 4 + build_tp25k.tcl | 4 + impl/pnr/device.cfg | 1 + impl/tang_nano_20k_c64_process_config.json | 2 +- src/misc/sysctrl.v | 7 +- src/tang_nano_20k_c64_top.vhd | 186 ++++++-- src/tang_nano_20k_c64_top_138k.vhd | 186 ++++++-- src/tang_nano_20k_c64_top_25k.vhd | 165 +++++-- src/uart_6551/6551rx.v | 269 +++++++++++ src/uart_6551/6551tx.v | 231 ++++++++++ src/uart_6551/BaudRate.vhd | 61 +++ src/uart_6551/uart_6551.v | 508 +++++++++++++++++++++ tang_mega_138k_c64.gprj | 4 + tang_nano_20k_c64.gprj | 4 + tang_primer_25k_c64.gprj | 4 + 17 files changed, 1533 insertions(+), 135 deletions(-) create mode 100644 src/uart_6551/6551rx.v create mode 100644 src/uart_6551/6551tx.v create mode 100644 src/uart_6551/BaudRate.vhd create mode 100644 src/uart_6551/uart_6551.v diff --git a/README.md b/README.md index 0eb447a..d804eac 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Features: * Joystick emulation on Keyboard Numpad
* [Dualshock 2 Gamepad](https://en.wikipedia.org/wiki/DualShock) Keys & Stick as Joystick
* [Dualshock 2 Gamepad](https://en.wikipedia.org/wiki/DualShock) Sticks as [Paddle](https://www.c64-wiki.com/wiki/Paddle) Emulation (analog mode)
+* Emulation of C64GS Cheetah Annihilator joystick 2nd Trigger Button (Pot X/Y) * emulated [1541 Diskdrive](https://en.wikipedia.org/wiki/Commodore_1541) on FAT/extFAT microSD card with parallel bus [Speedloader Dolphin DOS 2](https://rr.pokefinder.org/wiki/Dolphin_DOS). [GER manual](https://www.c64-wiki.de/wiki/Dolphin_DOS)
* c1541 DOS ROM selection * Cartridge ROM (*.CRT) loader @@ -147,7 +148,7 @@ Enable REU, select c1541 CBM DOS ROM and load the PRG.
* S2 keep pressed during power-up for FLASH programming of FPGA bitstream
> [!CAUTION] A FLASH programm attempt without keeping the board in reset may lead to corruption of the C1541 DOS images stored in FLASH requiring re-programming. -* S1 reserved
+* S1 swap the Joystick Ports if OSD **Swap Joys** is set to Off mode.
## OSD invoke by F12 keypress
@@ -168,24 +169,29 @@ invoke by F12 keypress
* SID Filter selection * geoRAM activation * Loader (CRT/PRG/BIN/TAP/FLT) file selection
+* Joystick Port Swap ## Gamecontrol support legacy single D9 Digital Joystick. OSD: **Retro D9**
+Atari ST type of Joystick 2nd button supported using a MiSTeryNano shield. + or
USB Joystick(s). OSD: **USB #1 Joy** or **USB #2 Joy**
or
-Gamepad Stick as Joystick. OSD: **DualShock2** -
**stick digital** for Move and Left **L1** or Right **R1** shoulder Button for Trigger or following **Pad** controls:
+Gamepad Stick as Joystick. OSD: **DualShock 2** + +
left **stick digital** for Move and **square** , **cross** and **circle** Button for 3 Trigger buttons +or following **Pad** controls:
| Buttons | - | - | | - | - | - | -| Left L1/R1
Trigger | triangle button
Up | . | -| square button
Left | - | circle button
Right | -| - | cross button
Down | - |
+| square
Trigger | Up | cross
Trigger 2 | +| Left | - | Right | +| - | Down | circle
Trigger 3 |
or Keyboard Numpad. OSD: **Numpad**
| | | | |-|-|-| -|0
Trigger|8
Up|-| +|0
Trigger|8
Up|.
Trigger 2| |4
Left|-|6
Right| |-|2
Down|-| @@ -194,7 +200,7 @@ USB Mouse as c1351 Mouse emulation. or Dualshock2 Gamepad as Paddle. OSD: **DS2 Paddle**
Dualshock 2 Sticks in analog mode as VC-1312 Paddle emulation.
-Left **L1 / L2** and Right **R1 / R2** shoulder Button as Trigger
+**square** , **cross**, **circle** and **triangle** used as 4 Trigger buttons
You have first to set the DS2 Sticks into analog mode by pressing the DS2 ANALOG button. Mode indicated by red light indicator.
Configure DIGITAL mode (press ANALOG button again) when using the **Joystick** mode again and set OSD: **DualShock**
or USB Paddle. OSD: **USB #1 Padd** or **USB #2 Padd**
@@ -203,7 +209,7 @@ Button **1 / 2** as Trigger
## Keyboard ![Layout](\.assets/keymap.gif) - Tape Play not implemented. + PAGE UP (Tape Play) Key or the Tang S1 Button swap the Joystick Ports if OSD **Swap Joys** is set to Off mode. ## LED UI @@ -265,11 +271,11 @@ see pin configuration in .cst configuration file | 2 |1| J6 9 | 28 | DOWN | | 3 |4| J6 12 | 29 | LEFT | | 4 |3| J5 11 | 26 | RIGHT | -| 5 |-| - | - | POT Y | - | +| 5 |-| - | - | POT Y/ TRIGGER 3| - | | 6 |0| J5 8 | 27 | TRIGGER| | 7 |-| n.c | n.c | 5V | - | | 8 |-| J5 20 | - | GND | - | -| 9 |-| - | - | POT X | - | +| 9 |-| - | MiSTeryNano shield only | POT X/ TRIGGER 2| | **Pinmap Dualshock 2 Controller Interface**
image diff --git a/build_tm138k.tcl b/build_tm138k.tcl index a6cec97..63293cf 100644 --- a/build_tm138k.tcl +++ b/build_tm138k.tcl @@ -68,6 +68,10 @@ add_file src/sid/sid_filter.sv add_file src/sid/sid_tables.sv add_file src/sid/sid_top.sv add_file src/sid/sid_voice.sv +add_file src/uart_6551/6551rx.v +add_file src/uart_6551/6551tx.v +add_file src/uart_6551/uart_6551.v +add_file src/uart_6551/BaudRate.vhd set_option -synthesis_tool gowinsynthesis set_option -output_base_name tang_nano_20k_c64_138k diff --git a/build_tn20k.tcl b/build_tn20k.tcl index a7401dc..bde0649 100644 --- a/build_tn20k.tcl +++ b/build_tn20k.tcl @@ -65,6 +65,10 @@ add_file src/sid/sid_filter.sv add_file src/sid/sid_tables.sv add_file src/sid/sid_top.sv add_file src/sid/sid_voice.sv +add_file src/uart_6551/6551rx.v +add_file src/uart_6551/6551tx.v +add_file src/uart_6551/uart_6551.v +add_file src/uart_6551/BaudRate.vhd set_option -synthesis_tool gowinsynthesis set_option -output_base_name tang_nano_20k_c64 diff --git a/build_tp25k.tcl b/build_tp25k.tcl index ff2a526..79998b4 100644 --- a/build_tp25k.tcl +++ b/build_tp25k.tcl @@ -67,6 +67,10 @@ add_file src/sid/sid_filter.sv add_file src/sid/sid_tables.sv add_file src/sid/sid_top.sv add_file src/sid/sid_voice.sv +add_file src/uart_6551/6551rx.v +add_file src/uart_6551/6551tx.v +add_file src/uart_6551/uart_6551.v +add_file src/uart_6551/BaudRate.vhd set_option -synthesis_tool gowinsynthesis set_option -output_base_name tang_nano_20k_c64_25k diff --git a/impl/pnr/device.cfg b/impl/pnr/device.cfg index c7465c9..ad16672 100644 --- a/impl/pnr/device.cfg +++ b/impl/pnr/device.cfg @@ -19,4 +19,5 @@ set format = binary set power_on_reset_monitor = true set multiboot_spi_flash_address = 0x00000000 set vccx = 3.3 +set vcc = 1.0 set unused_pin = default diff --git a/impl/tang_nano_20k_c64_process_config.json b/impl/tang_nano_20k_c64_process_config.json index 76d096a..719b11c 100644 --- a/impl/tang_nano_20k_c64_process_config.json +++ b/impl/tang_nano_20k_c64_process_config.json @@ -77,7 +77,7 @@ "Synthesize_tool" : "GowinSyn", "TclPre" : "", "TopModule" : "tang_nano_20k_c64_top", - "USERCODE" : "default", + "USERCODE" : "00000001", "Unused_Pin" : "As_input_tri_stated_with_pull_up", "VCC" : "1.0", "VCCAUX" : 3.3, diff --git a/src/misc/sysctrl.v b/src/misc/sysctrl.v index 73a4bfd..3d2675f 100644 --- a/src/misc/sysctrl.v +++ b/src/misc/sysctrl.v @@ -52,7 +52,8 @@ module sysctrl ( output reg [2:0] system_sid_filter, output reg [2:0] system_sid_fc_offset, output reg system_georam, - output reg [1:0] system_uart + output reg [1:0] system_uart, + output reg system_joyswap ); reg [3:0] state; @@ -105,6 +106,8 @@ always @(posedge clk) begin system_sid_fc_offset <= 3'b000; system_georam <= 1'b0; system_uart <= 2'b00; + system_joyswap <= 1'b0; + end else begin int_ack <= 8'h00; @@ -202,6 +205,8 @@ always @(posedge clk) begin if(id == "#") system_georam <= data_in[0]; // RS232 UART port if(id == "*") system_uart <= data_in[1:0]; + // Joystick swap port + if(id == "&") system_joyswap <= data_in[0]; end end diff --git a/src/tang_nano_20k_c64_top.vhd b/src/tang_nano_20k_c64_top.vhd index c3f663a..5781ee2 100644 --- a/src/tang_nano_20k_c64_top.vhd +++ b/src/tang_nano_20k_c64_top.vhd @@ -117,10 +117,13 @@ signal joyMouse : std_logic_vector(6 downto 0); signal joyPaddle : std_logic_vector(6 downto 0); signal joyPaddle2 : std_logic_vector(6 downto 0); signal numpad : std_logic_vector(7 downto 0); +signal numpad_d : std_logic_vector(7 downto 0); signal joyDS2 : std_logic_vector(6 downto 0); -- joystick interface signal joyA : std_logic_vector(6 downto 0); signal joyB : std_logic_vector(6 downto 0); +signal joyA_c64 : std_logic_vector(6 downto 0); +signal joyB_c64 : std_logic_vector(6 downto 0); signal port_1_sel : std_logic_vector(3 downto 0); signal port_2_sel : std_logic_vector(3 downto 0); -- mouse / paddle @@ -296,6 +299,12 @@ signal key_triangle : std_logic; signal key_square : std_logic; signal key_circle : std_logic; signal key_cross : std_logic; +signal key_up : std_logic; +signal key_down : std_logic; +signal key_left : std_logic; +signal key_right : std_logic; +signal key_start : std_logic; +signal key_select : std_logic; signal IDSEL : std_logic_vector(5 downto 0); signal FBDSEL : std_logic_vector(5 downto 0); signal ntscModeD : std_logic; @@ -414,6 +423,11 @@ signal extra_button0 : std_logic_vector(7 downto 0); signal extra_button1 : std_logic_vector(7 downto 0); signal system_uart : std_logic_vector(1 downto 0); signal uart_rx_muxed : std_logic; +signal joyswap : std_logic; +signal user_d : std_logic := '0'; +signal system_joyswap : std_logic; +signal pd1,pd2,pd3,pd4 : std_logic_vector(7 downto 0); +signal cs_uart : std_logic_vector(1 downto 0); -- 64k core ram 0x000000 -- cartridge RAM banks are mapped to 0x010000 @@ -508,10 +522,10 @@ gamepad: entity work.dualshock2 stick_ly => paddle_2, stick_rx => paddle_3, stick_ry => paddle_4, - key_up => open, - key_down => open, - key_left => open, - key_right => open, + key_up => key_up, + key_down => key_down, + key_left => key_left, + key_right => key_right, key_l1 => key_l1, key_l2 => key_l2, key_r1 => key_r1, @@ -520,8 +534,8 @@ gamepad: entity work.dualshock2 key_square => key_square, key_circle => key_circle, key_cross => key_cross, - key_start => open, - key_select => open, + key_start => key_start, + key_select => key_select, key_lstick => open, key_rstick => open, debug1 => open, @@ -894,23 +908,24 @@ flashclock: rPLL leds_n <= not leds; leds(0) <= led1541; -joyDS2 <= ("00" & (key_l1 or key_r1) & key_circle & key_square & key_cross & key_triangle); --- 4 3 2 1 0 digital c64 --- TR RI LE DN UP -joyDigital <= not("11" & io(0) & io(3) & io(4) & io(1) & io(2)); -joyUsb1 <= ("00" & joystick1(4) & joystick1(0) & joystick1(1) & joystick1(2) & joystick1(3)); -joyUsb2 <= ("00" & joystick2(4) & joystick2(0) & joystick2(1) & joystick2(2) & joystick2(3)); -joyNumpad <= "00" & numpad(4) & numpad(0) & numpad(1) & numpad(2) & numpad(3); -joyMouse <= "00" & mouse_btns(0) & "000" & mouse_btns(1); -joyPaddle <= ("00" & '0' & key_l1 & key_l2 & "00"); -- bound to physical paddle position DS2 -joyPaddle2 <= ("00" & '0' & key_r1 & key_r2 & "00"); -joyUsb1A <= ("00" & '0' & joystick1(5) & joystick1(4) & "00"); -- Y,X button -joyUsb2A <= ("00" & '0' & joystick2(5) & joystick2(4) & "00"); -- Y,X button + +-- 6 5 4 3 2 1 0 +-- TR3 TR2 TR RI LE DN UP digital c64 +joyDS2 <= key_circle & key_cross & key_square & key_right & key_left & key_down & key_up; +joyDigital <= not('1' & io(5) & io(0) & io(3) & io(4) & io(1) & io(2)); +joyUsb1 <= joystick1(6 downto 4) & joystick1(0) & joystick1(1) & joystick1(2) & joystick1(3); +joyUsb2 <= joystick2(6 downto 4) & joystick2(0) & joystick2(1) & joystick2(2) & joystick2(3); +joyNumpad <= '0' & numpad(5 downto 4) & numpad(0) & numpad(1) & numpad(2) & numpad(3); +joyMouse <= "00" & mouse_btns(0) & "000" & mouse_btns(1); +joyPaddle <= "00" & '0' & key_cross & key_square & "00"; -- single DS left stick +joyPaddle2 <= "00" & '0' & key_triangle & key_circle & "00"; -- single DS right stick +joyUsb1A <= "00" & '0' & joystick1(5) & joystick1(4) & "00"; -- Y,X button +joyUsb2A <= "00" & '0' & joystick2(5) & joystick2(4) & "00"; -- Y,X button -- send external DB9 joystick port to µC -db9_joy <= not('1' & io(0), io(2), io(1), io(4), io(3)); -io(5) <= 'Z'; -- reserved for digital joystick button 2 +db9_joy <= not(io(5) & io(0), io(2), io(1), io(4), io(3)); +-- http://wiki.icomp.de/wiki/DE-9_Joystick:de process(clk32) begin if rising_edge(clk32) then @@ -934,11 +949,11 @@ process(clk32) begin if rising_edge(clk32) then case port_2_sel is - when "0000" => joyB <= joyDigital; - when "0001" => joyB <= joyUsb1; - when "0010" => joyB <= joyUsb2; - when "0011" => joyB <= joyNumpad; - when "0100" => joyB <= joyDS2; + when "0000" => joyB <= joyDigital; -- 2nd button + when "0001" => joyB <= joyUsb1; -- 2nd button + when "0010" => joyB <= joyUsb2; -- 2nd button + when "0011" => joyB <= joyNumpad; -- 2nd button + when "0100" => joyB <= joyDS2; -- 2nd button when "0101" => joyB <= joyMouse; when "0110" => joyB <= joyPaddle2; when "0111" => joyB <= joyUsb1A; @@ -949,17 +964,62 @@ begin end if; end process; --- paddle pins - mouse -pot1 <= not paddle_1 when port_1_sel = "0110" else joystick1_x_pos(7 downto 0) when port_1_sel = "0111" else ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_1_sel = "0101" else x"ff"; -pot2 <= not paddle_2 when port_1_sel = "0110" else joystick1_y_pos(7 downto 0) when port_1_sel = "0111" else ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_1_sel = "0101" else x"ff"; -pot3 <= not paddle_3 when port_2_sel = "0110" else joystick2_x_pos(7 downto 0) when port_2_sel = "1000" else ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_2_sel = "0101" else x"ff"; -pot4 <= not paddle_4 when port_2_sel = "0110" else joystick2_y_pos(7 downto 0) when port_2_sel = "1000" else ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_2_sel = "0101" else x"ff"; +-- process to toggle joy A/B port with USER button or Keyboard page-up (STRG + CSR UP) +-- TN20k,TP25k user button is high active +-- TM138k pro low active +process(clk32) +begin + if rising_edge(clk32) then + if vsync = '1' then + user_d <= user; + numpad_d <= numpad; + if (user = '1' and user_d = '0') or + (numpad(7) = '1' and numpad_d(7) = '0') then + joyswap <= not joyswap; -- toggle mode + elsif system_joyswap = '1' then -- OSD fixed setting mode + joyswap <= '1'; -- OSD fixed setting mode + end if; + end if; + end if; +end process; + +-- swap joysticks +joyA_c64 <= joyB when joyswap = '1' else joyA; +joyB_c64 <= joyA when joyswap = '1' else joyB; + +-- swap paddle +pot1 <= pd3 when joyswap = '1' else pd1; +pot2 <= pd4 when joyswap = '1' else pd2; +pot3 <= pd1 when joyswap = '1' else pd3; +pot4 <= pd2 when joyswap = '1' else pd4; + +-- paddle - mouse - GS controller 2nd button and 3rd button +pd1 <= not paddle_1 when port_1_sel = "0110" else + joystick1_x_pos(7 downto 0) when port_1_sel = "0111" else + ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_1_sel = "0101" else + x"00" when port_1_sel < 5 and joyA_c64(5) = '1' else + x"ff"; +pd2 <= not paddle_2 when port_1_sel = "0110" else + joystick1_y_pos(7 downto 0) when port_1_sel = "0111" else + ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_1_sel = "0101" else + x"00" when port_1_sel < 5 and joyA_c64(6) = '1' else + x"ff"; +pd3 <= not paddle_3 when port_2_sel = "0110" else + joystick2_x_pos(7 downto 0) when port_2_sel = "1000" else + ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_2_sel = "0101" else + x"00" when port_2_sel < 5 and joyB_c64(5) = '1' else + x"ff"; +pd4 <= not paddle_4 when port_2_sel = "0110" else + joystick2_y_pos(7 downto 0) when port_2_sel = "1000" else + ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_2_sel = "0101" else + x"00" when port_2_sel < 5 and joyB_c64(6) = '1' else + x"ff"; process(clk32, reset_n) variable mov_x: signed(6 downto 0); variable mov_y: signed(6 downto 0); begin - if reset_n = '0' then + if reset_n = '0' then mouse_x_pos <= (others => '0'); mouse_y_pos <= (others => '0'); joystick1_x_pos <= x"ff"; @@ -1080,7 +1140,7 @@ hid_inst: entity work.hid system_sid_fc_offset => sid_fc_offset, system_georam => georam, system_uart => system_uart, - + system_joyswap => system_joyswap, int_out_n => m0s(4), int_in => std_logic_vector(unsigned'(x"0" & sdc_int & "0" & hid_int & "0")), int_ack => int_ack, @@ -1195,8 +1255,8 @@ fpga64_sid_iec_inst: entity work.fpga64_sid_iec irq_ext_n => not reu_irq, -- joystick interface - joyA => joyA, - joyB => joyB, + joyA => joyA_c64, + joyB => joyB_c64, pot1 => pot1, pot2 => pot2, pot3 => pot3, @@ -1347,7 +1407,7 @@ port map data_in => c64_data_out, addr_out => cart_addr, - freeze_key => freeze_key, + freeze_key => numpad(6), mod_key => '0', nmi => nmi, nmi_ack => nmi_ack @@ -1670,15 +1730,17 @@ port map ( uart_rx_muxed <= uart_rx when system_uart = "00" else io(6) when system_uart = "01" else '1'; io(7) <= uart_tx; - -- UART_RX synchronizer - process(clk32) - begin - if rising_edge(clk32) then - uart_rxD <= uart_rxD(2 downto 0) & uart_rx_muxed; - if uart_rxD = "0000" then uart_rx_filtered <= '0'; end if; - if uart_rxD = "1111" then uart_rx_filtered <= '1'; end if; - end if; - end process; +-- UART_RX synchronizer +process(clk32) +begin + if rising_edge(clk32) then + uart_rxD(0) <= uart_rx_muxed; + uart_rxD(1) <= uart_rxD(0); + if uart_rxD(0) = uart_rxD(1) then + uart_rx_filtered <= uart_rxD(1); + end if; + end if; +end process; -- connect user port process (all) @@ -1748,4 +1810,40 @@ begin end if; end process; +-- 3.686.400Hz clock enable derived from 315 Mhz clock +--baudgen_inst: entity work.BaudRate +--port map( +-- i_CLOCK => clk_pixel_x10, +-- o_serialEn => CLK_6551_EN +--); + +-- | SwiftLink $DE00/$DF00/$D700/NMI (300-38400 baud) +-- | Turbo-232 only: $DE07/56839/TURBO232+7 Enhanced-Speed Register +-- https://gglabs.us/node/2057 + +cs_uart <= not uart_en & uart_cs; + +--uart_inst : entity work.glb6551 +--port map ( +-- RESET_N => reset_n, +-- CLK => clk32, +-- RX_CLK => open, +-- RX_CLK_IN => CLK_6551_EN, +-- XTAL_CLK_IN => CLK_6551_EN, +-- PH_2 => phi2_p, +-- DI => c64_data_out, +-- DO => uart_data, +-- IRQ => uart_irq, +-- CS => cs_uart, +-- RW_N => not (ram_we and uart_cs), +-- RS => c64_addr(1 downto 0), +-- TXDATA_OUT => tx_6551, +-- RXDATA_IN => uart_rx_filtered, +-- RTS => open, +-- CTS => '1', +-- DCD => '1', +-- DTR => open, +-- DSR => '1' +-- ); + end Behavioral_top; diff --git a/src/tang_nano_20k_c64_top_138k.vhd b/src/tang_nano_20k_c64_top_138k.vhd index 18f5c5f..67e6e88 100644 --- a/src/tang_nano_20k_c64_top_138k.vhd +++ b/src/tang_nano_20k_c64_top_138k.vhd @@ -128,10 +128,13 @@ signal joyMouse : std_logic_vector(6 downto 0); signal joyPaddle : std_logic_vector(6 downto 0); signal joyPaddle2 : std_logic_vector(6 downto 0); signal numpad : std_logic_vector(7 downto 0); +signal numpad_d : std_logic_vector(7 downto 0); signal joyDS2 : std_logic_vector(6 downto 0); -- joystick interface signal joyA : std_logic_vector(6 downto 0); signal joyB : std_logic_vector(6 downto 0); +signal joyA_c64 : std_logic_vector(6 downto 0); +signal joyB_c64 : std_logic_vector(6 downto 0); signal port_1_sel : std_logic_vector(3 downto 0); signal port_2_sel : std_logic_vector(3 downto 0); -- mouse / paddle @@ -307,6 +310,12 @@ signal key_triangle : std_logic; signal key_square : std_logic; signal key_circle : std_logic; signal key_cross : std_logic; +signal key_up : std_logic; +signal key_down : std_logic; +signal key_left : std_logic; +signal key_right : std_logic; +signal key_start : std_logic; +signal key_select : std_logic; signal audio_div : unsigned(8 downto 0); signal flash_clk : std_logic; signal flash_lock : std_logic; @@ -423,6 +432,11 @@ signal extra_button0 : std_logic_vector(7 downto 0); signal extra_button1 : std_logic_vector(7 downto 0); signal system_uart : std_logic_vector(1 downto 0); signal uart_rx_muxed : std_logic; +signal joyswap : std_logic; +signal user_d : std_logic := '0'; +signal system_joyswap : std_logic; +signal pd1,pd2,pd3,pd4 : std_logic_vector(7 downto 0); +signal cs_uart : std_logic_vector(1 downto 0); -- 64k core ram 0x000000 -- cartridge RAM banks are mapped to 0x010000 @@ -475,10 +489,10 @@ gamepad: entity work.dualshock2 stick_ly => paddle_2, stick_rx => paddle_3, stick_ry => paddle_4, - key_up => open, - key_down => open, - key_left => open, - key_right => open, + key_up => key_up, + key_down => key_down, + key_left => key_left, + key_right => key_right, key_l1 => key_l1, key_l2 => key_l2, key_r1 => key_r1, @@ -487,8 +501,8 @@ gamepad: entity work.dualshock2 key_square => key_square, key_circle => key_circle, key_cross => key_cross, - key_start => open, - key_select => open, + key_start => key_start, + key_select => key_select, key_lstick => open, key_rstick => open, debug1 => open, @@ -810,23 +824,24 @@ flashclock: entity work.Gowin_PLL_138k_flash leds_n <= not leds; leds(0) <= led1541; -joyDS2 <= ("00" & (key_l1 or key_r1) & key_circle & key_square & key_cross & key_triangle); --- 4 3 2 1 0 digital c64 --- TR RI LE DN UP -joyDigital <= not("11" & io(0) & io(3) & io(4) & io(1) & io(2)); -joyUsb1 <= ("00" & joystick1(4) & joystick1(0) & joystick1(1) & joystick1(2) & joystick1(3)); -joyUsb2 <= ("00" & joystick2(4) & joystick2(0) & joystick2(1) & joystick2(2) & joystick2(3)); -joyNumpad <= "00" & numpad(4) & numpad(0) & numpad(1) & numpad(2) & numpad(3); -joyMouse <= "00" & mouse_btns(0) & "000" & mouse_btns(1); -joyPaddle <= ("00" & '0' & key_l1 & key_l2 & "00"); -- bound to physical paddle position DS2 -joyPaddle2 <= ("00" & '0' & key_r1 & key_r2 & "00"); -joyUsb1A <= ("00" & '0' & joystick1(5) & joystick1(4) & "00"); -- Y,X button -joyUsb2A <= ("00" & '0' & joystick2(5) & joystick2(4) & "00"); -- Y,X button + +-- 6 5 4 3 2 1 0 +-- TR3 TR2 TR RI LE DN UP digital c64 +joyDS2 <= key_circle & key_cross & key_square & key_right & key_left & key_down & key_up; +joyDigital <= not('1' & io(5) & io(0) & io(3) & io(4) & io(1) & io(2)); +joyUsb1 <= joystick1(6 downto 4) & joystick1(0) & joystick1(1) & joystick1(2) & joystick1(3); +joyUsb2 <= joystick2(6 downto 4) & joystick2(0) & joystick2(1) & joystick2(2) & joystick2(3); +joyNumpad <= '0' & numpad(5 downto 4) & numpad(0) & numpad(1) & numpad(2) & numpad(3); +joyMouse <= "00" & mouse_btns(0) & "000" & mouse_btns(1); +joyPaddle <= "00" & '0' & key_cross & key_square & "00"; -- single DS left stick +joyPaddle2 <= "00" & '0' & key_triangle & key_circle & "00"; -- single DS right stick +joyUsb1A <= "00" & '0' & joystick1(5) & joystick1(4) & "00"; -- Y,X button +joyUsb2A <= "00" & '0' & joystick2(5) & joystick2(4) & "00"; -- Y,X button -- send external DB9 joystick port to µC -db9_joy <= not('1' & io(0), io(2), io(1), io(4), io(3)); -io(5) <= 'Z'; -- reserved for digital joystick button 2 +db9_joy <= not(io(5) & io(0), io(2), io(1), io(4), io(3)); +-- http://wiki.icomp.de/wiki/DE-9_Joystick:de process(clk32) begin if rising_edge(clk32) then @@ -850,11 +865,11 @@ process(clk32) begin if rising_edge(clk32) then case port_2_sel is - when "0000" => joyB <= joyDigital; - when "0001" => joyB <= joyUsb1; - when "0010" => joyB <= joyUsb2; - when "0011" => joyB <= joyNumpad; - when "0100" => joyB <= joyDS2; + when "0000" => joyB <= joyDigital; -- 2nd button + when "0001" => joyB <= joyUsb1; -- 2nd button + when "0010" => joyB <= joyUsb2; -- 2nd button + when "0011" => joyB <= joyNumpad; -- 2nd button + when "0100" => joyB <= joyDS2; -- 2nd button when "0101" => joyB <= joyMouse; when "0110" => joyB <= joyPaddle2; when "0111" => joyB <= joyUsb1A; @@ -865,11 +880,56 @@ begin end if; end process; --- paddle pins - mouse -pot1 <= not paddle_1 when port_1_sel = "0110" else joystick1_x_pos(7 downto 0) when port_1_sel = "0111" else ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_1_sel = "0101" else x"ff"; -pot2 <= not paddle_2 when port_1_sel = "0110" else joystick1_y_pos(7 downto 0) when port_1_sel = "0111" else ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_1_sel = "0101" else x"ff"; -pot3 <= not paddle_3 when port_2_sel = "0110" else joystick2_x_pos(7 downto 0) when port_2_sel = "1000" else ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_2_sel = "0101" else x"ff"; -pot4 <= not paddle_4 when port_2_sel = "0110" else joystick2_y_pos(7 downto 0) when port_2_sel = "1000" else ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_2_sel = "0101" else x"ff"; +-- process to toggle joy A/B port with USER button or Keyboard page-up (STRG + CSR UP) +-- TN20k,TP25k user button is high active +-- TM138k pro low active +process(clk32) +begin + if rising_edge(clk32) then + if vsync = '1' then + user_d <= user; + numpad_d <= numpad; + if (user = '0' and user_d = '1') or + (numpad(7) = '1' and numpad_d(7) = '0') then + joyswap <= not joyswap; -- toggle mode + elsif system_joyswap = '1' then -- OSD fixed setting mode + joyswap <= '1'; -- OSD fixed setting mode + end if; + end if; + end if; +end process; + +-- swap joysticks +joyA_c64 <= joyB when joyswap = '1' else joyA; +joyB_c64 <= joyA when joyswap = '1' else joyB; + +-- swap paddle +pot1 <= pd3 when joyswap = '1' else pd1; +pot2 <= pd4 when joyswap = '1' else pd2; +pot3 <= pd1 when joyswap = '1' else pd3; +pot4 <= pd2 when joyswap = '1' else pd4; + +-- paddle - mouse - GS controller 2nd button and 3rd button +pd1 <= not paddle_1 when port_1_sel = "0110" else + joystick1_x_pos(7 downto 0) when port_1_sel = "0111" else + ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_1_sel = "0101" else + x"00" when port_1_sel < 5 and joyA_c64(5) = '1' else + x"ff"; +pd2 <= not paddle_2 when port_1_sel = "0110" else + joystick1_y_pos(7 downto 0) when port_1_sel = "0111" else + ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_1_sel = "0101" else + x"00" when port_1_sel < 5 and joyA_c64(6) = '1' else + x"ff"; +pd3 <= not paddle_3 when port_2_sel = "0110" else + joystick2_x_pos(7 downto 0) when port_2_sel = "1000" else + ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_2_sel = "0101" else + x"00" when port_2_sel < 5 and joyB_c64(5) = '1' else + x"ff"; +pd4 <= not paddle_4 when port_2_sel = "0110" else + joystick2_y_pos(7 downto 0) when port_2_sel = "1000" else + ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_2_sel = "0101" else + x"00" when port_2_sel < 5 and joyB_c64(6) = '1' else + x"ff"; process(clk32, reset_n) variable mov_x: signed(6 downto 0); @@ -956,7 +1016,7 @@ hid_inst: entity work.hid joystick_strobe => joystick_strobe, extra_button0 => extra_button0, extra_button1 => extra_button1 - ); +); module_inst: entity work.sysctrl port map @@ -996,7 +1056,7 @@ hid_inst: entity work.hid system_sid_fc_offset => sid_fc_offset, system_georam => georam, system_uart => system_uart, - + system_joyswap => system_joyswap, int_out_n => m0s(4), int_in => std_logic_vector(unsigned'(x"0" & sdc_int & "0" & hid_int & "0")), int_ack => int_ack, @@ -1111,8 +1171,8 @@ fpga64_sid_iec_inst: entity work.fpga64_sid_iec irq_ext_n => not reu_irq, -- joystick interface - joyA => joyA, - joyB => joyB, + joyA => joyA_c64, + joyB => joyB_c64, pot1 => pot1, pot2 => pot2, pot3 => pot3, @@ -1263,7 +1323,7 @@ port map data_in => c64_data_out, addr_out => cart_addr, - freeze_key => freeze_key, + freeze_key => numpad(6), mod_key => '0', nmi => nmi, nmi_ack => nmi_ack @@ -1586,15 +1646,17 @@ port map ( uart_rx_muxed <= uart_rx when system_uart = "00" else io(6) when system_uart = "01" else '1'; io(7) <= uart_tx; - -- UART_RX synchronizer - process(clk32) - begin - if rising_edge(clk32) then - uart_rxD <= uart_rxD(2 downto 0) & uart_rx_muxed; - if uart_rxD = "0000" then uart_rx_filtered <= '0'; end if; - if uart_rxD = "1111" then uart_rx_filtered <= '1'; end if; - end if; - end process; +-- UART_RX synchronizer +process(clk32) +begin + if rising_edge(clk32) then + uart_rxD(0) <= uart_rx_muxed; + uart_rxD(1) <= uart_rxD(0); + if uart_rxD(0) = uart_rxD(1) then + uart_rx_filtered <= uart_rxD(1); + end if; + end if; +end process; -- connect user port process (all) @@ -1664,4 +1726,40 @@ begin end if; end process; +-- 3.686.400Hz clock enable derived from 315 Mhz clock +--baudgen_inst: entity work.BaudRate +--port map( +-- i_CLOCK => clk_pixel_x10, +-- o_serialEn => CLK_6551_EN +--); + +-- | SwiftLink $DE00/$DF00/$D700/NMI (300-38400 baud) +-- | Turbo-232 only: $DE07/56839/TURBO232+7 Enhanced-Speed Register +-- https://gglabs.us/node/2057 + +cs_uart <= not uart_en & uart_cs; + +--uart_inst : entity work.glb6551 +--port map ( +-- RESET_N => reset_n, +-- CLK => clk32, +-- RX_CLK => open, +-- RX_CLK_IN => CLK_6551_EN, +-- XTAL_CLK_IN => CLK_6551_EN, +-- PH_2 => phi2_p, +-- DI => c64_data_out, +-- DO => uart_data, +-- IRQ => uart_irq, +-- CS => cs_uart, +-- RW_N => not (ram_we and uart_cs), +-- RS => c64_addr(1 downto 0), +-- TXDATA_OUT => tx_6551, +-- RXDATA_IN => uart_rx_filtered, +-- RTS => open, +-- CTS => '1', +-- DCD => '1', +-- DTR => open, +-- DSR => '1' +-- ); + end Behavioral_top; diff --git a/src/tang_nano_20k_c64_top_25k.vhd b/src/tang_nano_20k_c64_top_25k.vhd index 31667aa..79fa74f 100644 --- a/src/tang_nano_20k_c64_top_25k.vhd +++ b/src/tang_nano_20k_c64_top_25k.vhd @@ -122,10 +122,13 @@ signal joyMouse : std_logic_vector(6 downto 0); signal joyPaddle : std_logic_vector(6 downto 0); signal joyPaddle2 : std_logic_vector(6 downto 0); signal numpad : std_logic_vector(7 downto 0); +signal numpad_d : std_logic_vector(7 downto 0); signal joyDS2 : std_logic_vector(6 downto 0); -- joystick interface signal joyA : std_logic_vector(6 downto 0); signal joyB : std_logic_vector(6 downto 0); +signal joyA_c64 : std_logic_vector(6 downto 0); +signal joyB_c64 : std_logic_vector(6 downto 0); signal port_1_sel : std_logic_vector(3 downto 0); signal port_2_sel : std_logic_vector(3 downto 0); -- mouse / paddle @@ -301,6 +304,12 @@ signal key_triangle : std_logic; signal key_square : std_logic; signal key_circle : std_logic; signal key_cross : std_logic; +signal key_up : std_logic; +signal key_down : std_logic; +signal key_left : std_logic; +signal key_right : std_logic; +signal key_start : std_logic; +signal key_select : std_logic; signal audio_div : unsigned(8 downto 0); signal flash_clk : std_logic; signal flash_lock : std_logic; @@ -419,6 +428,11 @@ signal extra_button0 : std_logic_vector(7 downto 0); signal extra_button1 : std_logic_vector(7 downto 0); signal system_uart : std_logic_vector(1 downto 0); signal uart_rx_muxed : std_logic; +signal joyswap : std_logic; +signal user_d : std_logic := '0'; +signal system_joyswap : std_logic; +signal pd1,pd2,pd3,pd4 : std_logic_vector(7 downto 0); +signal cs_uart : std_logic_vector(1 downto 0); -- 64k core ram 0x000000 -- cartridge RAM banks are mapped to 0x010000 @@ -759,14 +773,14 @@ leds(1) <= system_leds(0); -- 4 3 2 1 0 digital c64 joyDS2 <= (others => '0'); joyDigital <= (others => '0'); -joyUsb1 <= ("00" & joystick1(4) & joystick1(0) & joystick1(1) & joystick1(2) & joystick1(3)); -joyUsb2 <= ("00" & joystick2(4) & joystick2(0) & joystick2(1) & joystick2(2) & joystick2(3)); -joyNumpad <= "00" & numpad(4) & numpad(0) & numpad(1) & numpad(2) & numpad(3); -joyMouse <= "00" & mouse_btns(0) & "000" & mouse_btns(1); -joyPaddle <= ("00" & '0' & key_l1 & key_l2 & "00"); -- bound to physical paddle position DS2 -joyPaddle2 <= ("00" & '0' & key_r1 & key_r2 & "00"); -joyUsb1A <= ("00" & '0' & joystick1(5) & joystick1(4) & "00"); -- Y,X button -joyUsb2A <= ("00" & '0' & joystick2(5) & joystick2(4) & "00"); -- Y,X button +joyUsb1 <= joystick1(6 downto 4) & joystick1(0) & joystick1(1) & joystick1(2) & joystick1(3); +joyUsb2 <= joystick2(6 downto 4) & joystick2(0) & joystick2(1) & joystick2(2) & joystick2(3); +joyNumpad <= '0' & numpad(5 downto 4) & numpad(0) & numpad(1) & numpad(2) & numpad(3); +joyMouse <= "00" & mouse_btns(0) & "000" & mouse_btns(1); +joyPaddle <= (others => '0'); +joyPaddle2 <= (others => '0'); +joyUsb1A <= "00" & '0' & joystick1(5) & joystick1(4) & "00"; -- Y,X button +joyUsb2A <= "00" & '0' & joystick2(5) & joystick2(4) & "00"; -- Y,X button -- send external DB9 joystick port to µC db9_joy <= "000000"; @@ -794,11 +808,11 @@ process(clk32) begin if rising_edge(clk32) then case port_2_sel is - when "0000" => joyB <= joyDigital; - when "0001" => joyB <= joyUsb1; - when "0010" => joyB <= joyUsb2; - when "0011" => joyB <= joyNumpad; - when "0100" => joyB <= joyDS2; + when "0000" => joyB <= joyDigital; -- 2nd button + when "0001" => joyB <= joyUsb1; -- 2nd button + when "0010" => joyB <= joyUsb2; -- 2nd button + when "0011" => joyB <= joyNumpad; -- 2nd button + when "0100" => joyB <= joyDS2; -- 2nd button when "0101" => joyB <= joyMouse; when "0110" => joyB <= joyPaddle2; when "0111" => joyB <= joyUsb1A; @@ -809,17 +823,62 @@ begin end if; end process; --- paddle pins - mouse -pot1 <= not paddle_1 when port_1_sel = "0110" else joystick1_x_pos(7 downto 0) when port_1_sel = "0111" else ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_1_sel = "0101" else x"ff"; -pot2 <= not paddle_2 when port_1_sel = "0110" else joystick1_y_pos(7 downto 0) when port_1_sel = "0111" else ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_1_sel = "0101" else x"ff"; -pot3 <= not paddle_3 when port_2_sel = "0110" else joystick2_x_pos(7 downto 0) when port_2_sel = "1000" else ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_2_sel = "0101" else x"ff"; -pot4 <= not paddle_4 when port_2_sel = "0110" else joystick2_y_pos(7 downto 0) when port_2_sel = "1000" else ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_2_sel = "0101" else x"ff"; +-- process to toggle joy A/B port with USER button or Keyboard page-up (STRG + CSR UP) +-- TN20k,TP25k user button is high active +-- TM138k pro low active +process(clk32) +begin + if rising_edge(clk32) then + if vsync = '1' then + user_d <= user; + numpad_d <= numpad; + if (user = '1' and user_d = '0') or + (numpad(7) = '1' and numpad_d(7) = '0') then + joyswap <= not joyswap; -- toggle mode + elsif system_joyswap = '1' then -- OSD fixed setting mode + joyswap <= '1'; -- OSD fixed setting mode + end if; + end if; + end if; +end process; + +-- swap joysticks +joyA_c64 <= joyB when joyswap = '1' else joyA; +joyB_c64 <= joyA when joyswap = '1' else joyB; + +-- swap paddle +pot1 <= pd3 when joyswap = '1' else pd1; +pot2 <= pd4 when joyswap = '1' else pd2; +pot3 <= pd1 when joyswap = '1' else pd3; +pot4 <= pd2 when joyswap = '1' else pd4; + +-- paddle - mouse - GS controller 2nd button and 3rd button +pd1 <= not paddle_1 when port_1_sel = "0110" else + joystick1_x_pos(7 downto 0) when port_1_sel = "0111" else + ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_1_sel = "0101" else + x"00" when port_1_sel < 5 and joyA_c64(5) = '1' else + x"ff"; +pd2 <= not paddle_2 when port_1_sel = "0110" else + joystick1_y_pos(7 downto 0) when port_1_sel = "0111" else + ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_1_sel = "0101" else + x"00" when port_1_sel < 5 and joyA_c64(6) = '1' else + x"ff"; +pd3 <= not paddle_3 when port_2_sel = "0110" else + joystick2_x_pos(7 downto 0) when port_2_sel = "1000" else + ('0' & std_logic_vector(mouse_x_pos(6 downto 1)) & '0') when port_2_sel = "0101" else + x"00" when port_2_sel < 5 and joyB_c64(5) = '1' else + x"ff"; +pd4 <= not paddle_4 when port_2_sel = "0110" else + joystick2_y_pos(7 downto 0) when port_2_sel = "1000" else + ('0' & std_logic_vector(mouse_y_pos(6 downto 1)) & '0') when port_2_sel = "0101" else + x"00" when port_2_sel < 5 and joyB_c64(6) = '1' else + x"ff"; process(clk32, reset_n) variable mov_x: signed(6 downto 0); variable mov_y: signed(6 downto 0); begin - if reset_n = '0' then + if reset_n = '0' then mouse_x_pos <= (others => '0'); mouse_y_pos <= (others => '0'); joystick1_x_pos <= x"ff"; @@ -900,7 +959,7 @@ hid_inst: entity work.hid joystick_strobe => joystick_strobe, extra_button0 => extra_button0, extra_button1 => extra_button1 - ); +); module_inst: entity work.sysctrl port map @@ -940,7 +999,7 @@ hid_inst: entity work.hid system_sid_fc_offset => sid_fc_offset, system_georam => georam, system_uart => system_uart, - + system_joyswap => system_joyswap, int_out_n => m0s(4), int_in => std_logic_vector(unsigned'(x"0" & sdc_int & "0" & hid_int & "0")), int_ack => int_ack, @@ -1055,8 +1114,8 @@ fpga64_sid_iec_inst: entity work.fpga64_sid_iec irq_ext_n => not reu_irq, -- joystick interface - joyA => joyA, - joyB => joyB, + joyA => joyA_c64, + joyB => joyB_c64, pot1 => pot1, pot2 => pot2, pot3 => pot3, @@ -1207,7 +1266,7 @@ port map data_in => c64_data_out, addr_out => cart_addr, - freeze_key => freeze_key, + freeze_key => numpad(6), mod_key => '0', nmi => nmi, nmi_ack => nmi_ack @@ -1227,7 +1286,7 @@ port map RnW => not (ram_we and IOE), nIRQ => midi_irq_n, nNMI => midi_nmi_n, - + RX => midi_rx, TX => midi_tx ); @@ -1530,15 +1589,17 @@ port map ( uart_rx_muxed <= uart_rx when system_uart = "00" else io(6) when system_uart = "01" else '1'; io(7) <= uart_tx; - -- UART_RX synchronizer - process(clk32) - begin - if rising_edge(clk32) then - uart_rxD <= uart_rxD(2 downto 0) & uart_rx_muxed; - if uart_rxD = "0000" then uart_rx_filtered <= '0'; end if; - if uart_rxD = "1111" then uart_rx_filtered <= '1'; end if; - end if; - end process; +-- UART_RX synchronizer +process(clk32) +begin + if rising_edge(clk32) then + uart_rxD(0) <= uart_rx_muxed; + uart_rxD(1) <= uart_rxD(0); + if uart_rxD(0) = uart_rxD(1) then + uart_rx_filtered <= uart_rxD(1); + end if; + end if; +end process; -- connect user port process (all) @@ -1608,4 +1669,40 @@ begin end if; end process; +-- 3.686.400Hz clock enable derived from 315 Mhz clock +--baudgen_inst: entity work.BaudRate +--port map( +-- i_CLOCK => clk_pixel_x10, +-- o_serialEn => CLK_6551_EN +--); + +-- | SwiftLink $DE00/$DF00/$D700/NMI (300-38400 baud) +-- | Turbo-232 only: $DE07/56839/TURBO232+7 Enhanced-Speed Register +-- https://gglabs.us/node/2057 + +cs_uart <= not uart_en & uart_cs; + +--uart_inst : entity work.glb6551 +--port map ( +-- RESET_N => reset_n, +-- CLK => clk32, +-- RX_CLK => open, +-- RX_CLK_IN => CLK_6551_EN, +-- XTAL_CLK_IN => CLK_6551_EN, +-- PH_2 => phi2_p, +-- DI => c64_data_out, +-- DO => uart_data, +-- IRQ => uart_irq, +-- CS => cs_uart, +-- RW_N => not (ram_we and uart_cs), +-- RS => c64_addr(1 downto 0), +-- TXDATA_OUT => tx_6551, +-- RXDATA_IN => uart_rx_filtered, +-- RTS => open, +-- CTS => '1', +-- DCD => '1', +-- DTR => open, +-- DSR => '1' +-- ); + end Behavioral_top; diff --git a/src/uart_6551/6551rx.v b/src/uart_6551/6551rx.v new file mode 100644 index 0000000..0be834b --- /dev/null +++ b/src/uart_6551/6551rx.v @@ -0,0 +1,269 @@ +//////////////////////////////////////////////////////////////////////////////// +// Project Name: CoCo3FPGA Version 4.0 +// File Name: 6551rx.v +// +// CoCo3 in an FPGA +// +// Revision: 4.0 07/10/16 +//////////////////////////////////////////////////////////////////////////////// +// +// CPU section copyrighted by John Kent +// The FDC co-processor copyrighted Daniel Wallner. +// SDRAM Controller copyrighted by XESS Corp. +// +//////////////////////////////////////////////////////////////////////////////// +// +// Color Computer 3 compatible system on a chip +// +// Version : 4.0 +// +// Copyright (c) 2008 Gary Becker (gary_l_becker@yahoo.com) +// +// All rights reserved +// +// Redistribution and use in source and synthezised forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// Redistributions in synthesized form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Please report bugs to the author, but before you do so, please +// make sure that this is not a derivative work and that +// you have the latest version of this file. +// +// The latest version of this file can be found at: +// http://groups.yahoo.com/group/CoCo3FPGA +// +// File history : +// +// 1.0 Full Release +// 2.0 Partial Release +// 3.0 Full Release +// 3.0.0.1 Update to fix DoD interrupt issue +// 3.0.1.0 Update to fix 32/40 CoCO3 Text issue and add 2 Meg max memory +// 4.0.X.X Full Release +//////////////////////////////////////////////////////////////////////////////// +// Gary Becker +// gary_L_becker@yahoo.com +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// MISTer Conversion by Stan Hodge and Alan Steremberg (& Gary Becker) +// stan.pda@gmail.com +// +// 1/11/22 Changed to be super synchronus +//////////////////////////////////////////////////////////////////////////////// + +module uart51_rx( +RESET_N, +CLK, +BAUD_CLK, +//E, +//REG_READ, +RX_DATA, +RX_BUFFER, +// RX_READY, +RX_WORD, +RX_PAR_DIS, +RX_PARITY, +PARITY_ERR, +// OVERRUN, +FRAME, +READY +); +input RESET_N; +input CLK; +input BAUD_CLK; +//input E; +//input REG_READ; +input RX_DATA; +output [7:0] RX_BUFFER; +reg [7:0] RX_BUFFER; +// input RX_READY; +// reg RX_READY; +input [1:0] RX_WORD; +input RX_PAR_DIS; +input [1:0] RX_PARITY; +output PARITY_ERR; +reg PARITY_ERR; +// output OVERRUN; +// reg OVERRUN; +output FRAME; +reg FRAME; +output READY; +reg READY; +reg [5:0] STATE; +reg [2:0] BIT; +// reg [1:0] READ_STATE; +reg RX_DATA0; +reg RX_DATA1; + +// Even though we are checking the state machine using the E clock +// The clock can be up to 1/3 the speed of the bit clock +// Only the first three bits are checks and the state machine +// has three states that will compare +//always @ (negedge E or negedge RESET_N) +//begin +// if(~RESET_N) +// begin +// RX_READY <= 1'b0; +// READ_STATE <= 2'b00; +// end +// else +// case (READ_STATE) +// 2'b00: +// begin +// if(STATE[5:2] == 4'b1110) //Stop bit +// begin +// RX_READY <= 1'b1; +// READ_STATE <= 2'b01; +// end +// end +// 2'b01: +// begin +// if(REG_READ) +// begin +// RX_READY <= 1'b0; +// READ_STATE <= 2'b10; +// end +// end +// 2'b10: +// begin +// if(STATE[5:3] != 3'b111) +// READ_STATE <= 2'b00; +// end +// endcase +//end + + +always @ (posedge CLK or negedge RESET_N) +begin + if(!RESET_N) + begin + RX_BUFFER <= 8'h00; + STATE <= 6'b000000; +// OVERRUN <= 1'b0; + FRAME <= 1'b0; + BIT <= 3'b000; + RX_DATA0 <= 1'b1; + RX_DATA1 <= 1'b1; + READY <= 1'b0; + end + else + begin + if (BAUD_CLK) + begin + RX_DATA0 <= RX_DATA; + RX_DATA1 <= RX_DATA0; + case (STATE) + 6'b000000: // States 0-15 will be start bit + begin + BIT <= 3'b000; + if(~RX_DATA1) + STATE <= 6'b000001; + end + 6'b001111: // End of start bit, flag data not ready + begin // If data is not retrieved before this, then overrun + READY <= 1'b0; + STATE <= 6'b010000; + end + 6'b010111: // Each data bit is states 16-31, the middle is 23 + begin + RX_BUFFER[BIT] <= RX_DATA1; +// OVERRUN <= RX_READY; + STATE <= 6'b011000; + end + 6'b011111: // End of the data bits + begin + if(BIT == 3'b111) + begin + STATE <= 6'b100000; + end + else + begin + if((RX_WORD == 2'b01) && (BIT == 3'b110)) + begin + STATE <= 6'b100000; + end + else + begin + if((RX_WORD == 2'b10) && (BIT == 3'b101)) + begin + STATE <= 6'b100000; + end + else + begin + if((RX_WORD == 2'b11) && (BIT == 3'b100)) + begin + STATE <= 6'b100000; + end + else + begin + BIT <= BIT + 1'b1; + STATE <= 6'b010000; + end + end + end + end + end + 6'b100000: // First tick of Stop or Parity, Parity is 32 - 47 + begin + if(RX_PAR_DIS) + STATE <= 6'b110001; // get stop + else + STATE <= 6'b100001; // get parity + end + 6'b100111: // Middle of Parity is 39 + begin + PARITY_ERR <= ~RX_PARITY[1] & // Get but do not check Parity if 1 is set + (((RX_BUFFER[0] ^ RX_BUFFER[1]) + ^ (RX_BUFFER[2] ^ RX_BUFFER[3])) + + ^((RX_BUFFER[4] ^ RX_BUFFER[5]) + ^ (RX_BUFFER[6] ^ RX_BUFFER[7])) // clear bit #8 if only 7 bits + + ^ (~RX_PARITY[0] ^ RX_DATA1)); + STATE <= 6'b101000; +// 1 bit early for timing reasons + end + 6'b110111: // first stop bit is 32 or 48 then 49 - 63 + begin +// OVERRUN <= 1'b0; + FRAME <= !RX_DATA1; // if data != 1 then not stop bit + READY <= 1'b1; + STATE <= 6'b111000; + end +// In case of a framing error, wait until data is 1 then start over +// We skipped this check for 6 clock cycles so CPU speed is not a factor +// in the RX_READY state machine above + 6'b111000: + begin + if(RX_DATA1) + STATE <= 6'b000000; + end + default: + STATE <= STATE + 1'b1; + endcase + end + end +end +endmodule diff --git a/src/uart_6551/6551tx.v b/src/uart_6551/6551tx.v new file mode 100644 index 0000000..b0ad10a --- /dev/null +++ b/src/uart_6551/6551tx.v @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////////////////// +// Project Name: CoCo3FPGA Version 4.0 +// File Name: 6551tx.v +// +// CoCo3 in an FPGA +// +// Revision: 4.0 07/10/16 +//////////////////////////////////////////////////////////////////////////////// +// +// CPU section copyrighted by John Kent +// The FDC co-processor copyrighted Daniel Wallner. +// SDRAM Controller copyrighted by XESS Corp. +// +//////////////////////////////////////////////////////////////////////////////// +// +// Color Computer 3 compatible system on a chip +// +// Version : 4.0 +// +// Copyright (c) 2008 Gary Becker (gary_l_becker@yahoo.com) +// +// All rights reserved +// +// Redistribution and use in source and synthezised forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// Redistributions in synthesized form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Please report bugs to the author, but before you do so, please +// make sure that this is not a derivative work and that +// you have the latest version of this file. +// +// The latest version of this file can be found at: +// http://groups.yahoo.com/group/CoCo3FPGA +// +// File history : +// +// 1.0 Full Release +// 2.0 Partial Release +// 3.0 Full Release +// 3.0.0.1 Update to fix DoD interrupt issue +// 3.0.1.0 Update to fix 32/40 CoCO3 Text issue and add 2 Meg max memory +// 4.0.X.X Full Release +//////////////////////////////////////////////////////////////////////////////// +// Gary Becker +// gary_L_becker@yahoo.com +//////////////////////////////////////////////////////////////////////////////// + +module uart51_tx( +RESET_N, +CLK, +BAUD_CLK, +TX_DATA, +TX_START, +TX_DONE, +TX_STOP, +TX_WORD, +TX_PAR_DIS, +TX_PARITY, +CTS, +TX_BUFFER +); + +input RESET_N; +input CLK; +input BAUD_CLK; +output TX_DATA; +reg TX_DATA; +input TX_START; +output TX_DONE; +reg TX_DONE; +input TX_STOP; +input [1:0] TX_WORD; +input TX_PAR_DIS; +input [1:0] TX_PARITY; +input CTS; +input [7:0] TX_BUFFER; + +reg [6:0] STATE; +reg [2:0] BIT; +wire PARITY; +reg TX_START0; +reg TX_START1; + +assign PARITY = (~TX_PARITY[1] + + & ((TX_BUFFER[0] ^ TX_BUFFER[1]) + ^ (TX_BUFFER[2] ^ TX_BUFFER[3])) + + ^ (TX_BUFFER[4] + ^ (TX_BUFFER[5] & (TX_WORD != 2'b00))) + + ^ ((TX_BUFFER[6] & (TX_WORD[1] == 1'b1)) + ^ (TX_BUFFER[7] & (TX_WORD == 2'b11)))) // clear bit #8 if only 7 bits + + ^ ~TX_PARITY[0]; + +always @ (negedge CLK or negedge RESET_N) +begin + if(!RESET_N) + begin + STATE <= 7'b0000000; + TX_DATA <= 1'b1; + TX_DONE <= 1'b1; + BIT <= 3'b000; + TX_START0 <= 1'b0; + TX_START1 <= 1'b0; + end + else + begin + if (BAUD_CLK) + begin + TX_START0 <= TX_START; + TX_START1 <= TX_START0; + case (STATE) + 7'b0000000: + begin + BIT <= 3'b000; + TX_DATA <= 1'b1; + if(TX_START1 == 1'b1) + begin + TX_DONE <= 1'b0; + STATE <= 7'b0000001; + end + end + 7'b0000001: // Start bit + begin + TX_DATA <= 1'b0; + STATE <= 7'b0000010; + end + 7'b0010001: + begin + TX_DATA <= TX_BUFFER[BIT]; + STATE <= 7'b0010010; + end + 7'b0100000: + begin + BIT <= BIT + 1'b1; + if((TX_WORD == 2'b00) && (BIT != 3'b111)) + begin + STATE <= 7'b0010001; + end + else + begin + if((TX_WORD == 2'b01) && (BIT != 3'b110)) + begin + STATE <= 7'b0010001; + end + else + begin + if((TX_WORD == 2'b10) && (BIT != 3'b101)) + begin + STATE <= 7'b0010001; + end + else + begin + if((TX_WORD == 2'b11) && (BIT != 3'b100)) + begin + STATE <= 7'b0010001; + end + else + begin + if(!TX_PAR_DIS) + begin + STATE <= 7'b0100001; // do parity + end + else + begin + STATE <= 7'b0110001; // do stop + end + end + end + end + end + end +// Start parity bit + 7'b0100001: + begin + TX_DATA <= PARITY; + STATE <= 7'b0100010; + end +// start stop + 7'b0110001: + begin + TX_DONE <= 1'b1; + TX_DATA <= 1'b1; + STATE <= 7'b0110010; + end +// end of first stop bit-1 + 7'b0111111: + begin + if(!TX_STOP) + STATE <= 7'b1001111; // go check for CTS + else + STATE <= 7'b1000000; + end + 7'b1001111: + begin + if(!CTS) // this is not correct for a 6551 + begin + STATE <= 7'b0000000; + end + end + default: + STATE <= STATE + 1'b1; + endcase + end + end +end +endmodule diff --git a/src/uart_6551/BaudRate.vhd b/src/uart_6551/BaudRate.vhd new file mode 100644 index 0000000..7a649d6 --- /dev/null +++ b/src/uart_6551/BaudRate.vhd @@ -0,0 +1,61 @@ +-- Baud Rate Generator + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; +use ieee.std_logic_unsigned.all; + +ENTITY BaudRate IS + GENERIC ( + BAUD_RATE : integer := 230400 + ); + PORT ( + i_CLOCK : IN std_logic; + o_serialEn : OUT std_logic + ); +END BaudRate; + +ARCHITECTURE BaudRate_beh OF BaudRate IS + + signal w_serialCount : std_logic_vector(15 downto 0); + signal w_serialCount_d : std_logic_vector(15 downto 0); + +BEGIN + BAUD_230400: if (BAUD_RATE=230400) generate + begin + baud_div: process (w_serialCount_d, w_serialCount) + begin + w_serialCount_d <= w_serialCount + 767; -- 315Mhz + end process; + end generate BAUD_230400; + + BAUD_115200: if (BAUD_RATE=115200) generate + begin + baud_div: process (w_serialCount_d, w_serialCount) + begin + w_serialCount_d <= w_serialCount + 1887; -- 64Mhz + end process; + end generate BAUD_115200; + + BAUD_38400: if (BAUD_RATE=38400) generate + begin + baud_div: process (w_serialCount_d, w_serialCount) + begin + w_serialCount_d <= w_serialCount + 805; + end process; + end generate BAUD_38400; + + + process (i_CLOCK) + begin + if rising_edge(i_CLOCK) then + w_serialCount <= w_serialCount_d; + if w_serialCount(15) = '0' and w_serialCount_d(15) = '1' then + o_serialEn <= '1'; + else + o_serialEn <= '0'; + end if; + end if; + end process; + +END BaudRate_beh; diff --git a/src/uart_6551/uart_6551.v b/src/uart_6551/uart_6551.v new file mode 100644 index 0000000..d9fee07 --- /dev/null +++ b/src/uart_6551/uart_6551.v @@ -0,0 +1,508 @@ +//////////////////////////////////////////////////////////////////////////////// +// Project Name: CoCo3FPGA Version 4.0 +// File Name: uart_6551.v +// +// CoCo3 in an FPGA +// +// Revision: 4.0 07/10/16 +//////////////////////////////////////////////////////////////////////////////// +// +// CPU section copyrighted by John Kent +// The FDC co-processor copyrighted Daniel Wallner. +// SDRAM Controller copyrighted by XESS Corp. +// +//////////////////////////////////////////////////////////////////////////////// +// +// Color Computer 3 compatible system on a chip +// +// Version : 4.0 +// +// Copyright (c) 2008 Gary Becker (gary_l_becker@yahoo.com) +// +// All rights reserved +// +// Redistribution and use in source and synthezised forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// Redistributions in synthesized form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Please report bugs to the author, but before you do so, please +// make sure that this is not a derivative work and that +// you have the latest version of this file. +// +// The latest version of this file can be found at: +// http://groups.yahoo.com/group/CoCo3FPGA +// +// File history : +// +// 1.0 Full Release +// 2.0 Partial Release +// 3.0 Full Release +// 3.0.0.1 Update to fix DoD interrupt issue +// 3.0.1.0 Update to fix 32/40 CoCO3 Text issue and add 2 Meg max memory +// 4.0.X.X Full Release +//////////////////////////////////////////////////////////////////////////////// +// Gary Becker +// gary_L_becker@yahoo.com +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// MISTer Conversion by Stan Hodge and Alan Steremberg (& Gary Becker) +// stan.pda@gmail.com +// +// 1/11/22 Changed to be super synchronus +//////////////////////////////////////////////////////////////////////////////// + +module glb6551( +RESET_N, +CLK, +RX_CLK, +RX_CLK_IN, +XTAL_CLK_IN, +PH_2, +DI, +DO, +IRQ, +CS, +RW_N, +RS, +TXDATA_OUT, +RXDATA_IN, +RTS, +CTS, +DCD, +DTR, +DSR +); + +input RESET_N; +input CLK; +output RX_CLK; +input RX_CLK_IN; +input XTAL_CLK_IN; +input PH_2; +input [7:0] DI; +output [7:0] DO; +output IRQ; +input [1:0] CS; +input [1:0] RS; +input RW_N; +output TXDATA_OUT; +input RXDATA_IN; +output RTS; +input CTS; +input DCD; +output DTR; +input DSR; + +reg [7:0] TX_BUFFER; +reg [7:0] TX_REG; +wire [7:0] RX_BUFFER; +reg [7:0] RX_REG; +wire [7:0] STATUS_REG; +reg [7:0] CTL_REG; +reg [7:0] CMD_REG; +reg OVERRUN; +reg FRAME; +reg PARITY; + +wire TX_DONE; +reg TX_DONE0; +reg TX_DONE1; +reg TX_START; +reg TDRE; +reg RDRF; +reg [10:0] TX_CLK_DIV; +wire TX_CLK; +wire RX_CLK; +wire FRAME_BUF; +wire [1:0] WORD_SELECT; +wire RESET_X; +wire STOP; +wire PARITY_ERR; +wire PAR_DIS; +reg [7:0] LOOPBACK; +wire RX_DATA; +wire TX_DATA; +reg RESET_NX; +reg TX_CLK_REG_T; +reg TX_CLK_REG; +reg [1:0] READ_STATE; +wire GOT_DATA; +reg READY0; +reg READY1; +/* +Baud rate divisors +(for toggle of baud clock bit) +1 50 1152 +2 75 768 +3 110 524 -0.069396 +4 135 428 -0.311526 +5 150 384 +6 300 192 +7 600 96 +8 1200 48 +9 1800 32 +A 2400 24 +B 3600 16 +C 4800 12 +D 7200 8 +E 9600 6 +F 19200 3 +*/ + +//assign TX_CLK_REG = TX_CLK_REG_T & XTAL_CLK_IN; + +always @ (negedge CLK or negedge RESET_X) +begin + if(!RESET_X) + begin + TX_CLK_DIV <= 11'h000; + TX_CLK_REG_T <= 1'b0; + TX_CLK_REG <= 1'b0; + end + else + begin + TX_CLK_REG <= 1'b0; + if (XTAL_CLK_IN) + begin + case (TX_CLK_DIV) + 11'h000: + begin + TX_CLK_DIV <= 11'h001; + TX_CLK_REG_T <= ~TX_CLK_REG_T; + if (TX_CLK_REG_T) + TX_CLK_REG <= 1'b1; + end + 11'h002: + begin + if(CTL_REG[3:0] == 4'hF) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h003; + end + 11'h005: + begin + if(CTL_REG[3:0] == 4'hE) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h006; + end + 11'h007: + begin + if(CTL_REG[3:0] == 4'hD) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h008; + end + 11'h00B: + begin + if(CTL_REG[3:0] == 4'hC) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h00C; + end + 11'h00F: + begin + if(CTL_REG[3:0] == 4'hB) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h010; + end + 11'h017: + begin + if(CTL_REG[3:0] == 4'hA) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h018; + end + 11'h01F: + begin + if(CTL_REG[3:0] == 4'h9) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h020; + end + 11'h02F: + begin + if(CTL_REG[3:0] == 4'h8) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h030; + end + 11'h05F: + begin + if(CTL_REG[3:0] == 4'h7) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h060; + end + 11'h0BF: + begin + if(CTL_REG[3:0] == 4'h6) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h0C0; + end + 11'h17F: + begin + if(CTL_REG[3:0] == 4'h5) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h180; + end + 11'h1AB: + begin + if(CTL_REG[3:0] == 4'h4) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h1AC; + end + 11'h20B: + begin + if(CTL_REG[3:0] == 4'h3) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h20C; + end + 11'h2FF: + begin + if(CTL_REG[3:0] == 4'h2) + TX_CLK_DIV <= 11'h000; + else + TX_CLK_DIV <= 11'h300; + end + 11'h47F: + begin + TX_CLK_DIV <= 11'h000; + end + default: + begin + TX_CLK_DIV <= TX_CLK_DIV +1'b1; + end + endcase + end + end +end + +assign TX_CLK = (CTL_REG[3:0] == 4'h0) ? XTAL_CLK_IN: + TX_CLK_REG; + +assign RX_CLK = (CTL_REG[4] == 1'b0) ? RX_CLK_IN: + TX_CLK; + +assign RESET_X = RESET_NX ? 1'b0: + RESET_N; + +always @ (negedge CLK) +begin + if (TX_CLK) + LOOPBACK <= {LOOPBACK[6:0], TX_DATA}; //half bit time FIFO +end + +assign RX_DATA = (CMD_REG[4:2] == 3'b100) ? LOOPBACK[7]: + RXDATA_IN; + +assign TXDATA_OUT = (CMD_REG[4:2] == 3'b100) ? 1'b1: + TX_DATA; + +assign STATUS_REG = {!IRQ, DSR, DCD, TDRE, RDRF, OVERRUN, FRAME, PARITY}; + +assign DO = (RS == 2'b00) ? RX_REG: + (RS == 2'b01) ? STATUS_REG: + (RS == 2'b10) ? CMD_REG: + CTL_REG; + +assign IRQ = ({CMD_REG[1:0], RDRF} == 3'b011) ? 1'b0: + ({CMD_REG[3:2], CMD_REG[0], TDRE} == 4'b0111) ? 1'b0: + 1'b1; + +assign RTS = (CMD_REG[3:2] == 2'b00); +assign DTR = ~CMD_REG[0]; + +assign STOP = (CTL_REG[7] == 1'b0) ? 1'b0: // Stop = 1 + ({CTL_REG[7:5], CMD_REG[5]} == 4'b1001) ? 1'b0: // Stop >1 but 8bit word and parity + 1'b1; // Stop > 1 + +assign PAR_DIS = ~CMD_REG[5]; +assign WORD_SELECT = CTL_REG[6:5]; + +always @ (negedge CLK or negedge RESET_N) +begin + if(!RESET_N) + RESET_NX <= 1'b1; + else + begin + if (PH_2) + if({RW_N, CS, RS} == 5'b00101) // Software RESET + RESET_NX <= 1'b1; + else + RESET_NX <= 1'b0; + end +end + +always @ (negedge CLK or negedge RESET_X) +begin + if(!RESET_X) + begin + RDRF <= 1'b0; + READ_STATE <= 2'b00; + TX_BUFFER <= 8'h00; + CTL_REG <= 8'h00; +// Commador data sheet says reset value is 02 +// but Apple will not work unless it is 00 + CMD_REG <= 8'h00; + TDRE <= 1'b1; + TX_START <= 1'b0; + RX_REG <= 8'h00; + OVERRUN <= 1'b0; + FRAME <= 1'b0; + PARITY <= 1'b0; + TX_DONE1 <= 1'b1; + TX_DONE0 <= 1'b1; + READY0 <= 1'b0; + READY1 <= 1'b0; + end + else + begin + if (PH_2) + begin + TX_DONE1 <= TX_DONE0; // sync TX_DONE with E clock for metastability? + TX_DONE0 <= TX_DONE; + READY1 <= READY0; + READY0 <= GOT_DATA; + case (READ_STATE) + 2'b00: + begin + if(READY1) //Stop bit + begin + RDRF <= 1'b1; + READ_STATE <= 2'b01; + RX_REG <= RX_BUFFER; + OVERRUN <= 1'b0; + PARITY <= (PARITY_ERR & !PAR_DIS); + FRAME <= FRAME_BUF; + end + end + 2'b01: + begin + if({RW_N, CS, RS} == 5'b10100) + begin + RDRF <= 1'b0; + READ_STATE <= 2'b10; + PARITY <= 1'b0; + OVERRUN <= 1'b0; + FRAME <= 1'b0; + end + else + begin + if(~READY1) + READ_STATE <= 2'b11; + end + end + 2'b10: + begin + if(~READY1) + READ_STATE <= 2'b00; + end + 2'b11: + begin + if({RW_N, CS, RS} == 5'b10100) + begin + RDRF <= 1'b0; + READ_STATE <= 2'b00; + PARITY <= 1'b0; + OVERRUN <= 1'b0; + FRAME <= 1'b0; + end + else + begin + if(READY1) + begin + RDRF <= 1'b1; + READ_STATE <= 2'b01; + OVERRUN <= 1'b1; + PARITY <= (PARITY_ERR & !PAR_DIS); + FRAME <= FRAME_BUF; + RX_REG <= RX_BUFFER; + end + end + end + endcase + + if({RW_N, CS, RS} == 5'b00100) // Write TX data register + TX_REG <= DI; + + if({RW_N, CS, RS} == 5'b00110) // Write CMD register + CMD_REG <= DI; + + if({RW_N, CS, RS} == 5'b00111) // Write CTL register + CTL_REG <= DI; + + if(~TDRE & TX_DONE1 & ~TX_START & ~(CS == 2'b01)) + begin + TX_BUFFER <= TX_REG; + TDRE <= 1'b1; + TX_START <= 1'b1; + end + else + begin + if({RW_N, CS, RS} == 5'b00100) // Write TX data register + TDRE <= 1'b0; + if(~TX_DONE1) + TX_START <= 1'b0; + end + end + end +end + +uart51_tx tx( +.RESET_N(RESET_X), +.CLK(CLK), +.BAUD_CLK(TX_CLK), +.TX_DATA(TX_DATA), +.TX_START(TX_START), +.TX_DONE(TX_DONE), +.TX_STOP(STOP), +.TX_WORD(WORD_SELECT), +.TX_PAR_DIS(PAR_DIS), +.TX_PARITY(CMD_REG[7:6]), +.CTS(CTS), +.TX_BUFFER(TX_BUFFER) +); + +uart51_rx rx( +.RESET_N(RESET_X), +.CLK(CLK), +.BAUD_CLK(RX_CLK), +.RX_DATA(RX_DATA), +.RX_BUFFER(RX_BUFFER), +.RX_WORD(WORD_SELECT), +.RX_PAR_DIS(PAR_DIS), +.RX_PARITY(CMD_REG[7:6]), +.PARITY_ERR(PARITY_ERR), +.FRAME(FRAME_BUF), +.READY(GOT_DATA) +); + +endmodule diff --git a/tang_mega_138k_c64.gprj b/tang_mega_138k_c64.gprj index 289da20..6b0adb2 100644 --- a/tang_mega_138k_c64.gprj +++ b/tang_mega_138k_c64.gprj @@ -73,5 +73,9 @@ + + + + diff --git a/tang_nano_20k_c64.gprj b/tang_nano_20k_c64.gprj index 6b4cc0c..3e4a0ac 100644 --- a/tang_nano_20k_c64.gprj +++ b/tang_nano_20k_c64.gprj @@ -44,6 +44,9 @@ + + + @@ -67,6 +70,7 @@ + diff --git a/tang_primer_25k_c64.gprj b/tang_primer_25k_c64.gprj index 1513f1e..79a96d9 100644 --- a/tang_primer_25k_c64.gprj +++ b/tang_primer_25k_c64.gprj @@ -42,6 +42,9 @@ + + + @@ -68,6 +71,7 @@ +