Merge branch 'mmu' into 'master'
Add memory mapper. See merge request bslathi19/super6502!10
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
85
hw/fpga/hvl/mm_testbench.sv
Normal file
85
hw/fpga/hvl/mm_testbench.sv
Normal file
@@ -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
|
||||
58
hw/fpga/memory_mapper.sv
Normal file
58
hw/fpga/memory_mapper.sv
Normal file
@@ -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
|
||||
|
||||
@@ -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
|
||||
endmodule
|
||||
|
||||
24
hw/fpga/simulation/modelsim/mm_testbench.do
Normal file
24
hw/fpga/simulation/modelsim/mm_testbench.do
Normal file
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -8,4 +8,7 @@ UART_STATUS = UART + 1
|
||||
LED = $7ff6
|
||||
SW = LED
|
||||
|
||||
MM_CTRL = $7ff7
|
||||
MM_DATA = $7fe0
|
||||
|
||||
IRQ_STATUS = $7fff
|
||||
|
||||
33
sw/main.c
33
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();
|
||||
|
||||
12
sw/mapper.h
Normal file
12
sw/mapper.h
Normal file
@@ -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
|
||||
|
||||
32
sw/mapper.s
Normal file
32
sw/mapper.s
Normal file
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user