2018-01-27 13:40:59 +11:00
|
|
|
module apple1(
|
2018-01-29 17:45:01 +11:00
|
|
|
input clk25, // 25 MHz master clock
|
|
|
|
input rst_n, // active low synchronous reset (needed for simulation)
|
2018-01-27 00:48:05 +01:00
|
|
|
|
2018-01-02 00:33:20 +11:00
|
|
|
input uart_rx,
|
|
|
|
output uart_tx,
|
2018-01-27 18:11:33 +01:00
|
|
|
output uart_cts,
|
2018-01-28 15:02:51 +11:00
|
|
|
|
2018-01-29 17:45:01 +11:00
|
|
|
input ps2_clk, // PS/2 keyboard serial clock input
|
|
|
|
input ps2_din, // PS/2 keyboard serial data input
|
2018-01-29 00:39:24 +01:00
|
|
|
|
2018-01-29 17:45:01 +11:00
|
|
|
output [15:0] pc_monitor, // spy for program counter / debugging
|
|
|
|
input reset_button // allow a physical reset button
|
2018-01-02 00:33:20 +11:00
|
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
2018-01-27 00:21:05 +11:00
|
|
|
// Registers and Wires
|
2018-01-02 00:33:20 +11:00
|
|
|
|
2018-01-27 17:00:33 +11:00
|
|
|
wire [15:0] ab;
|
2018-01-27 00:21:05 +11:00
|
|
|
wire [7:0] dbi;
|
2018-01-27 17:00:33 +11:00
|
|
|
wire [7:0] dbo;
|
|
|
|
wire we;
|
2018-01-28 15:02:51 +11:00
|
|
|
|
2018-01-02 00:33:20 +11:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
2018-01-27 00:21:05 +11:00
|
|
|
// Clocks
|
2018-01-28 15:02:51 +11:00
|
|
|
|
|
|
|
// generate clock enable once every
|
2018-01-26 22:38:46 +01:00
|
|
|
// 25 clocks. This will (hopefully) make
|
|
|
|
// the 6502 run at 1 MHz or 1Hz
|
|
|
|
//
|
2018-01-27 00:48:05 +01:00
|
|
|
// the clock division counter is synchronously
|
|
|
|
// reset using rst_n to avoid undefined signals
|
|
|
|
// in simulation
|
|
|
|
//
|
|
|
|
|
2018-01-27 18:11:33 +01:00
|
|
|
//`define SLOWCPU
|
|
|
|
`ifdef SLOWCPU
|
|
|
|
reg [25:0] clk_div;
|
|
|
|
reg cpu_clken;
|
|
|
|
always @(posedge clk25)
|
|
|
|
begin
|
|
|
|
// note: clk_div should be compared to
|
|
|
|
// N-1, where N is the clock divisor
|
2018-01-27 18:47:56 +01:00
|
|
|
if ((clk_div == 24999999) || (rst_n == 1'b0))
|
2018-01-27 18:11:33 +01:00
|
|
|
clk_div <= 0;
|
|
|
|
else
|
|
|
|
clk_div <= clk_div + 1'b1;
|
2018-01-26 22:38:46 +01:00
|
|
|
|
2018-01-27 18:11:33 +01:00
|
|
|
cpu_clken <= (clk_div[25:0] == 0);
|
2018-01-28 15:02:51 +11:00
|
|
|
end
|
2018-01-27 18:11:33 +01:00
|
|
|
`else
|
|
|
|
reg [4:0] clk_div;
|
|
|
|
reg cpu_clken;
|
|
|
|
always @(posedge clk25)
|
|
|
|
begin
|
|
|
|
// note: clk_div should be compared to
|
|
|
|
// N-1, where N is the clock divisor
|
|
|
|
if ((clk_div == 24) || (rst_n == 1'b0))
|
|
|
|
clk_div <= 0;
|
|
|
|
else
|
|
|
|
clk_div <= clk_div + 1'b1;
|
|
|
|
|
|
|
|
cpu_clken <= (clk_div[4:0] == 0);
|
|
|
|
end
|
|
|
|
`endif
|
2018-01-26 22:38:46 +01:00
|
|
|
|
2018-01-12 01:01:34 +11:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
2018-01-27 00:21:05 +11:00
|
|
|
// Reset
|
|
|
|
wire reset;
|
|
|
|
reg hard_reset;
|
|
|
|
reg [5:0] reset_cnt;
|
|
|
|
wire pwr_up_reset = &reset_cnt;
|
2018-01-12 01:01:34 +11:00
|
|
|
|
2018-01-27 00:21:05 +11:00
|
|
|
always @(posedge clk25)
|
|
|
|
begin
|
2018-01-27 00:48:05 +01:00
|
|
|
if (rst_n == 1'b0)
|
|
|
|
begin
|
|
|
|
reset_cnt <= 6'b0;
|
2018-01-27 01:21:47 +01:00
|
|
|
hard_reset <= 1'b0;
|
2018-01-27 00:48:05 +01:00
|
|
|
end
|
|
|
|
else if (cpu_clken)
|
2018-01-27 00:21:05 +11:00
|
|
|
begin
|
|
|
|
if (!pwr_up_reset)
|
2018-01-28 02:00:21 +01:00
|
|
|
reset_cnt <= reset_cnt + 6'b1;
|
2018-01-12 01:01:34 +11:00
|
|
|
|
2018-01-27 00:21:05 +11:00
|
|
|
hard_reset <= pwr_up_reset;
|
|
|
|
end
|
|
|
|
end
|
2018-01-12 01:01:34 +11:00
|
|
|
|
2018-01-29 17:45:01 +11:00
|
|
|
assign reset = ~(hard_reset && reset_button);
|
2018-01-12 01:01:34 +11:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// 6502
|
2018-01-27 17:00:33 +11:00
|
|
|
arlet_6502 my_cpu(
|
2018-01-27 00:21:05 +11:00
|
|
|
.clk (clk25),
|
2018-01-27 17:00:33 +11:00
|
|
|
.enable (cpu_clken),
|
2018-01-27 00:21:05 +11:00
|
|
|
.reset (reset),
|
2018-01-27 17:00:33 +11:00
|
|
|
.ab (ab),
|
|
|
|
.dbi (dbi),
|
|
|
|
.dbo (dbo),
|
|
|
|
.we (we),
|
2018-01-27 22:13:52 +11:00
|
|
|
.irq_n (1'b1),
|
|
|
|
.nmi_n (1'b1),
|
2018-01-27 18:11:33 +01:00
|
|
|
.ready (cpu_clken),
|
|
|
|
.pc_monitor (pc_monitor)
|
2018-01-12 01:01:34 +11:00
|
|
|
);
|
|
|
|
|
2018-01-27 00:21:05 +11:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// RAM and ROM
|
|
|
|
|
|
|
|
wire ram_cs = (ab[15:13] == 3'b000); // 0x0000 -> 0x1FFF
|
|
|
|
wire uart_cs = (ab[15:2] == 14'b11010000000100); // 0xD010 -> 0xD013
|
2018-01-29 00:39:24 +01:00
|
|
|
wire ps2kb_cs = 1'b0;
|
|
|
|
//wire uart_cs = (ab[15:1] == 15'b110100000001001); // 0xD012 -> 0xD013
|
|
|
|
//wire ps2kb_cs = (ab[15:1] == 15'b110100000001000); // 0xD010 -> 0xD011
|
2018-01-27 00:21:05 +11:00
|
|
|
wire basic_cs = (ab[15:12] == 4'b1110); // 0xE000 -> 0xEFFF
|
|
|
|
wire rom_cs = (ab[15:8] == 8'b11111111); // 0xFF00 -> 0xFFFF
|
|
|
|
|
|
|
|
// RAM
|
|
|
|
wire [7:0] ram_dout;
|
2018-01-29 17:45:01 +11:00
|
|
|
ram my_ram(
|
2018-01-27 00:21:05 +11:00
|
|
|
.clk(clk25),
|
|
|
|
.address(ab[12:0]),
|
|
|
|
.w_en(we & ram_cs),
|
|
|
|
.din(dbo),
|
|
|
|
.dout(ram_dout)
|
|
|
|
);
|
|
|
|
|
|
|
|
// WozMon ROM
|
|
|
|
wire [7:0] rom_dout;
|
2018-01-29 17:45:01 +11:00
|
|
|
rom_wozmon my_rom_wozmon(
|
2018-01-27 00:21:05 +11:00
|
|
|
.clk(clk25),
|
|
|
|
.address(ab[7:0]),
|
|
|
|
.dout(rom_dout)
|
|
|
|
);
|
|
|
|
|
2018-01-28 15:02:51 +11:00
|
|
|
// Basic ROM
|
|
|
|
wire [7:0] basic_dout;
|
2018-01-29 17:45:01 +11:00
|
|
|
rom_basic my_rom_basic(
|
2018-01-28 15:02:51 +11:00
|
|
|
.clk(clk25),
|
2018-01-28 20:18:56 +01:00
|
|
|
.address(ab[11:0]),
|
2018-01-28 15:02:51 +11:00
|
|
|
.dout(basic_dout)
|
|
|
|
);
|
|
|
|
|
2018-01-27 00:21:05 +11:00
|
|
|
// UART
|
|
|
|
wire [7:0] uart_dout;
|
2018-01-28 00:23:09 +11:00
|
|
|
uart #(
|
2018-01-28 15:02:51 +11:00
|
|
|
`ifdef SIM
|
|
|
|
100, 10, 2 // for simulation don't need real baud rates
|
|
|
|
`else
|
2018-01-29 17:45:01 +11:00
|
|
|
25000000, 115200, 8 // 25MHz, 115200 baud, 8 times RX oversampling
|
2018-01-28 15:02:51 +11:00
|
|
|
`endif
|
2018-01-29 17:45:01 +11:00
|
|
|
) my_uart(
|
2018-01-27 00:21:05 +11:00
|
|
|
.clk(clk25),
|
2018-01-27 22:13:52 +11:00
|
|
|
.reset(reset),
|
2018-01-27 00:21:05 +11:00
|
|
|
|
|
|
|
.uart_rx(uart_rx),
|
|
|
|
.uart_tx(uart_tx),
|
|
|
|
.uart_cts(uart_cts),
|
|
|
|
|
|
|
|
.enable(uart_cs & cpu_clken),
|
2018-01-29 00:39:24 +01:00
|
|
|
//.address({1'b1, ab[0]}), // for ps/2
|
2018-01-27 00:21:05 +11:00
|
|
|
.address(ab[1:0]),
|
|
|
|
.w_en(we & uart_cs),
|
|
|
|
.din(dbo),
|
2018-01-27 13:40:59 +11:00
|
|
|
.dout(uart_dout)
|
2018-01-27 00:21:05 +11:00
|
|
|
);
|
2018-01-02 00:33:20 +11:00
|
|
|
|
2018-01-29 00:39:24 +01:00
|
|
|
// PS/2 keyboard interface
|
|
|
|
wire [7:0] ps2_dout;
|
2018-01-29 17:45:01 +11:00
|
|
|
ps2keyboard keyboard(
|
2018-01-29 00:39:24 +01:00
|
|
|
.clk25(clk25),
|
|
|
|
.reset(reset),
|
|
|
|
.key_clk(ps2_clk),
|
|
|
|
.key_din(ps2_din),
|
|
|
|
.cs(ps2kb_cs),
|
|
|
|
.address(ab[0]),
|
|
|
|
.dout(ps2_dout)
|
|
|
|
);
|
|
|
|
|
2018-01-27 00:21:05 +11:00
|
|
|
// link up chip selected device to cpu input
|
2018-01-28 15:02:51 +11:00
|
|
|
assign dbi = ram_cs ? ram_dout :
|
|
|
|
rom_cs ? rom_dout :
|
|
|
|
basic_cs ? basic_dout :
|
|
|
|
uart_cs ? uart_dout :
|
2018-01-29 00:39:24 +01:00
|
|
|
ps2kb_cs ? ps2_dout :
|
2018-01-27 00:21:05 +11:00
|
|
|
8'hFF;
|
2018-01-02 00:33:20 +11:00
|
|
|
endmodule
|