2018-08-13 22:17:36 +00:00
|
|
|
|
2018-02-27 04:48:36 +00:00
|
|
|
`include "hvsync_generator.v"
|
|
|
|
`include "font_cp437_8x8.v"
|
|
|
|
`include "ram.v"
|
|
|
|
`include "tile_renderer.v"
|
|
|
|
`include "sprite_scanline_renderer.v"
|
|
|
|
`include "lfsr.v"
|
|
|
|
`include "sound_generator.v"
|
|
|
|
`include "cpu16.v"
|
|
|
|
|
2018-10-01 16:30:47 +00:00
|
|
|
/*
|
|
|
|
A full video game console, with the following components:
|
|
|
|
|
|
|
|
64 kilobytes (32,678 16-bit words) of RAM
|
|
|
|
16-bit CPU running at 4.857 MHz
|
|
|
|
32x30 tile graphics with 256 x 8 tile ROM
|
|
|
|
32 16x16 sprites per frame with sprite ROM
|
|
|
|
16 colors (two per tile, one per sprite)
|
|
|
|
Two game controllers (four direction switches, two buttons)
|
|
|
|
One paddle/analog stick controller
|
|
|
|
*/
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
module cpu_platform(clk, reset, hsync, vsync,
|
|
|
|
hpaddle, vpaddle,
|
|
|
|
switches_p1, switches_p2,
|
|
|
|
rgb);
|
2018-02-27 04:48:36 +00:00
|
|
|
|
|
|
|
input clk, reset;
|
2018-05-27 18:13:06 +00:00
|
|
|
input hpaddle, vpaddle;
|
2018-07-12 02:53:05 +00:00
|
|
|
input [7:0] switches_p1;
|
|
|
|
input [7:0] switches_p2;
|
2018-02-27 04:48:36 +00:00
|
|
|
output hsync, vsync;
|
|
|
|
output [3:0] rgb;
|
|
|
|
|
|
|
|
wire display_on;
|
|
|
|
wire [8:0] hpos;
|
|
|
|
wire [8:0] vpos;
|
|
|
|
|
|
|
|
// video RAM bus
|
2018-02-28 03:35:42 +00:00
|
|
|
wire [15:0] ram_read;
|
2018-02-28 17:09:29 +00:00
|
|
|
reg [15:0] ram_write;
|
|
|
|
reg ram_writeenable;
|
2018-02-27 04:48:36 +00:00
|
|
|
|
|
|
|
// multiplex sprite and tile RAM
|
|
|
|
reg [15:0] tile_ram_addr;
|
2018-02-28 03:35:42 +00:00
|
|
|
reg [5:0] sprite_ram_addr;
|
|
|
|
wire tile_reading;
|
|
|
|
wire sprite_reading;
|
|
|
|
wire [14:0] mux_ram_addr; // 15-bit RAM access
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// multiplexor for sprite/tile/CPU RAM
|
2018-02-28 03:35:42 +00:00
|
|
|
always @(*)
|
|
|
|
if (cpu_busy) begin
|
2018-02-28 17:09:29 +00:00
|
|
|
if (sprite_reading)
|
|
|
|
mux_ram_addr = {9'b111111100, sprite_ram_addr};
|
2018-02-28 03:35:42 +00:00
|
|
|
else
|
|
|
|
mux_ram_addr = tile_ram_addr[14:0];
|
|
|
|
end else
|
|
|
|
mux_ram_addr = cpu_ram_addr[14:0];
|
2018-02-27 04:48:36 +00:00
|
|
|
|
|
|
|
// tile and sprite ROM
|
|
|
|
wire [10:0] tile_rom_addr;
|
|
|
|
wire [7:0] tile_rom_data;
|
|
|
|
wire [15:0] sprite_rom_addr;
|
|
|
|
wire [15:0] sprite_rom_data;
|
|
|
|
|
|
|
|
// gfx outputs
|
|
|
|
wire [3:0] tile_rgb;
|
|
|
|
wire [3:0] sprite_rgb;
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// video sync generator
|
2018-02-27 04:48:36 +00:00
|
|
|
hvsync_generator hvsync_gen(
|
|
|
|
.clk(clk),
|
|
|
|
.reset(reset),
|
|
|
|
.hsync(hsync),
|
|
|
|
.vsync(vsync),
|
|
|
|
.display_on(display_on),
|
|
|
|
.hpos(hpos),
|
|
|
|
.vpos(vpos)
|
|
|
|
);
|
|
|
|
|
2018-02-28 03:35:42 +00:00
|
|
|
// RAM (32k x 16 bits)
|
|
|
|
RAM_sync #(15,16) ram(
|
2018-02-27 04:48:36 +00:00
|
|
|
.clk(clk),
|
2018-02-28 03:35:42 +00:00
|
|
|
.dout(ram_read),
|
|
|
|
.din(ram_write),
|
|
|
|
.addr(mux_ram_addr),
|
|
|
|
.we(ram_writeenable)
|
2018-02-27 04:48:36 +00:00
|
|
|
);
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// tile graphics
|
2018-02-27 04:48:36 +00:00
|
|
|
tile_renderer tile_gen(
|
|
|
|
.clk(clk),
|
|
|
|
.reset(reset),
|
|
|
|
.hpos(hpos),
|
|
|
|
.vpos(vpos),
|
|
|
|
.ram_addr(tile_ram_addr),
|
2018-02-28 03:35:42 +00:00
|
|
|
.ram_read(ram_read),
|
|
|
|
.ram_busy(tile_reading),
|
2018-02-27 04:48:36 +00:00
|
|
|
.rom_addr(tile_rom_addr),
|
|
|
|
.rom_data(tile_rom_data),
|
|
|
|
.rgb(tile_rgb)
|
|
|
|
);
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// sprite scanline renderer
|
2018-02-27 04:48:36 +00:00
|
|
|
sprite_scanline_renderer ssr(
|
|
|
|
.clk(clk),
|
|
|
|
.reset(reset),
|
|
|
|
.hpos(hpos),
|
|
|
|
.vpos(vpos),
|
|
|
|
.ram_addr(sprite_ram_addr),
|
2018-02-28 03:35:42 +00:00
|
|
|
.ram_data(ram_read),
|
|
|
|
.ram_busy(sprite_reading),
|
2018-02-27 04:48:36 +00:00
|
|
|
.rom_addr(sprite_rom_addr),
|
|
|
|
.rom_data(sprite_rom_data),
|
|
|
|
.rgb(sprite_rgb)
|
|
|
|
);
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// tile ROM
|
2018-02-27 04:48:36 +00:00
|
|
|
font_cp437_8x8 tile_rom(
|
|
|
|
.addr(tile_rom_addr),
|
|
|
|
.data(tile_rom_data)
|
|
|
|
);
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// sprite ROM
|
2018-02-27 04:48:36 +00:00
|
|
|
example_bitmap_rom bitmap_rom(
|
|
|
|
.addr(sprite_rom_addr),
|
|
|
|
.data(sprite_rom_data)
|
|
|
|
);
|
2018-02-28 03:35:42 +00:00
|
|
|
|
|
|
|
// sprites overlay tiles
|
2018-02-27 04:48:36 +00:00
|
|
|
assign rgb = display_on
|
|
|
|
? (sprite_rgb>0 ? sprite_rgb : tile_rgb)
|
|
|
|
: 0;
|
|
|
|
|
2018-02-28 03:35:42 +00:00
|
|
|
// CPU
|
|
|
|
reg cpu_hold = 0;
|
|
|
|
wire cpu_busy;
|
|
|
|
wire [15:0] cpu_ram_addr;
|
2018-02-27 04:48:36 +00:00
|
|
|
wire busy;
|
2018-02-28 03:35:42 +00:00
|
|
|
wire [15:0] cpu_bus;
|
2018-05-27 18:13:06 +00:00
|
|
|
wire [15:0] flags = {11'b0, vsync, hsync, vpaddle, hpaddle, display_on};
|
2018-07-12 02:53:05 +00:00
|
|
|
wire [15:0] switches = {switches_p2, switches_p1};
|
2018-02-28 03:35:42 +00:00
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// select ROM, RAM, switches ($FFFE) or flags ($FFFF)
|
|
|
|
always @(*)
|
|
|
|
casez (cpu_ram_addr)
|
|
|
|
16'hfffe: cpu_bus = switches;
|
|
|
|
16'hffff: cpu_bus = flags;
|
|
|
|
16'b0???????????????: cpu_bus = ram_read;
|
|
|
|
16'b1???????????????: cpu_bus = program_rom[cpu_ram_addr[14:0]];
|
|
|
|
endcase
|
|
|
|
|
|
|
|
// 16-bit CPU
|
2018-02-27 04:48:36 +00:00
|
|
|
CPU16 cpu(
|
|
|
|
.clk(clk),
|
|
|
|
.reset(reset),
|
2018-07-12 02:53:05 +00:00
|
|
|
.hold(tile_reading | sprite_reading), // hold input
|
|
|
|
.busy(cpu_busy), // busy output
|
2018-02-28 03:35:42 +00:00
|
|
|
.address(cpu_ram_addr),
|
|
|
|
.data_in(cpu_bus),
|
|
|
|
.data_out(ram_write),
|
|
|
|
.write(ram_writeenable));
|
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// program ROM ($8000-$FFFE)
|
|
|
|
reg [15:0] program_rom[0:32767];
|
2018-02-27 04:48:36 +00:00
|
|
|
|
2018-07-12 02:53:05 +00:00
|
|
|
// example ROM program code
|
2018-02-28 03:35:42 +00:00
|
|
|
`ifdef EXT_INLINE_ASM
|
|
|
|
initial begin
|
2018-03-02 05:15:33 +00:00
|
|
|
program_rom = '{
|
2018-02-28 03:35:42 +00:00
|
|
|
__asm
|
|
|
|
.arch femto16
|
|
|
|
.org 0x8000
|
2018-07-12 02:53:05 +00:00
|
|
|
.len 32768
|
2018-02-28 03:35:42 +00:00
|
|
|
mov sp,@$6fff
|
2018-02-28 17:09:29 +00:00
|
|
|
mov dx,@InitPageTable
|
2018-02-28 03:35:42 +00:00
|
|
|
jsr dx
|
2018-02-28 17:09:29 +00:00
|
|
|
mov ax,@$4ffe
|
|
|
|
mov dx,@ClearTiles
|
|
|
|
jsr dx
|
|
|
|
mov dx,@ClearSprites
|
2018-02-28 03:35:42 +00:00
|
|
|
jsr dx
|
|
|
|
reset
|
2018-02-28 17:09:29 +00:00
|
|
|
InitPageTable:
|
2018-02-28 03:35:42 +00:00
|
|
|
mov ax,@$6000 ; screen buffer
|
|
|
|
mov bx,@$7e00 ; page table start
|
|
|
|
mov cx,#32 ; 32 rows
|
2018-02-28 17:09:29 +00:00
|
|
|
InitPTLoop:
|
2018-02-28 03:35:42 +00:00
|
|
|
mov [bx],ax
|
|
|
|
add ax,#32
|
|
|
|
inc bx
|
|
|
|
dec cx
|
2018-02-28 17:09:29 +00:00
|
|
|
bnz InitPTLoop
|
2018-02-28 03:35:42 +00:00
|
|
|
rts
|
2018-02-28 17:09:29 +00:00
|
|
|
ClearTiles:
|
|
|
|
mov bx,@$6000
|
2018-03-02 05:15:33 +00:00
|
|
|
mov cx,@$3c0
|
2018-02-28 03:35:42 +00:00
|
|
|
ClearLoop:
|
|
|
|
mov [bx],ax
|
|
|
|
inc bx
|
|
|
|
dec cx
|
|
|
|
bnz ClearLoop
|
|
|
|
rts
|
2018-02-28 17:09:29 +00:00
|
|
|
ClearSprites:
|
|
|
|
mov bx,@$7f00
|
|
|
|
mov ax,#0
|
2018-03-02 02:17:37 +00:00
|
|
|
mov cx,#$40
|
2018-02-28 17:09:29 +00:00
|
|
|
ClearSLoop:
|
|
|
|
mov ax,[bx]
|
|
|
|
add ax,@$101
|
|
|
|
mov [bx],ax
|
|
|
|
inc bx
|
|
|
|
dec cx
|
|
|
|
bnz ClearSLoop
|
2018-07-12 02:53:05 +00:00
|
|
|
rts
|
2018-02-28 03:35:42 +00:00
|
|
|
__endasm
|
|
|
|
};
|
|
|
|
end
|
|
|
|
`endif
|
|
|
|
|
2018-02-27 04:48:36 +00:00
|
|
|
endmodule
|