diff --git a/hw/fpga/addr_decode.sv b/hw/fpga/addr_decode.sv index 1b4dd5e..83f3c57 100644 --- a/hw/fpga/addr_decode.sv +++ b/hw/fpga/addr_decode.sv @@ -2,11 +2,13 @@ module addr_decode( input logic [15:0] addr, output logic ram_cs, output logic rom_cs, - output logic hex_cs + output logic hex_cs, + output logic uart_cs ); assign rom_cs = addr[15]; assign ram_cs = ~addr[15] && addr < 16'h7ff0; assign hex_cs = addr >= 16'h7ff0 && addr < 16'h7ff4; +assign uart_cs = addr >= 16'h7ff4 && addr < 16'h7ff6; endmodule diff --git a/hw/fpga/hvl/cs_testbench.sv b/hw/fpga/hvl/cs_testbench.sv index b552abb..b764c0f 100644 --- a/hw/fpga/hvl/cs_testbench.sv +++ b/hw/fpga/hvl/cs_testbench.sv @@ -8,8 +8,9 @@ logic [15:0] addr; logic ram_cs; logic rom_cs; logic hex_cs; +logic uart_cs; -int cs_count = ram_cs + rom_cs + hex_cs; +int cs_count = ram_cs + rom_cs + hex_cs + uart_cs; addr_decode dut(.*); @@ -29,7 +30,12 @@ initial begin : TEST_VECTORS if (i >= 16'h7ff0 && i < 16'h7ff4) begin assert(hex_cs == '1) else - $error("Bad CS! addr=%4x should have io_cs!", addr); + $error("Bad CS! addr=%4x should have hex_cs!", addr); + end + if (i >= 16'h7ff4 && i < 16'6) begin + assert(uart_cs == '1) + else + $error("Bad CS! addr=%4x should have uart_cs!", addr); end if (i >= 2**15) begin assert(rom_cs == '1) diff --git a/hw/fpga/hvl/uart_testbench.sv b/hw/fpga/hvl/uart_testbench.sv new file mode 100644 index 0000000..8e1a05d --- /dev/null +++ b/hw/fpga/hvl/uart_testbench.sv @@ -0,0 +1,60 @@ +module testbench(); + +timeunit 10ns; + +timeprecision 1ns; + +logic clk_50, clk, rst, cs; +logic [1:0] addr; +logic [7:0] data_in, data_out; +logic rw; +logic RXD, TXD; + +logic [7:0] status; + +uart dut(.*); + +always #1 clk_50 = clk_50 === 1'b0; +always #100 clk = clk === 1'b0; + +task write(logic [7:0] data); + @(negedge clk); + cs <= '1; + addr <= '0; + data_in <= data; + rw <= '0; + + @(negedge clk); + cs <= '0; + addr <= '0; + data_in <= 8'hxx; + rw <= '1; + + do begin + @(negedge clk); + cs <= '1; + addr <= 1'b1; + rw <= '1; + @(negedge clk); + end while (data_out != 8'h0); +endtask + +task puts(string s, int n); + for (int i = 0; i < n; i++) + write(s[i]); +endtask + +initial begin + rst <= '1; + repeat(5) @(posedge clk); + rst <= '0; + rw <= '1; + cs <= '0; + status <= '0; + + puts("Hello, world!\n", 14); + + $finish(); +end + +endmodule diff --git a/hw/fpga/simulation/modelsim/.gitignore b/hw/fpga/simulation/modelsim/.gitignore index f397c9b..38bbc77 100644 --- a/hw/fpga/simulation/modelsim/.gitignore +++ b/hw/fpga/simulation/modelsim/.gitignore @@ -8,7 +8,7 @@ *.dat *.dbs *.psm -*.bak +*.bak* *.cmp *.jpg *.html @@ -20,7 +20,7 @@ wlf* *.vstf *.ucdb cov*/ -transcript* +*transcript* sc_dpiheader.h vsim.dbg *.sft diff --git a/hw/fpga/simulation/modelsim/super6502_run_msim_rtl_verilog.do b/hw/fpga/simulation/modelsim/super6502_run_msim_rtl_verilog.do new file mode 100644 index 0000000..f0f1614 --- /dev/null +++ b/hw/fpga/simulation/modelsim/super6502_run_msim_rtl_verilog.do @@ -0,0 +1,17 @@ +transcript on +if {[file exists rtl_work]} { + vdel -lib rtl_work -all +} +vlib rtl_work +vmap work rtl_work + +vlog -vlog01compat -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/ram.v} +vlog -vlog01compat -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/rom.v} +vlog -vlog01compat -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/cpu_clk.v} +vlog -vlog01compat -work work +incdir+/home/byron/Projects/super6502/hw/fpga/db {/home/byron/Projects/super6502/hw/fpga/db/cpu_clk_altpll.v} +vlog -sv -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/uart.sv} +vlog -sv -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/addr_decode.sv} +vlog -sv -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/super6502.sv} +vlog -sv -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/HexDriver.sv} +vlog -sv -work work +incdir+/home/byron/Projects/super6502/hw/fpga {/home/byron/Projects/super6502/hw/fpga/SevenSeg.sv} + diff --git a/hw/fpga/simulation/modelsim/uart.do b/hw/fpga/simulation/modelsim/uart.do new file mode 100644 index 0000000..dde4bcd --- /dev/null +++ b/hw/fpga/simulation/modelsim/uart.do @@ -0,0 +1,17 @@ +transcript on +if {[file exists rtl_work]} { + vdel -lib rtl_work -all +} +vlib rtl_work +vmap work rtl_work + +vlog -sv -work work {../../uart.sv} +vlog -sv -work work {../../hvl/uart_testbench.sv} + +vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L stratixv_ver -L stratixv_hssi_ver -L stratixv_pcie_hip_ver -L rtl_work -L work -voptargs="+acc" testbench + +add wave -group {dut} -radix hexadecimal sim:/testbench/dut/* + +onfinish stop +run -all + diff --git a/hw/fpga/super6502.qsf b/hw/fpga/super6502.qsf index 7c3a514..496716f 100644 --- a/hw/fpga/super6502.qsf +++ b/hw/fpga/super6502.qsf @@ -140,15 +140,6 @@ set_location_assignment PIN_C16 -to HEX0[3] set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" -set_global_assignment -name SYSTEMVERILOG_FILE addr_decode.sv -set_global_assignment -name SYSTEMVERILOG_FILE bb_spi_controller.sv -set_global_assignment -name SYSTEMVERILOG_FILE super6502.sv -set_global_assignment -name QIP_FILE ram.qip -set_global_assignment -name SDC_FILE super6502.sdc -set_global_assignment -name QIP_FILE rom.qip -set_global_assignment -name SYSTEMVERILOG_FILE HexDriver.sv -set_global_assignment -name SYSTEMVERILOG_FILE SevenSeg.sv -set_global_assignment -name QIP_FILE cpu_clk.qip set_location_assignment PIN_B8 -to rst_n set_location_assignment PIN_P11 -to clk_50 set_global_assignment -name ENABLE_OCT_DONE OFF @@ -160,46 +151,45 @@ set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_vpb -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_addr[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_be -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_data[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_irqb -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_led -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_mlb -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_nmib -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_phi2 -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_rdy -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_resb -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_rwb -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_sob -set_instance_assignment -name IO_STANDARD "2.5 V" -to cpu_sync -set_instance_assignment -name IO_STANDARD "2.5 V" -to clk_50 +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_vpb +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[15] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[14] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[13] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[12] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[11] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[10] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[9] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[8] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[7] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_addr[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_be +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[7] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_data[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_irqb +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_led +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_mlb +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_nmib +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_phi2 +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_rdy +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_resb +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_rwb +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_sob +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_sync +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to clk_50 set_global_assignment -name ENABLE_SIGNALTAP OFF set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp1.stp -set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp set_location_assignment PIN_F20 -to HEX4[6] set_location_assignment PIN_F19 -to HEX4[5] set_location_assignment PIN_H19 -to HEX4[4] @@ -214,4 +204,83 @@ set_location_assignment PIN_N19 -to HEX5[5] set_location_assignment PIN_N20 -to HEX5[6] set_location_assignment PIN_F18 -to HEX4[0] set_location_assignment PIN_E20 -to HEX4[1] +set_location_assignment PIN_AB5 -to UART_RXD +set_location_assignment PIN_AB6 -to UART_TXD +set_global_assignment -name SYSTEMVERILOG_FILE uart.sv +set_global_assignment -name SYSTEMVERILOG_FILE addr_decode.sv +set_global_assignment -name SYSTEMVERILOG_FILE bb_spi_controller.sv +set_global_assignment -name SYSTEMVERILOG_FILE super6502.sv +set_global_assignment -name QIP_FILE ram.qip +set_global_assignment -name SDC_FILE super6502.sdc +set_global_assignment -name QIP_FILE rom.qip +set_global_assignment -name SYSTEMVERILOG_FILE HexDriver.sv +set_global_assignment -name SYSTEMVERILOG_FILE SevenSeg.sv +set_global_assignment -name QIP_FILE cpu_clk.qip +set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RXD +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_TXD +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX1[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX2[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX3[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX4[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX5[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to rst_n +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[7] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[8] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[9] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to Run +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[7] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[8] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[9] set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/hw/fpga/super6502.sv b/hw/fpga/super6502.sv index 1b61440..54bcf61 100644 --- a/hw/fpga/super6502.sv +++ b/hw/fpga/super6502.sv @@ -20,7 +20,10 @@ module super6502( output logic cpu_be, output logic cpu_nmib, - output logic [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5 + output logic [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, + + input logic UART_RXD, + output logic UART_TXD ); logic rst; @@ -37,10 +40,12 @@ assign cpu_data = cpu_rwb ? cpu_data_out : 'z; logic [7:0] rom_data_out; logic [7:0] ram_data_out; +logic [7:0] uart_data_out; logic ram_cs; logic rom_cs; logic hex_cs; +logic uart_cs; cpu_clk cpu_clk( .inclk0(clk_50), @@ -62,7 +67,8 @@ addr_decode decode( .addr(cpu_addr), .ram_cs(ram_cs), .rom_cs(rom_cs), - .hex_cs(hex_cs) + .hex_cs(hex_cs), + .uart_cs(uart_cs) ); @@ -71,6 +77,8 @@ always_comb begin cpu_data_out = ram_data_out; else if (rom_cs) cpu_data_out = rom_data_out; + else if (uart_cs) + cpu_data_out = uart_data_out; else cpu_data_out = 'x; end @@ -102,7 +110,19 @@ SevenSeg segs( .addr(cpu_addr[1:0]), .HEX0(HEX0), .HEX1(HEX1), .HEX2(HEX2), .HEX3(HEX3), .HEX4(HEX4), .HEX5(HEX5) ); - + +uart uart( + .clk_50(clk_50), + .clk(clk), + .rst(rst), + .rw(cpu_rwb), + .data_in(cpu_data_in), + .cs(uart_cs), + .addr(cpu_addr[1:0]), + .RXD(UART_RXD), + .TXD(UART_TXD), + .data_out(uart_data_out) +); endmodule \ No newline at end of file diff --git a/hw/fpga/uart.sv b/hw/fpga/uart.sv new file mode 100644 index 0000000..9c86ffb --- /dev/null +++ b/hw/fpga/uart.sv @@ -0,0 +1,151 @@ +module uart( + input clk_50, + input clk, + input rst, + + input cs, + input rw, + input [7:0] data_in, + input [1:0] addr, + + input RXD, + + output logic TXD, + + output logic [7:0] data_out +); + +//Handle reading and writing registers + +logic [7:0] tx_buf; +logic [7:0] rx_buf; +logic [7:0] status; + +logic tx_flag; + +logic tx_flag_set; +logic tx_flag_clear; + +assign status[0] = tx_flag | tx_flag_clear; + +always_ff @(posedge clk) begin + if (rst) begin + tx_flag_set <= '0; + tx_buf <= '0; + rx_buf <= '0; + status[7:1] <= '0; + end + + if (cs) begin + if (~rw) begin + if (addr == 0) + tx_buf <= data_in; + end else begin + if (addr == 0) + data_out <= rx_buf; + if (addr == 1) + data_out <= status; + end + end + + if (~rw & cs && addr == 0) + tx_flag_set <= '1; + else + tx_flag_set <= '0; +end + +// state controller +typedef enum bit [2:0] {START, DATA, PARITY, STOP, IDLE} macro_t; +struct packed { + macro_t macro; + logic [3:0] count; +} state, next_state; +localparam logic [3:0] maxcount = 4'h7; + +// baud rate: 9600 +localparam baud = 9600; +localparam count = (50000000/baud)-1; +logic [14:0] clkdiv; + +always_ff @(posedge clk_50) begin + if (rst) begin + clkdiv <= 0; + state.macro <= IDLE; + state.count <= 3'b0; + tx_flag <= '0; + end else begin + if (tx_flag_set) + tx_flag <= '1; + else if (tx_flag_clear) + tx_flag <= '0; + + if (clkdiv == count) begin + clkdiv <= 0; + state <= next_state; + end else begin + clkdiv <= clkdiv + 15'b1; + end + end +end + +always_comb begin + next_state = state; + + unique case (state.macro) + START: begin + next_state.macro = DATA; + next_state.count = 3'b0; + end + DATA: begin + if (state.count == maxcount) begin + next_state.macro = STOP; // or PARITY + next_state.count = 3'b0; + end else begin + next_state.count = state.count + 3'b1; + next_state.macro = DATA; + end + end + PARITY: begin + end + STOP: begin + next_state.macro = IDLE; + next_state.count = '0; + end + IDLE: begin + if (tx_flag) + next_state.macro = START; + else + next_state.macro = IDLE; + end + + default:; + endcase +end + +always_comb begin + TXD = '1; + tx_flag_clear = '0; + + unique case (state.macro) + START: begin + TXD = '0; + end + DATA: begin + TXD = tx_buf[state.count]; + end + PARITY: begin + + end + STOP: begin + tx_flag_clear = '1; + TXD = '1; + end + IDLE: begin + TXD = '1; + end + + default:; + endcase +end + +endmodule diff --git a/sw/io.inc65 b/sw/io.inc65 index 4bf4736..9192cff 100644 --- a/sw/io.inc65 +++ b/sw/io.inc65 @@ -1 +1,6 @@ -SEVEN_SEG = $7ff0 +SEVEN_SEG = $7ff0 + +UART = $7ff4 +UART_TXB = UART +UART_RXB = UART +UART_STATUS = UART + 1 diff --git a/sw/main.c b/sw/main.c index c7a5217..b72826f 100644 --- a/sw/main.c +++ b/sw/main.c @@ -1,10 +1,24 @@ #include #include "sevenseg.h" +#include "uart.h" + +void puts(const char* s) +{ + while (*s) { + uart_txb_block(*s); + if (*s == '\n') + uart_txb_block('\r'); + + s++; + } +} int main() { hex_enable(0x3f); hex_set_24(0xabcdef); + + puts("Hello, World!\n"); while(1); return 0; } diff --git a/sw/tests/test_main.c b/sw/tests/test_main.c index 2f32592..50e3d85 100644 --- a/sw/tests/test_main.c +++ b/sw/tests/test_main.c @@ -1,6 +1,7 @@ #include #include "sevenseg.h" +#include "uart.h" int main(void) { @@ -56,6 +57,23 @@ int main(void) } printf("Done!\n\n"); + printf("Testing uart_txb_block...\n"); + *(uint8_t*)0x7ff5 = 0; + uart_txb_block(0xa5); + if (*(uint8_t*)0x7ff4 != 0xa5) { + printf("Incorrect value!\n", i); + retval++; + } + printf("Done!\n\n"); + + printf("Testing uart_status...\n"); + *(uint8_t*)0x7ff5 = 0xa5; + if (uart_status() != 0xa5) { + printf("Incorrect value!\n", i); + retval++; + } + printf("Done!\n\n"); + return retval != 0; } \ No newline at end of file diff --git a/sw/uart.h b/sw/uart.h new file mode 100644 index 0000000..c96b48c --- /dev/null +++ b/sw/uart.h @@ -0,0 +1,11 @@ +#ifndef _UART_H +#define _UART_H + +#include + +void uart_txb(uint8_t val); +void uart_txb_block(uint8_t val); + +uint8_t uart_status(); + +#endif \ No newline at end of file diff --git a/sw/uart.s b/sw/uart.s new file mode 100644 index 0000000..80b5563 --- /dev/null +++ b/sw/uart.s @@ -0,0 +1,29 @@ +.include "io.inc65" + +.importzp sp, sreg + +.export _uart_txb +.export _uart_txb_block +.export _uart_status + +.autoimport on + +.code + +; @in A: byte to transmit +; Transmits a byte over the UART +_uart_txb: + sta UART_TXB ; Just write value, don't wait + rts + +_uart_txb_block: + sta UART_TXB ; Write value +@1: lda UART_STATUS ; Wait for status[0] to be 0 + bit #$01 + bne @1 + rts + +_uart_status: + lda UART_STATUS + ldx #$00 + rts