diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 16e5ba1119333bfa0d6adfd4197a7fc01ccbc7a5..25079d45b53d488132212ed36af9e488b929df20 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,3 +38,10 @@ test-sw: script: - cd sw/ - make test + +test_mm: + stage: test + image: bslathi19/modelsim_18.1:lite + script: + - cd hw/fpga/simulation/modelsim/ + - vsim -do "do mm_testbench.do" diff --git a/hw/fpga/addr_decode.sv b/hw/fpga/addr_decode.sv index 01c32cbd43980d774444e7368a6cfb319051c58c..a145fccdfad9058502c918a661d2fce8d2423b4a 100644 --- a/hw/fpga/addr_decode.sv +++ b/hw/fpga/addr_decode.sv @@ -1,18 +1,22 @@ module addr_decode( - input logic [15:0] addr, + input logic [23:0] addr, output logic sdram_cs, output logic rom_cs, output logic hex_cs, output logic uart_cs, output logic irq_cs, - output logic board_io_cs + output logic board_io_cs, + output logic mm_cs1, + output logic mm_cs2 ); -assign rom_cs = addr >= 16'h8000; -assign sdram_cs = addr < 16'h7ff0; -assign hex_cs = addr >= 16'h7ff0 && addr < 16'h7ff4; -assign uart_cs = addr >= 16'h7ff4 && addr < 16'h7ff6; -assign board_io_cs = addr == 16'h7ff6; -assign irq_cs = addr == 16'h7fff; +assign rom_cs = addr >= 24'h008000 && addr < 24'h010000; +assign sdram_cs = addr < 24'h007fe0 || addr >= 24'h010000; +assign mm_cs1 = addr >= 24'h007fe0 && addr < 24'h007ff0; +assign hex_cs = addr >= 24'h007ff0 && addr < 24'h007ff4; +assign uart_cs = addr >= 24'h007ff4 && addr < 24'h007ff6; +assign board_io_cs = addr == 24'h007ff6; +assign mm_cs2 = addr == 24'h007ff7; +assign irq_cs = addr == 24'h007fff; endmodule diff --git a/hw/fpga/hvl/cs_testbench.sv b/hw/fpga/hvl/cs_testbench.sv index 7624080d597921df00d4bc96bba067742e507ea3..a6e10729320faba518e995c17951c0caa59f4814 100644 --- a/hw/fpga/hvl/cs_testbench.sv +++ b/hw/fpga/hvl/cs_testbench.sv @@ -4,27 +4,29 @@ timeunit 10ns; timeprecision 1ns; -logic [15:0] addr; +logic [23:0] addr; logic sdram_cs; logic rom_cs; logic hex_cs; logic board_io_cs; logic uart_cs; logic irq_cs; +logic mm_cs2; +logic mm_cs1; -int cs_count = sdram_cs + rom_cs + hex_cs + uart_cs + board_io_cs; +int cs_count = sdram_cs + rom_cs + hex_cs + uart_cs + board_io_cs + mm_cs2 + mm_cs1; addr_decode dut(.*); initial begin : TEST_VECTORS - for (int i = 0; i < 2**16; i++) begin + for (int i = 0; i < 2**24; i++) begin addr <= i; #1 assert(cs_count < 2) else $error("Multiple chip selects present!"); - if (i < 16'h7ff0) begin + if (i < 16'h7fe0 || i >= 24'h010000) begin assert(sdram_cs == '1) else $error("Bad CS! addr=%4x should have sdram_cs!", addr); @@ -44,12 +46,22 @@ initial begin : TEST_VECTORS else $error("Bad CS! addr=%4x should have board_io_cs!", addr); end + if (i == 16'h7ff7) begin + assert(mm_cs2 == '1) + else + $error("Bad CS! addr=%4x should have mm_cs2!", addr); + end + if (i >= 16'h7fe0 && i < 16'h7ff0) begin + assert(mm_cs1 == '1) + else + $error("Bad CS! addr=%4x should have mm_cs1!", addr); + end if (i == 16'h7fff) begin assert(irq_cs == '1) else $error("Bad CS! addr=%4x should have irq_cs!", addr); end - if (i >= 2**15) begin + if (i >= 2**15 && i < 24'h010000) begin assert(rom_cs == '1) else $error("Bad CS! addr=%4x should have rom_cs!", addr); diff --git a/hw/fpga/hvl/mm_testbench.sv b/hw/fpga/hvl/mm_testbench.sv new file mode 100644 index 0000000000000000000000000000000000000000..b4983376ee4d60728139273fb03d7d1462f41597 --- /dev/null +++ b/hw/fpga/hvl/mm_testbench.sv @@ -0,0 +1,85 @@ +module testbench(); + +timeunit 10ns; + +timeprecision 1ns; + +logic clk_50, clk, cs; +logic rw, MM_cs; +logic rst; +logic [3:0] RS, MA; +logic [7:0] data_in; +logic [7:0] data_out; + +logic [11:0] MO; + +logic [11:0] _data_in; +assign _data_in = {4'h0, data_in}; + +logic [11:0] _data_out; +assign data_out = _data_out[7:0]; + +logic [15:0] cpu_addr; +logic [23:0] mm_address; +assign MA = cpu_addr[15:12]; +assign mm_address = {MO, cpu_addr[11:0]}; + +memory_mapper dut( + .data_in(_data_in), + .data_out(_data_out), + .* +); + +always #1 clk_50 = clk_50 === 1'b0; +always #100 clk = clk === 1'b0; + +task write_reg(logic [3:0] addr, logic [7:0] data); + @(negedge clk); + cs <= '1; + RS <= addr; + data_in <= data; + rw <= '0; + @(posedge clk); + cs <= '0; + rw <= '1; + @(negedge clk); +endtask + +task enable(logic [7:0] data); + @(negedge clk); + MM_cs <= '1; + rw <= '0; + data_in <= data; + @(posedge clk); + rw <= '1; + MM_cs <= '0; + @(negedge clk); +endtask + +initial begin + rst <= '1; + repeat(5) @(posedge clk); + rst <= '0; + + cpu_addr <= 16'h0abc; + write_reg(4'h0, 8'hcc); + $display("Address: %x", mm_address); + assert(mm_address == 24'h000abc) else begin + $error("Bad address before enable!"); + end + + enable(1); + $display("Address: %x", mm_address); + assert(mm_address == 24'h0ccabc) else begin + $error("Bad address after enable!"); + end + + enable(0); + $display("Address: %x", mm_address); + assert(mm_address == 24'h000abc) else begin + $error("Bad address after enable!"); + end + $finish(); +end + +endmodule diff --git a/hw/fpga/memory_mapper.sv b/hw/fpga/memory_mapper.sv new file mode 100644 index 0000000000000000000000000000000000000000..00858d76a371391226592b02d5245ff66110d522 --- /dev/null +++ b/hw/fpga/memory_mapper.sv @@ -0,0 +1,58 @@ +/* + * This is based off of the 74LS610, but is not identical. + Some of the inputs are flipped so that they are all active high, + and some outputs are reordered. + Notably, when MM is low, MA is present on MO0-MO4, not 8 to 11. + */ + +module memory_mapper( + input clk, + input rst, + + input rw, + input cs, + + input MM_cs, + + input [3:0] RS, + + input [3:0] MA, + + input logic [11:0] data_in, + output logic [11:0] data_out, + + output logic [11:0] MO +); + +logic [11:0] RAM [16]; + +logic MM; + + +always_ff @(posedge clk) begin + if (rst) begin + MM <= '0; + end else begin + if (MM_cs & ~rw) begin // can't read MM but do you really need too? + MM = |data_in; + end + + if (cs & ~rw) begin // write to registers + RAM[RS] <= data_in; + end else if (cs & rw) begin // read registers + data_out <= RAM[RS]; + end + end +end + + +always_comb begin + if (MM) begin // normal mode + MO = RAM[MA]; + end else begin // passthrough mode + MO = {8'b0, MA}; + end +end + +endmodule + diff --git a/hw/fpga/sdram.sv b/hw/fpga/sdram.sv index 522596f38f1d64e34a93e28b51e9f88db3701eaf..6b28f405b508ac588c0f3cc805dc75ec962c7ab3 100644 --- a/hw/fpga/sdram.sv +++ b/hw/fpga/sdram.sv @@ -2,7 +2,7 @@ module sdram( input rst, input clk_50, input cpu_clk, - input [15:0] addr, + input [23:0] addr, input sdram_cs, input rwb, input [7:0] data_in, @@ -84,4 +84,4 @@ sdram_platform u0 ( .sdram_wire_we_n(DRAM_WE_N) //.we_n ); -endmodule \ No newline at end of file +endmodule diff --git a/hw/fpga/simulation/modelsim/mm_testbench.do b/hw/fpga/simulation/modelsim/mm_testbench.do new file mode 100644 index 0000000000000000000000000000000000000000..9cdf64941120065d0e29567a71f639d8600c51e4 --- /dev/null +++ b/hw/fpga/simulation/modelsim/mm_testbench.do @@ -0,0 +1,24 @@ +transcript on +if {[file exists rtl_work]} { + vdel -lib rtl_work -all +} +vlib rtl_work +vmap work rtl_work + +vlog -sv -work work {../../memory_mapper.sv} +vlog -sv -work work {../../hvl/mm_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 + +if { [coverage attribute -name TESTSTATUS -concise] == "1"} { + echo Warning + quit -f -code 0 +} + +quit -code [coverage attribute -name TESTSTATUS -concise] + diff --git a/hw/fpga/super6502.qsf b/hw/fpga/super6502.qsf index 09cd0fceba0fad1eb02a17d61495f85baabbe429..fdb728991730b0d8498d3348b73f00b230641c90 100644 --- a/hw/fpga/super6502.qsf +++ b/hw/fpga/super6502.qsf @@ -350,6 +350,7 @@ set_location_assignment PIN_V22 -to DRAM_LDQM set_location_assignment PIN_U22 -to DRAM_RAS_N set_location_assignment PIN_J21 -to DRAM_UDQM set_location_assignment PIN_V20 -to DRAM_WE_N +set_global_assignment -name SYSTEMVERILOG_FILE memory_mapper.sv set_global_assignment -name SYSTEMVERILOG_FILE board_io.sv set_global_assignment -name SYSTEMVERILOG_FILE sdram.sv set_global_assignment -name QIP_FILE sdram_platform/synthesis/sdram_platform.qip diff --git a/hw/fpga/super6502.sv b/hw/fpga/super6502.sv index 896a50191a9ecdc29443f565fc41475dcc0b116b..fdfdafa1ba66304c831739e971b75a3e0eb6591f 100644 --- a/hw/fpga/super6502.sv +++ b/hw/fpga/super6502.sv @@ -3,15 +3,15 @@ module super6502( input clk_50, input logic rst_n, input logic button_1, - + input logic [15:0] cpu_addr, inout logic [7:0] cpu_data, - + input logic cpu_vpb, input logic cpu_mlb, input logic cpu_rwb, input logic cpu_sync, - + output logic cpu_led, output logic cpu_resb, output logic cpu_rdy, @@ -20,9 +20,9 @@ module super6502( output logic cpu_phi2, output logic cpu_be, output logic cpu_nmib, - + output logic [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, - + input logic UART_RXD, output logic UART_TXD, @@ -42,7 +42,7 @@ module super6502( output DRAM_CAS_N, output DRAM_RAS_N ); - + logic rst; assign rst = ~rst_n; @@ -60,6 +60,7 @@ logic [7:0] sdram_data_out; logic [7:0] uart_data_out; logic [7:0] irq_data_out; logic [7:0] board_io_data_out; +logic [7:0] mm_data_out; logic sdram_cs; logic rom_cs; @@ -67,6 +68,8 @@ logic hex_cs; logic uart_cs; logic irq_cs; logic board_io_cs; +logic mm_cs1; +logic mm_cs2; cpu_clk cpu_clk( .inclk0(clk_50), @@ -84,14 +87,34 @@ assign cpu_be = '1; assign cpu_nmib = '1; assign cpu_irqb = irq_data_out == 0; +logic [11:0] mm_MO; + +logic [23:0] mm_addr; +assign mm_addr = {mm_MO, cpu_addr[11:0]}; + +memory_mapper memory_mapper( + .clk(clk), + .rst(rst), + .rw(cpu_rwb), + .cs(mm_cs1), + .MM_cs(mm_cs2), + .RS(cpu_addr[3:0]), + .MA(cpu_addr[15:12]), + .data_in(cpu_data_in), + .data_out(mm_data_out), + .MO(mm_MO) +); + addr_decode decode( - .addr(cpu_addr), + .addr(mm_addr), .sdram_cs(sdram_cs), .rom_cs(rom_cs), .hex_cs(hex_cs), .uart_cs(uart_cs), .irq_cs(irq_cs), - .board_io_cs(board_io_cs) + .board_io_cs(board_io_cs), + .mm_cs1(mm_cs1), + .mm_cs2(mm_cs2) ); @@ -106,6 +129,8 @@ always_comb begin cpu_data_out = irq_data_out; else if (board_io_cs) cpu_data_out = board_io_data_out; + else if (mm_cs1) + cpu_data_out = mm_data_out; else cpu_data_out = 'x; end @@ -115,7 +140,7 @@ sdram sdram( .rst(rst), .clk_50(clk_50), .cpu_clk(cpu_phi2), - .addr(cpu_addr), + .addr(mm_addr), .sdram_cs(sdram_cs), .rwb(cpu_rwb), .data_in(cpu_data_in), @@ -193,6 +218,6 @@ always_ff @(posedge clk_50) begin end end - + endmodule - \ No newline at end of file + diff --git a/sw/io.inc65 b/sw/io.inc65 index 61b079b434c7a745a40c3591f56cc0c16e39306a..5e87bc20afdbf83dd4da432cc3b26a9bd2dd5c02 100644 --- a/sw/io.inc65 +++ b/sw/io.inc65 @@ -8,4 +8,7 @@ UART_STATUS = UART + 1 LED = $7ff6 SW = LED +MM_CTRL = $7ff7 +MM_DATA = $7fe0 + IRQ_STATUS = $7fff diff --git a/sw/main.c b/sw/main.c index 1979789f98472becb8aa95d3cdaba306fd4e3390..4f894d84a807584a560860b95bd34d37102987e6 100644 --- a/sw/main.c +++ b/sw/main.c @@ -3,6 +3,7 @@ #include "board_io.h" #include "uart.h" +#include "mapper.h" int main() { int i; @@ -13,6 +14,38 @@ int main() { clrscr(); cprintf("Hello, world!\n"); + for (i = 0; i < 16; i++){ + cprintf("Mapping %1xxxx to %2xxxx\n", i, i); + mapper_write(i, i); + } + + cprintf("Enabling Mapper\n"); + mapper_enable(1); + + cprintf("Writing 0xcccc to 0x4000\n"); + *(unsigned int*)(0x4000) = 0xcccc; + + cprintf("Writing 0xdddd to 0x5000\n"); + *(unsigned int*)(0x5000) = 0xdddd; + + cprintf("Mapping %1xxxx to %2xxxx\n", 4, 16); + mapper_write(16, 4); + + cprintf("Mapping %1xxxx to %2xxxx\n", 5, 16); + mapper_write(16, 5); + + cprintf("Writing 0xa5a5 to 0x4000\n"); + *(unsigned int*)(0x4000) = 0xa5a5; + + cprintf("Reading from 0x5000: %x\n", *(unsigned int*)(0x5000)); + + cprintf("Resetting map\n"); + mapper_write(4, 4); + mapper_write(5, 5); + + cprintf("Reading from 0x4000: %x\n", *(unsigned int*)(0x4000)); + cprintf("Reading from 0x5000: %x\n", *(unsigned int*)(0x5000)); + while (1) { sw = sw_read(); diff --git a/sw/mapper.h b/sw/mapper.h new file mode 100644 index 0000000000000000000000000000000000000000..8276b60060c0aa3791f3d3118c88ebf0d0a22ed3 --- /dev/null +++ b/sw/mapper.h @@ -0,0 +1,12 @@ +#ifndef _MAPPER_H +#define _MAPPER_H + +#include <stdint.h> + +void mapper_enable(uint8_t en); + +uint8_t mapper_read(uint8_t addr); +void mapper_write(uint8_t data, uint8_t addr); + +#endif + diff --git a/sw/mapper.s b/sw/mapper.s new file mode 100644 index 0000000000000000000000000000000000000000..2ed1bc0d15ef785d6d611a96ee45f685c6025fca --- /dev/null +++ b/sw/mapper.s @@ -0,0 +1,32 @@ +.include "io.inc65" + +.importzp sp, sreg + +.export _mapper_enable +.export _mapper_read, _mapper_write + +.autoimport on + +.code + + +; void mapper_enable(uint8_t en) +_mapper_enable: + sta MM_CTRL + rts + +_mapper_read: + phx + tax + lda MM_DATA,x + ldx #$00 + rts + +_mapper_write: + phx + tax + jsr popa + sta MM_DATA,x + plx + rts +