mirror of
https://github.com/MiSTer-devel/Gameboy_MiSTer.git
synced 2026-04-19 03:04:09 +00:00
40
Gameboy.sv
40
Gameboy.sv
@@ -151,7 +151,7 @@ assign AUDIO_MIX = status[8:7];
|
||||
// 0 1 2 3
|
||||
// 01234567890123456789012345678901
|
||||
// 0123456789ABCDEFGHIJKLMNOPQRSTUV
|
||||
// XXXXXXXXXXXXXXXXXXXXX XX
|
||||
// XXXXXXXXXXXXXXXXXXXXX XXXXX
|
||||
|
||||
`include "build_id.v"
|
||||
localparam CONF_STR = {
|
||||
@@ -179,9 +179,12 @@ localparam CONF_STR = {
|
||||
"-;",
|
||||
"OB,Boot,Normal,Fast;",
|
||||
"O6,Link Port,Disabled,Enabled;",
|
||||
"-;",
|
||||
"OPQ,FastForward Sound,Normal,Hack,Off;",
|
||||
"OR,Pause when OSD is open,Off,On;",
|
||||
"-;",
|
||||
"R0,Reset;",
|
||||
"J1,A,B,Select,Start;",
|
||||
"J1,A,B,Select,Start,FastForward;",
|
||||
"V,v",`BUILD_DATE
|
||||
};
|
||||
|
||||
@@ -555,6 +558,9 @@ always @(posedge clk_sys) if(reset) begin
|
||||
else if(cart_download) isGBC <= !filetype[7:4];
|
||||
end
|
||||
|
||||
wire [15:0] GB_AUDIO_L;
|
||||
wire [15:0] GB_AUDIO_R;
|
||||
|
||||
// the gameboy itself
|
||||
gb gb (
|
||||
.reset ( reset ),
|
||||
@@ -562,6 +568,7 @@ gb gb (
|
||||
.clk_sys ( clk_sys ),
|
||||
.ce ( ce_cpu ), // the whole gameboy runs on 4mhnz
|
||||
.ce_2x ( ce_cpu2x ), // ~8MHz in dualspeed mode (GBC)
|
||||
.ce_sound ( ce_sound ), // ~8Mhz if not fastforward
|
||||
|
||||
.fast_boot ( status[11] ),
|
||||
|
||||
@@ -583,8 +590,8 @@ gb gb (
|
||||
.gbc_bios_do ( bios_do ),
|
||||
|
||||
// audio
|
||||
.audio_l ( AUDIO_L ),
|
||||
.audio_r ( AUDIO_R ),
|
||||
.audio_l ( GB_AUDIO_L ),
|
||||
.audio_r ( GB_AUDIO_R ),
|
||||
|
||||
// interface to the lcd
|
||||
.lcd_clkena ( lcd_clkena ),
|
||||
@@ -609,6 +616,9 @@ gb gb (
|
||||
.gg_available(gg_available)
|
||||
);
|
||||
|
||||
assign AUDIO_L = (joystick_0[8] && status[26]) ? 16'd0 : GB_AUDIO_L;
|
||||
assign AUDIO_R = (joystick_0[8] && status[26]) ? 16'd0 : GB_AUDIO_R;
|
||||
|
||||
// the lcd to vga converter
|
||||
wire [7:0] video_r, video_g, video_b;
|
||||
wire video_hs, video_vs;
|
||||
@@ -739,14 +749,22 @@ video_mixer #(.LINE_LENGTH(200), .GAMMA(1)) video_mixer
|
||||
|
||||
//////////////////////////////// CE ////////////////////////////////////
|
||||
|
||||
reg ce_cpu, ce_cpu2x;
|
||||
always @(negedge clk_sys) begin
|
||||
reg [2:0] div = 0;
|
||||
|
||||
div <= div + 1'd1;
|
||||
ce_cpu2x <= !div[1:0];
|
||||
ce_cpu <= !div[2:0];
|
||||
end
|
||||
wire ce_cpu, ce_cpu2x, ce_sound, ce_soundhack;
|
||||
wire cart_act = cart_wr | cart_rd;
|
||||
|
||||
speedcontrol speedcontrol
|
||||
(
|
||||
.clk_sys (clk_sys),
|
||||
.pause (status[27] && OSD_STATUS && !ioctl_download),
|
||||
.speedup (joystick_0[8] && !ioctl_download && !OSD_STATUS),
|
||||
.cart_act (cart_act),
|
||||
.ce (ce_cpu),
|
||||
.ce_2x (ce_cpu2x),
|
||||
.ce_2xNormal (ce_soundhack)
|
||||
);
|
||||
|
||||
assign ce_sound = status[25] ? ce_soundhack : ce_cpu2x;
|
||||
|
||||
///////////////////////////// GBC BIOS /////////////////////////////////
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ set_global_assignment -name VERILOG_FILE rtl/timer.v
|
||||
set_global_assignment -name VERILOG_FILE rtl/sprites.v
|
||||
set_global_assignment -name VERILOG_FILE rtl/lcd.v
|
||||
set_global_assignment -name VHDL_FILE rtl/gbc_snd.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/speedcontrol.vhd
|
||||
set_global_assignment -name VERILOG_FILE rtl/gb.v
|
||||
set_global_assignment -name VERILOG_FILE rtl/hdma.v
|
||||
set_global_assignment -name VERILOG_FILE rtl/link.v
|
||||
|
||||
97
rtl/gb.v
97
rtl/gb.v
@@ -25,6 +25,7 @@ module gb (
|
||||
input clk_sys,
|
||||
input ce,
|
||||
input ce_2x,
|
||||
input ce_sound,
|
||||
|
||||
input fast_boot,
|
||||
input [7:0] joystick,
|
||||
@@ -93,7 +94,8 @@ wire sel_zpram = (cpu_addr[15:7] == 9'b111111111) && // 127 bytes zero pageram a
|
||||
wire sel_audio = (cpu_addr[15:8] == 8'hff) && // audio reg ff10 - ff3f and ff76/ff77 PCM12/PCM34 (undocumented registers)
|
||||
((cpu_addr[7:5] == 3'b001) || (cpu_addr[7:4] == 4'b0001) || (cpu_addr[7:0] == 8'h76) || (cpu_addr[7:0] == 8'h77));
|
||||
|
||||
//DMA can select from $0000 to $F100
|
||||
//DMA can select from $0000 to $F100
|
||||
wire [15:0] dma_addr;
|
||||
wire dma_sel_rom = !dma_addr[15]; // lower 32k are rom
|
||||
wire dma_sel_cram = dma_addr[15:13] == 3'b101; // 8k cart ram at $a000
|
||||
wire dma_sel_vram = dma_addr[15:13] == 3'b100; // 8k video ram at $8000
|
||||
@@ -108,16 +110,46 @@ wire sel_key1 = cpu_addr == 16'hff4d; // KEY1 - CGB Mode Only - Prepar
|
||||
wire sel_rp = cpu_addr == 16'hff56; //FF56 - RP - CGB Mode Only - Infrared Communications Port
|
||||
|
||||
//HDMA can select from $0000 to $7ff0 or A000-DFF0
|
||||
wire [15:0] hdma_source_addr;
|
||||
wire hdma_sel_rom = !hdma_source_addr[15]; // lower 32k are rom
|
||||
wire hdma_sel_cram = hdma_source_addr[15:13] == 3'b101; // 8k cart ram at $a000
|
||||
wire hdma_sel_iram = hdma_source_addr[15:13] == 3'b110; // 8k internal ram at $c000-$dff0
|
||||
|
||||
|
||||
// the boot roms sees a special $42 flag in $ff50 if it's supposed to to a fast boot
|
||||
reg boot_rom_enabled;
|
||||
wire sel_fast = fast_boot && cpu_addr == 16'hff50 && boot_rom_enabled;
|
||||
|
||||
wire sc_start;
|
||||
wire sc_shiftclock;
|
||||
wire [7:0] sc_r = {sc_start,6'h3F,sc_shiftclock};
|
||||
|
||||
wire irq_ack;
|
||||
wire [7:0] irq_vec;
|
||||
reg [4:0] if_r;
|
||||
reg [4:0] ie_r; // writing $ffff sets the irq enable mask
|
||||
wire irq_n;
|
||||
|
||||
reg [2:0] iram_bank; //1-7 FF70 - SVBK
|
||||
reg vram_bank; //0-1 FF4F - VBK
|
||||
|
||||
wire [7:0] hdma_do;
|
||||
wire hdma_active;
|
||||
|
||||
reg cpu_speed; // - 0 Normal mode (4MHz) - 1 Double Speed Mode (8MHz)
|
||||
reg prepare_switch; // set to 1 to toggle speed
|
||||
|
||||
wire [7:0] joy_do;
|
||||
wire [7:0] sb_o;
|
||||
wire [7:0] timer_do;
|
||||
wire [7:0] video_do;
|
||||
wire [7:0] audio_do;
|
||||
wire [7:0] rom_do;
|
||||
wire [7:0] vram_do;
|
||||
wire [7:0] vram1_do;
|
||||
wire [7:0] zpram_do;
|
||||
wire [7:0] iram_do;
|
||||
|
||||
// http://gameboy.mongenel.com/dmg/asmmemmap.html
|
||||
wire [7:0] cpu_di =
|
||||
irq_ack?irq_vec:
|
||||
@@ -165,6 +197,8 @@ end
|
||||
|
||||
wire cpu_stop;
|
||||
|
||||
wire genie_ovr;
|
||||
wire [7:0] genie_data;
|
||||
|
||||
GBse cpu (
|
||||
.RESET_n ( !reset_r ),
|
||||
@@ -192,9 +226,6 @@ GBse cpu (
|
||||
// --------------------------- Cheat Engine ---------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
wire genie_ovr;
|
||||
wire [7:0] genie_data;
|
||||
|
||||
CODES codes (
|
||||
.clk (clk_sys),
|
||||
.reset (gg_reset),
|
||||
@@ -211,8 +242,6 @@ CODES codes (
|
||||
// --------------------------------------------------------------------
|
||||
// --------------------- Speed Toggle KEY1 (GBC)-----------------------
|
||||
// --------------------------------------------------------------------
|
||||
reg cpu_speed; // - 0 Normal mode (4MHz) - 1 Double Speed Mode (8MHz)
|
||||
reg prepare_switch; // set to 1 to toggle speed
|
||||
assign speed = cpu_speed;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
@@ -236,12 +265,11 @@ end
|
||||
|
||||
wire audio_rd = !cpu_rd_n && sel_audio;
|
||||
wire audio_wr = !cpu_wr_n && sel_audio;
|
||||
wire [7:0] audio_do;
|
||||
|
||||
gbc_snd audio (
|
||||
.clk ( clk_sys ),
|
||||
.ce ( ce_2x ),
|
||||
.reset ( reset_r ),
|
||||
.ce ( ce_sound ),
|
||||
.reset ( reset_r ),
|
||||
|
||||
.is_gbc ( isGBC ),
|
||||
|
||||
@@ -261,9 +289,6 @@ gbc_snd audio (
|
||||
|
||||
// SNAC
|
||||
wire serial_irq;
|
||||
wire [7:0] sb_o;
|
||||
wire sc_start;
|
||||
wire sc_shiftclock;
|
||||
|
||||
assign sc_int_clock2 = sc_shiftclock;
|
||||
|
||||
@@ -302,7 +327,7 @@ always @(posedge clk_cpu) begin
|
||||
else if(sel_joy && !cpu_wr_n) p54 <= cpu_do[5:4];
|
||||
end
|
||||
|
||||
wire [7:0] joy_do = { 2'b11, p54, joy_din };
|
||||
assign joy_do = { 2'b11, p54, joy_din };
|
||||
assign joy_p54 = p54;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -313,10 +338,10 @@ assign joy_p54 = p54;
|
||||
// the register to 1. The "highest" one active is cleared when the cpu
|
||||
// runs an interrupt ack cycle or when it writes a 0 to the register
|
||||
|
||||
wire irq_ack = !cpu_iorq_n && !cpu_m1_n;
|
||||
assign irq_ack = !cpu_iorq_n && !cpu_m1_n;
|
||||
|
||||
// irq vector
|
||||
wire [7:0] irq_vec =
|
||||
assign irq_vec =
|
||||
if_r[0]&&ie_r[0]?8'h40: // vsync
|
||||
if_r[1]&&ie_r[1]?8'h48: // lcdc
|
||||
if_r[2]&&ie_r[2]?8'h50: // timer
|
||||
@@ -329,15 +354,15 @@ wire [7:0] irq_vec =
|
||||
reg [3:0] inputD, inputD2;
|
||||
|
||||
// irq is low when an enable irq is active
|
||||
wire irq_n = !(ie_r & if_r);
|
||||
assign irq_n = !(ie_r & if_r);
|
||||
|
||||
reg [4:0] if_r;
|
||||
reg [4:0] ie_r; // writing $ffff sets the irq enable mask
|
||||
wire video_irq,vblank_irq;
|
||||
wire timer_irq;
|
||||
|
||||
reg old_vblank_irq, old_video_irq, old_timer_irq, old_serial_irq;
|
||||
reg old_ack = 0;
|
||||
always @(negedge clk_cpu) begin //negedge to trigger interrupt earlier
|
||||
reg old_ack = 0;
|
||||
|
||||
|
||||
if(reset_r) begin
|
||||
ie_r <= 5'h00;
|
||||
if_r <= 5'h00;
|
||||
@@ -391,8 +416,6 @@ end
|
||||
// ------------------------------ timer -------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
wire timer_irq;
|
||||
wire [7:0] timer_do;
|
||||
timer timer (
|
||||
.reset ( reset_r ),
|
||||
.clk ( clk_cpu ), //2x in fast mode
|
||||
@@ -411,10 +434,7 @@ timer timer (
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// cpu tries to read or write the lcd controller registers
|
||||
wire video_irq,vblank_irq;
|
||||
wire [7:0] video_do;
|
||||
wire [12:0] video_addr;
|
||||
wire [15:0] dma_addr;
|
||||
wire video_rd, dma_rd;
|
||||
wire [7:0] dma_data = dma_sel_iram?iram_do:dma_sel_vram?(isGBC&&vram_bank)?vram1_do:vram_do:cart_do;
|
||||
|
||||
@@ -460,9 +480,8 @@ video video (
|
||||
// total 8k/16k (CGB) vram from $8000 to $9fff
|
||||
wire cpu_wr_vram = sel_vram && !cpu_wr_n && lcd_mode!=3;
|
||||
|
||||
reg vram_bank; //0-1 FF4F - VBK
|
||||
|
||||
wire [7:0] vram_do,vram1_do;
|
||||
wire hdma_rd;
|
||||
wire is_hdma_cart_addr;
|
||||
wire [7:0] vram_di = (hdma_rd&&isGBC)?
|
||||
hdma_sel_iram?iram_do:
|
||||
is_hdma_cart_addr?cart_do:
|
||||
@@ -473,6 +492,7 @@ wire [7:0] vram_di = (hdma_rd&&isGBC)?
|
||||
wire vram_wren = video_rd?1'b0:!vram_bank&&((hdma_rd&&isGBC)||cpu_wr_vram);
|
||||
wire vram1_wren = video_rd?1'b0:vram_bank&&((hdma_rd&&isGBC)||cpu_wr_vram);
|
||||
|
||||
wire [15:0] hdma_target_addr;
|
||||
wire [12:0] vram_addr = video_rd?video_addr:(hdma_rd&&isGBC)?hdma_target_addr[12:0]:(dma_rd&&dma_sel_vram)?dma_addr[12:0]:cpu_addr[12:0];
|
||||
|
||||
|
||||
@@ -505,12 +525,6 @@ end
|
||||
// -------------------------- HDMA engine(GBC) ------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
wire [15:0] hdma_source_addr;
|
||||
wire [15:0] hdma_target_addr;
|
||||
wire [7:0] hdma_do;
|
||||
wire hdma_rd;
|
||||
wire hdma_active;
|
||||
|
||||
hdma hdma(
|
||||
.reset ( reset_r ),
|
||||
.clk ( clk_sys ),
|
||||
@@ -540,7 +554,6 @@ hdma hdma(
|
||||
|
||||
// 127 bytes internal zero page ram from $ff80 to $fffe
|
||||
wire cpu_wr_zpram = sel_zpram && !cpu_wr_n;
|
||||
wire [7:0] zpram_do;
|
||||
spram #(7) zpram (
|
||||
.clock ( clk_cpu ),
|
||||
.address ( cpu_addr[6:0] ),
|
||||
@@ -553,7 +566,7 @@ spram #(7) zpram (
|
||||
// ------------------------ 8k/32k(GBC) internal ram -----------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
reg [2:0] iram_bank; //1-7 FF70 - SVBK
|
||||
wire cpu_wr_iram = sel_iram && !cpu_wr_n;
|
||||
wire iram_wren = (dma_rd&&dma_sel_iram)||(isGBC&&hdma_rd&&hdma_sel_iram)?1'b0:cpu_wr_iram;
|
||||
|
||||
wire [14:0] iram_addr = (isGBC&&hdma_rd&&hdma_sel_iram)? //hdma transfer?
|
||||
@@ -567,8 +580,6 @@ wire [14:0] iram_addr = (isGBC&&hdma_rd&&hdma_sel_iram)? //hdma tr
|
||||
{3'd0,cpu_addr[11:0]}; //bank 0
|
||||
|
||||
|
||||
wire cpu_wr_iram = sel_iram && !cpu_wr_n;
|
||||
wire [7:0] iram_do;
|
||||
spram #(15) iram (
|
||||
.clock ( clk_cpu ),
|
||||
.address ( iram_addr ),
|
||||
@@ -594,7 +605,6 @@ end
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// writing 01(GB) or 11(GBC) to $ff50 disables the internal rom
|
||||
reg boot_rom_enabled;
|
||||
always @(posedge clk) begin
|
||||
if(reset_r)
|
||||
boot_rom_enabled <= 1'b1;
|
||||
@@ -605,7 +615,10 @@ end
|
||||
|
||||
// combine boot rom data with cartridge data
|
||||
|
||||
wire [7:0] rom_do = isGBC? //GameBoy Color?
|
||||
wire [7:0] boot_rom_do;
|
||||
wire [7:0] fast_boot_rom_do;
|
||||
|
||||
assign rom_do = isGBC? //GameBoy Color?
|
||||
(((cpu_addr[14:8] == 7'h00) || (hdma_rd&& hdma_source_addr[14:8] == 7'h00))&& boot_rom_enabled)?gbc_bios_do: //0-FF bootrom 1st part
|
||||
((cpu_addr[14:9] == 6'h00) || (hdma_rd&& hdma_source_addr[14:9] == 6'h00))? cart_do: //100-1FF Cart Header
|
||||
(((cpu_addr[14:12] == 3'h0) || (hdma_rd&& hdma_source_addr[14:12] == 3'h0)) && boot_rom_enabled)?gbc_bios_do: //200-8FF bootrom 2nd part
|
||||
@@ -614,7 +627,7 @@ wire [7:0] rom_do = isGBC? //GameBoy Color?
|
||||
|
||||
|
||||
wire is_dma_cart_addr = (dma_sel_rom || dma_sel_cram); //rom or external ram
|
||||
wire is_hdma_cart_addr = (hdma_sel_rom || hdma_sel_cram); //rom or external ram
|
||||
assign is_hdma_cart_addr = (hdma_sel_rom || hdma_sel_cram); //rom or external ram
|
||||
|
||||
assign cart_di = cpu_do;
|
||||
assign cart_addr = (isGBC&&hdma_rd&&is_hdma_cart_addr)?hdma_source_addr:(dma_rd&&is_dma_cart_addr)?dma_addr:cpu_addr;
|
||||
@@ -623,14 +636,12 @@ assign cart_wr = (sel_rom || sel_cram) && !cpu_wr_n && !hdma_rd;
|
||||
|
||||
assign gbc_bios_addr = hdma_rd?hdma_source_addr[11:0]:cpu_addr[11:0];
|
||||
|
||||
wire [7:0] boot_rom_do;
|
||||
boot_rom boot_rom (
|
||||
.addr ( cpu_addr[7:0] ),
|
||||
.clk ( clk_sys ),
|
||||
.data ( boot_rom_do )
|
||||
);
|
||||
|
||||
wire [7:0] fast_boot_rom_do;
|
||||
fast_boot_rom fast_boot_rom (
|
||||
.addr ( cpu_addr[7:0] ),
|
||||
.clk ( clk_sys ),
|
||||
|
||||
@@ -602,6 +602,7 @@ begin
|
||||
when "1111" => -- FF3F 0000 1111 Samples 30 and 31
|
||||
wav_ram(30) <= s1_writedata(7 downto 4);
|
||||
wav_ram(31) <= s1_writedata(3 downto 0);
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
|
||||
@@ -770,6 +771,7 @@ begin
|
||||
s1_readdata <= wav_ram(28) & wav_ram(29);
|
||||
when "1111" => -- FF3F 0000 1111 Samples 30 and 31
|
||||
s1_readdata <= wav_ram(30) & wav_ram(31);
|
||||
when others => null;
|
||||
end case;
|
||||
else
|
||||
s1_readdata <= X"FF";
|
||||
@@ -991,7 +993,7 @@ begin
|
||||
acc_fcnt := ('0' & sq1_fcnt) + to_unsigned(1, acc_fcnt'length);
|
||||
if acc_fcnt(acc_fcnt'high) = '1' then
|
||||
sq1_suppressed <= '0';
|
||||
sq1_phase := sq1_phase + 1;
|
||||
if (sq1_phase < 7) then sq1_phase := sq1_phase + 1; else sq1_phase := 0; end if;
|
||||
sq1_fcnt := unsigned(sq1_freq);
|
||||
sq1_sduty := sq1_duty; -- only change duty after the sample is finished
|
||||
else
|
||||
@@ -1212,7 +1214,7 @@ begin
|
||||
acc_fcnt := ('0' & sq2_fcnt) + to_unsigned(1, acc_fcnt'length);
|
||||
if acc_fcnt(acc_fcnt'high) = '1' then
|
||||
sq2_suppressed <= '0';
|
||||
sq2_phase := sq2_phase + 1;
|
||||
if (sq2_phase < 7) then sq2_phase := sq2_phase + 1; else sq2_phase := 0; end if;
|
||||
sq2_fcnt := unsigned(sq2_freq);
|
||||
sq2_sduty := sq2_duty; -- only change duty after the sample is finished
|
||||
else
|
||||
|
||||
@@ -24,20 +24,19 @@ module link #(
|
||||
output reg sc_int_clock
|
||||
);
|
||||
|
||||
reg [7:0] sb_r = 0;
|
||||
assign sb = sb_r;
|
||||
|
||||
reg [3:0] serial_counter;
|
||||
|
||||
reg [7:0] sb_r = 0;
|
||||
|
||||
reg serial_out_r = 0;
|
||||
assign serial_data_out = serial_out_r;
|
||||
|
||||
reg serial_clk_out_r = 1;
|
||||
assign serial_clk_out = serial_clk_out_r;
|
||||
|
||||
assign serial_irq = serial_irq_r;
|
||||
reg serial_irq_r;
|
||||
assign serial_irq = serial_irq_r;
|
||||
|
||||
reg [8:0] serial_clk_div; //8192Hz
|
||||
|
||||
|
||||
73
rtl/speedcontrol.vhd
Normal file
73
rtl/speedcontrol.vhd
Normal file
@@ -0,0 +1,73 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
entity speedcontrol is
|
||||
port
|
||||
(
|
||||
clk_sys : in std_logic;
|
||||
pause : in std_logic;
|
||||
speedup : in std_logic;
|
||||
cart_act : in std_logic;
|
||||
ce : out std_logic := '0';
|
||||
ce_2x : out std_logic := '0';
|
||||
ceNormal : out std_logic := '0';
|
||||
ce_2xNormal : out std_logic := '0'
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of speedcontrol is
|
||||
|
||||
signal clkdiv : unsigned(2 downto 0) := (others => '0');
|
||||
signal nextdiv : unsigned(2 downto 0) := (others => '0');
|
||||
|
||||
signal clkdivNormal : unsigned(2 downto 0) := (others => '0');
|
||||
|
||||
signal cart_act_1 : std_logic := '0';
|
||||
|
||||
begin
|
||||
|
||||
process(clk_sys)
|
||||
begin
|
||||
if falling_edge(clk_sys) then
|
||||
if (pause = '1') then
|
||||
|
||||
ce <= '0';
|
||||
ce_2x <= '0';
|
||||
ceNormal <= '0';
|
||||
ce_2xNormal <= '0';
|
||||
|
||||
else
|
||||
|
||||
clkdiv <= clkdiv + 1;
|
||||
clkdivNormal <= clkdivNormal + 1;
|
||||
|
||||
-- generation for speed depending on speedup
|
||||
cart_act_1 <= cart_act;
|
||||
|
||||
if (clkdiv = "000") then ce <= '1'; else ce <= '0'; end if;
|
||||
if ((nextdiv = "111" and clkdiv(1 downto 0) = "00") or nextdiv = "001") then ce_2x <= '1'; else ce_2x <= '0'; end if;
|
||||
|
||||
if (clkdiv = nextdiv and (clkdiv = "111" or cart_act = '0')) then
|
||||
clkdiv <= "000";
|
||||
if (speedup = '1') then
|
||||
nextdiv <= "001";
|
||||
else
|
||||
nextdiv <= "111";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if (cart_act = '1' and cart_act_1 = '0') then
|
||||
nextdiv <= "111";
|
||||
end if;
|
||||
|
||||
-- generation for non speed up base, used e.g. for sound hack
|
||||
if (clkdivNormal = "000") then ceNormal <= '1'; else ceNormal <= '0'; end if;
|
||||
if (clkdivNormal(1 downto 0) = "00") then ce_2xNormal <= '1'; else ce_2xNormal <= '0'; end if;
|
||||
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
@@ -56,18 +56,19 @@ module sprites (
|
||||
|
||||
localparam SPRITES_PER_LINE = 10;
|
||||
|
||||
reg [7:0] oam_spr_addr;
|
||||
wire [7:0] oam_fetch_addr;
|
||||
reg [7:0] oam_q;
|
||||
|
||||
wire [7:0] oam_addr = dma_active ? oam_addr_in :
|
||||
oam_eval ? oam_spr_addr :
|
||||
oam_fetch ? oam_fetch_addr :
|
||||
oam_addr_in;
|
||||
|
||||
reg [7:0] oam_spr_addr;
|
||||
|
||||
wire valid_oam_addr = (oam_addr[7:4] < 4'hA); // $FEA0 - $FEFF unused range
|
||||
assign oam_do = dma_active ? 8'hFF : valid_oam_addr ? oam_q : 8'd0;
|
||||
|
||||
reg [7:0] oam_data[0:159];
|
||||
reg [7:0] oam_q;
|
||||
always @(posedge clk) begin
|
||||
if (ce_cpu) begin
|
||||
if(oam_wr && valid_oam_addr) begin
|
||||
@@ -93,6 +94,8 @@ wire sprite_on_line = (v_cnt + 8'd16 >= spr_y) && (v_cnt + 8'd16 < spr_y + spr_h
|
||||
|
||||
assign oam_eval_end = (spr_index == 6'd40);
|
||||
|
||||
wire [0:9] sprite_x_matches;
|
||||
|
||||
reg old_fetch_done;
|
||||
always @(posedge clk) begin
|
||||
if (ce) begin
|
||||
@@ -159,7 +162,7 @@ end
|
||||
|
||||
|
||||
// Sprite fetching
|
||||
wire [0:9] sprite_x_matches = {
|
||||
assign sprite_x_matches = {
|
||||
sprite_x[0] == h_cnt,
|
||||
sprite_x[1] == h_cnt,
|
||||
sprite_x[2] == h_cnt,
|
||||
@@ -192,7 +195,7 @@ wire [5:0] oam_fetch_index = sprite_no[active_sprite];
|
||||
reg [3:0] row;
|
||||
reg [7:0] tile_no;
|
||||
reg oam_fetch_cycle;
|
||||
wire [7:0] oam_fetch_addr = {oam_fetch_index, 1'b1, oam_fetch_cycle};
|
||||
assign oam_fetch_addr = {oam_fetch_index, 1'b1, oam_fetch_cycle};
|
||||
assign sprite_addr = size16 ? {tile_no[7:1],row} : {tile_no,row[2:0]};
|
||||
|
||||
always @(posedge clk) begin
|
||||
|
||||
117
rtl/video.v
117
rtl/video.v
@@ -67,45 +67,18 @@ wire [7:0] sprite_attr;
|
||||
wire [3:0] sprite_index;
|
||||
|
||||
wire oam_eval_end;
|
||||
sprites sprites (
|
||||
.clk ( clk ),
|
||||
.ce ( ce ),
|
||||
.ce_cpu ( ce_cpu ),
|
||||
.size16 ( lcdc_spr_siz ),
|
||||
.isGBC ( isGBC ),
|
||||
.sprite_en( lcdc_spr_ena ),
|
||||
.lcd_on ( lcd_on ),
|
||||
|
||||
.v_cnt ( v_cnt ),
|
||||
.h_cnt ( pcnt ),
|
||||
|
||||
.oam_eval ( oam ),
|
||||
.oam_fetch ( mode3 ),
|
||||
.oam_eval_reset ( end_of_line & ~vblank ),
|
||||
.oam_eval_end ( oam_eval_end ),
|
||||
|
||||
.sprite_fetch (sprite_found),
|
||||
.sprite_addr ( sprite_addr ),
|
||||
.sprite_attr ( sprite_attr ),
|
||||
.sprite_index ( sprite_index ),
|
||||
.sprite_fetch_done ( sprite_fetch_done) ,
|
||||
|
||||
.dma_active ( dma_active),
|
||||
.oam_wr ( oam_wr ),
|
||||
.oam_addr_in( oam_addr ),
|
||||
.oam_di ( oam_di ),
|
||||
.oam_do ( oam_do )
|
||||
);
|
||||
reg dma_active;
|
||||
reg [7:0] dma;
|
||||
reg [9:0] dma_cnt; // dma runs 4*160 clock cycles = 160us @ 4MHz
|
||||
|
||||
// give dma access to oam
|
||||
wire [7:0] oam_addr = dma_active?dma_addr[7:0]:cpu_addr;
|
||||
wire oam_wr = dma_active?(dma_cnt[1:0] == 2):(cpu_wr && cpu_sel_oam && !(mode==3 || mode==2));
|
||||
wire [7:0] oam_di = dma_active?dma_data:cpu_di;
|
||||
|
||||
|
||||
assign lcd_on = lcdc_on;
|
||||
|
||||
// $ff40 LCDC
|
||||
reg [7:0] lcdc;
|
||||
wire lcdc_on = lcdc[7];
|
||||
wire lcdc_win_tile_map_sel = lcdc[6];
|
||||
wire lcdc_win_ena = lcdc[5];
|
||||
@@ -120,7 +93,7 @@ wire lcdc_spr_ena = lcdc[1];
|
||||
wire lcdc_bg_ena = lcdc[0] | (isGBC&&isGBC_game);
|
||||
wire lcdc_bg_prio = lcdc[0];
|
||||
|
||||
reg [7:0] lcdc;
|
||||
assign lcd_on = lcdc_on;
|
||||
|
||||
// ff41 STAT
|
||||
reg [7:0] stat;
|
||||
@@ -130,11 +103,13 @@ reg [7:0] scy;
|
||||
reg [7:0] scx;
|
||||
|
||||
// ff44 line counter
|
||||
reg [8:0] h_cnt; // max 455
|
||||
reg [7:0] v_cnt; // max 153
|
||||
wire [7:0] ly = v_cnt;
|
||||
|
||||
// ff45 line counter compare
|
||||
wire lyc_match = (ly == lyc);
|
||||
reg [7:0] lyc;
|
||||
wire lyc_match = (ly == lyc);
|
||||
|
||||
reg [7:0] bgp;
|
||||
reg [7:0] obp0;
|
||||
@@ -165,9 +140,6 @@ reg[7:0] obpd [63:0]; //64 bytes
|
||||
assign dma_addr = { dma, dma_cnt[9:2] };
|
||||
assign dma_rd = dma_active;
|
||||
|
||||
reg dma_active;
|
||||
reg [7:0] dma;
|
||||
reg [9:0] dma_cnt; // dma runs 4*160 clock cycles = 160us @ 4MHz
|
||||
always @(posedge clk) begin
|
||||
if(reset)
|
||||
dma_active <= 1'b0;
|
||||
@@ -232,6 +204,7 @@ always @(posedge clk) begin
|
||||
end
|
||||
end
|
||||
|
||||
wire pcnt_end;
|
||||
wire mode3_end = isGBC ? pcnt_end : (~sprite_found & pcnt_end);
|
||||
|
||||
reg mode3_end_l;
|
||||
@@ -365,8 +338,10 @@ assign cpu_do =
|
||||
reg skip_en;
|
||||
reg [7:0] skip;
|
||||
reg [7:0] pcnt;
|
||||
wire sprite_fetch_hold;
|
||||
wire bg_shift_empty;
|
||||
|
||||
wire pcnt_end = ( pcnt == (isGBC ? 8'd168 : 8'd167) );
|
||||
assign pcnt_end = ( pcnt == (isGBC ? 8'd168 : 8'd167) );
|
||||
wire pcnt_reset = end_of_line & ~vblank;
|
||||
always @(posedge clk) begin
|
||||
if (!lcd_on) begin
|
||||
@@ -400,9 +375,6 @@ always @(posedge clk) begin
|
||||
end
|
||||
end
|
||||
|
||||
reg [8:0] h_cnt; // max 455
|
||||
reg [7:0] v_cnt; // max 153
|
||||
|
||||
// vcnt_reset goes high a few cycles after v_cnt is incremented to 153.
|
||||
// It resets v_cnt back to 0 and keeps it in reset until the following line.
|
||||
// This results in v_cnt 0 lasting for almost 2 lines.
|
||||
@@ -440,17 +412,21 @@ wire [7:0] bg_col = pcnt + scx;
|
||||
wire [9:0] bg_map_addr = {bg_line[7:3], bg_col[7:3]};
|
||||
|
||||
reg [4:0] win_col;
|
||||
reg [7:0] win_line;
|
||||
wire window_ena;
|
||||
wire bg_fetch_done;
|
||||
wire bg_reload_shift;
|
||||
|
||||
wire [9:0] win_map_addr = {win_line[7:3], win_col[4:0]};
|
||||
|
||||
wire [9:0] bg_tile_map_addr = window_ena ? win_map_addr : bg_map_addr;
|
||||
|
||||
reg [7:0] win_line;
|
||||
wire [2:0] tile_line = window_ena ? win_line[2:0] : bg_line[2:0];
|
||||
|
||||
reg window_match, window_ena_d;
|
||||
|
||||
wire win_start = mode3 && lcdc_win_ena && ~sprite_fetch_hold && ~skip_en && ~bg_shift_empty && (v_cnt >= wy) && (pcnt == wx) && (wx < 8'hA7);
|
||||
wire window_ena = window_match & ~pcnt_reset & lcdc_win_ena;
|
||||
assign window_ena = window_match & ~pcnt_reset & lcdc_win_ena;
|
||||
|
||||
always @(posedge clk) begin
|
||||
|
||||
@@ -491,7 +467,6 @@ always @(posedge clk) begin
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------- bg, window and sprite fetch -------------------
|
||||
// --------------------------------------------------------------------
|
||||
@@ -531,15 +506,15 @@ wire [7:0] bg_vram_data_in = (isGBC & isGBC_game & bg_tile_attr_new[5]) ? bit_re
|
||||
reg [2:0] bg_fetch_cycle;
|
||||
reg [2:0] sprite_fetch_cycle;
|
||||
|
||||
wire bg_fetch_done = (bg_fetch_cycle >= 3'd5);
|
||||
assign bg_fetch_done = (bg_fetch_cycle >= 3'd5);
|
||||
wire sprite_fetch_done = (sprite_fetch_hold && sprite_fetch_cycle >= 3'd5);
|
||||
|
||||
// The first B01 cycle does not fetch sprites so wait until the bg shift register is not empty
|
||||
wire sprite_fetch_hold = sprite_found & ~bg_shift_empty;
|
||||
assign sprite_fetch_hold = sprite_found & ~bg_shift_empty;
|
||||
|
||||
reg [3:0] bg_shift_cnt;
|
||||
wire bg_shift_empty = (bg_shift_cnt == 0);
|
||||
wire bg_reload_shift = (bg_shift_cnt <= 1);
|
||||
assign bg_shift_empty = (bg_shift_cnt == 0);
|
||||
assign bg_reload_shift = (bg_shift_cnt <= 1);
|
||||
|
||||
wire spr_prio = sprite_attr[7];
|
||||
wire spr_attr_h_flip = sprite_attr[5];
|
||||
@@ -566,6 +541,13 @@ wire [7:0] spr_cgb_index_prio = spr_cgb_prio(spr_cgb_index_shift[3], spr_cgb_ind
|
||||
// CGB will mask the old pixel to 0 if the new pixel has higher priority.
|
||||
wire [7:0] spr_tile_mask = (spr_tile_shift_0 | spr_tile_shift_1) & ((isGBC & isGBC_game) ? ~spr_cgb_index_prio : 8'hFF);
|
||||
|
||||
// cycle through the B01s states
|
||||
wire bg_tile_map_rd = (mode3 && bg_fetch_cycle[2:1] == 2'b00);
|
||||
wire bg_tile_data0_rd = (mode3 && bg_fetch_cycle[2:1] == 2'b01);
|
||||
wire bg_tile_data1_rd = (mode3 && bg_fetch_cycle[2:1] == 2'b10);
|
||||
wire bg_tile_obj0_rd = (mode3 && sprite_fetch_cycle[2:1] == 2'b01);
|
||||
wire bg_tile_obj1_rd = (mode3 && sprite_fetch_cycle[2:1] == 2'b10);
|
||||
|
||||
always @(posedge clk) begin
|
||||
|
||||
if (ce) begin
|
||||
@@ -656,13 +638,6 @@ always @(posedge clk) begin
|
||||
|
||||
end
|
||||
|
||||
// cycle through the B01s states
|
||||
wire bg_tile_map_rd = (mode3 && bg_fetch_cycle[2:1] == 2'b00);
|
||||
wire bg_tile_data0_rd = (mode3 && bg_fetch_cycle[2:1] == 2'b01);
|
||||
wire bg_tile_data1_rd = (mode3 && bg_fetch_cycle[2:1] == 2'b10);
|
||||
wire bg_tile_obj0_rd = (mode3 && sprite_fetch_cycle[2:1] == 2'b01);
|
||||
wire bg_tile_obj1_rd = (mode3 && sprite_fetch_cycle[2:1] == 2'b10);
|
||||
|
||||
assign vram_rd = lcdc_on && (bg_tile_map_rd || bg_tile_data0_rd ||
|
||||
bg_tile_data1_rd || bg_tile_obj0_rd || bg_tile_obj1_rd);
|
||||
|
||||
@@ -680,6 +655,36 @@ assign vram_addr =
|
||||
bg_tile_obj0_rd ? {1'b0, sprite_addr, 1'b0} :
|
||||
{1'b0, sprite_addr, 1'b1};
|
||||
|
||||
sprites sprites (
|
||||
.clk ( clk ),
|
||||
.ce ( ce ),
|
||||
.ce_cpu ( ce_cpu ),
|
||||
.size16 ( lcdc_spr_siz ),
|
||||
.isGBC ( isGBC ),
|
||||
.sprite_en( lcdc_spr_ena ),
|
||||
.lcd_on ( lcd_on ),
|
||||
|
||||
.v_cnt ( v_cnt ),
|
||||
.h_cnt ( pcnt ),
|
||||
|
||||
.oam_eval ( oam ),
|
||||
.oam_fetch ( mode3 ),
|
||||
.oam_eval_reset ( end_of_line & ~vblank ),
|
||||
.oam_eval_end ( oam_eval_end ),
|
||||
|
||||
.sprite_fetch (sprite_found),
|
||||
.sprite_addr ( sprite_addr ),
|
||||
.sprite_attr ( sprite_attr ),
|
||||
.sprite_index ( sprite_index ),
|
||||
.sprite_fetch_done ( sprite_fetch_done) ,
|
||||
|
||||
.dma_active ( dma_active),
|
||||
.oam_wr ( oam_wr ),
|
||||
.oam_addr_in( oam_addr ),
|
||||
.oam_di ( oam_di ),
|
||||
.oam_do ( oam_do )
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ----------------------- lcd output stage -------------------------
|
||||
// --------------------------------------------------------------------
|
||||
@@ -693,6 +698,8 @@ reg sprite_pixel_visible;
|
||||
wire [1:0] sprite_pixel_data = {spr_tile_shift_1[7], spr_tile_shift_0[7]};
|
||||
wire sprite_pixel_prio = spr_prio_shift[7];
|
||||
|
||||
wire [1:0] bg_pix_data = { tile_shift_1[7], tile_shift_0[7] };
|
||||
|
||||
always @(*) begin
|
||||
sprite_pixel_visible = 1'b0;
|
||||
if (|sprite_pixel_data && lcdc_spr_ena) begin // pixel active and sprites enabled
|
||||
@@ -722,8 +729,6 @@ always @(*) begin
|
||||
|
||||
end
|
||||
|
||||
wire [1:0] bg_pix_data = { tile_shift_1[7], tile_shift_0[7] };
|
||||
|
||||
// If lcdc_bg_ena is off in Non-GBC mode then both background and window are blank. (BG color 0)
|
||||
wire [1:0] bgp_data = (!lcdc_bg_ena || bg_pix_data == 2'b00) ? bgp[1:0] :
|
||||
(bg_pix_data == 2'b01) ? bgp[3:2] :
|
||||
|
||||
BIN
sim/graeval.exe
Normal file
BIN
sim/graeval.exe
Normal file
Binary file not shown.
48
sim/readme.md
Normal file
48
sim/readme.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Purpose of this document
|
||||
|
||||
This readme shall deliver a small introduction on what the simulation can be used for and how to simulate the GB core.
|
||||
|
||||
Requirements: Modelsim or compatible Simulator. Windows 7/10 for viewing gpu output.
|
||||
Tested Version: Modelsim 10.5
|
||||
|
||||
# Available features
|
||||
|
||||
The simulation framework allows:
|
||||
- running ROM like on real hardware
|
||||
|
||||
Debugging options:
|
||||
- waveform viewer in modelsim
|
||||
- live graphical output
|
||||
|
||||
Speed:
|
||||
1 second realtime(FPGA) will take in the range of 5 Minutes in simulation. So don't expect to run deep into a game.
|
||||
|
||||
# Shortcoming
|
||||
|
||||
- The HPS Framework/Top level is not simulated at all, Cart download is done through a debug interface
|
||||
- Sound cannot be checked other than viewing waveform
|
||||
|
||||
# How to start
|
||||
|
||||
- run sim/vmap_all.bat
|
||||
- run sim/vcom_all.bat
|
||||
- run sim/vsim_start.bat
|
||||
|
||||
Simualtion will now open.
|
||||
- Start it with "Run All" button or command
|
||||
- go with a cmd tool into sim/tests
|
||||
- run "lua gb_bootrom.lua"
|
||||
|
||||
Test is now running. Watch command line or waveform.
|
||||
|
||||
# Debug graphic
|
||||
|
||||
In the sim folder, there is a "graeval.exe"
|
||||
When the simulation has run for a while and the file "gra_fb_out.gra" exists and the size is not zero,
|
||||
you can pull this file onto the graeval.exe
|
||||
A new window will open and draw everything the core outputs in simulation.
|
||||
|
||||
# How to simulate a specific ROM
|
||||
|
||||
Change the path to the ROM in the luascript "sim/tests/gb_bootrom.lua"
|
||||
As the script and the simulator run in different paths, you may have to change the path or copy the file locally.
|
||||
15
sim/src/gameboy/cheatcodes.sv
Normal file
15
sim/src/gameboy/cheatcodes.sv
Normal file
@@ -0,0 +1,15 @@
|
||||
module CODES(
|
||||
input clk,
|
||||
input reset,
|
||||
input enable,
|
||||
output available,
|
||||
input [15:0] addr_in,
|
||||
input [7:0] data_in,
|
||||
input [128:0] code,
|
||||
output genie_ovr,
|
||||
output [7:0] genie_data
|
||||
);
|
||||
|
||||
assign genie_ovr = 0;
|
||||
|
||||
endmodule
|
||||
87
sim/src/mem/SyncFifo.vhd
Normal file
87
sim/src/mem/SyncFifo.vhd
Normal file
@@ -0,0 +1,87 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity SyncFifo is
|
||||
generic
|
||||
(
|
||||
SIZE : integer;
|
||||
DATAWIDTH : integer;
|
||||
NEARFULLDISTANCE : integer
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
Din : in std_logic_vector(DATAWIDTH - 1 downto 0);
|
||||
Wr : in std_logic;
|
||||
Full : out std_logic;
|
||||
NearFull : out std_logic;
|
||||
|
||||
Dout : out std_logic_vector(DATAWIDTH - 1 downto 0);
|
||||
Rd : in std_logic;
|
||||
Empty : out std_logic
|
||||
);
|
||||
end SyncFifo;
|
||||
|
||||
architecture arch of SyncFifo is
|
||||
|
||||
constant SIZEBITS : integer := integer(ceil(log2(real(SIZE))));
|
||||
|
||||
type t_memory is array(0 to SIZE - 1) of std_logic_vector(DATAWIDTH - 1 downto 0);
|
||||
signal memory : t_memory;
|
||||
|
||||
signal wrcnt : unsigned(SIZEBITS - 1 downto 0) := (others => '0');
|
||||
signal rdcnt : unsigned(SIZEBITS - 1 downto 0) := (others => '0');
|
||||
|
||||
signal fifocnt : unsigned(SIZEBITS - 1 downto 0) := (others => '0');
|
||||
|
||||
signal full_wire : std_logic;
|
||||
signal empty_wire : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
full_wire <= '1' when rdcnt = wrcnt+1 else '0';
|
||||
empty_wire <= '1' when rdcnt = wrcnt else '0';
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if (reset = '1') then
|
||||
wrcnt <= (others => '0');
|
||||
rdcnt <= (others => '0');
|
||||
fifocnt <= (others => '0');
|
||||
else
|
||||
if (Wr = '1' and full_wire = '0') then
|
||||
if (Rd = '0' or empty_wire = '1') then
|
||||
fifocnt <= fifocnt + 1;
|
||||
end if;
|
||||
elsif (Rd = '1' and empty_wire = '0') then
|
||||
fifocnt <= fifocnt - 1;
|
||||
end if;
|
||||
|
||||
if (fifocnt < NEARFULLDISTANCE) then
|
||||
NearFull <= '0';
|
||||
else
|
||||
NearFull <= '1';
|
||||
end if;
|
||||
|
||||
if (Wr = '1' and full_wire = '0') then
|
||||
memory(to_integer(wrcnt)) <= Din;
|
||||
wrcnt <= wrcnt+1;
|
||||
end if;
|
||||
|
||||
if (Rd = '1' and empty_wire = '0') then
|
||||
Dout <= memory(to_integer(rdcnt));
|
||||
rdcnt <= rdcnt+1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
Full <= full_wire;
|
||||
Empty <= empty_wire;
|
||||
|
||||
end architecture;
|
||||
277
sim/src/procbus/proc_bus.vhd
Normal file
277
sim/src/procbus/proc_bus.vhd
Normal file
@@ -0,0 +1,277 @@
|
||||
-----------------------------------------------------------------
|
||||
--------------- Proc Bus Package --------------------------------
|
||||
-----------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
package pProc_bus is
|
||||
|
||||
constant proc_buswidth : integer := 32;
|
||||
constant proc_busadr : integer := 26;
|
||||
|
||||
constant proc_buscount : integer := 15;
|
||||
|
||||
constant proc_mpu_bits : integer := 16;
|
||||
|
||||
type proc_bus_type is record
|
||||
Din : std_logic_vector(proc_buswidth-1 downto 0);
|
||||
Dout : std_logic_vector(proc_buswidth-1 downto 0);
|
||||
Adr : std_logic_vector(proc_busadr-1 downto 0);
|
||||
rnw : std_logic;
|
||||
ena : std_logic;
|
||||
done : std_logic;
|
||||
end record;
|
||||
|
||||
type tBusArray_Din is array(0 to proc_buscount - 1) of std_logic_vector(proc_buswidth-1 downto 0);
|
||||
type tBusArray_Dout is array(0 to proc_buscount - 1) of std_logic_vector(proc_buswidth-1 downto 0);
|
||||
type tBusArray_Adr is array(0 to proc_buscount - 1) of std_logic_vector(proc_busadr-1 downto 0);
|
||||
type tBusArray_rnw is array(0 to proc_buscount - 1) of std_logic;
|
||||
type tBusArray_ena is array(0 to proc_buscount - 1) of std_logic;
|
||||
type tBusArray_done is array(0 to proc_buscount - 1) of std_logic;
|
||||
|
||||
type tMPUArray is array(0 to proc_buscount - 1) of std_logic_vector(proc_mpu_bits-1 downto 0);
|
||||
|
||||
end package;
|
||||
|
||||
|
||||
-----------------------------------------------------------------
|
||||
--------------- Reg Map Package --------------------------------
|
||||
-----------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.pProc_bus.all;
|
||||
|
||||
package pRegmap is
|
||||
|
||||
type regaccess_type is
|
||||
(
|
||||
readwrite,
|
||||
readonly,
|
||||
pulse,
|
||||
writeonly
|
||||
);
|
||||
|
||||
type regmap_type is record
|
||||
Adr : integer range 0 to (2**proc_busadr)-1;
|
||||
upper : integer range 0 to proc_buswidth-1;
|
||||
lower : integer range 0 to proc_buswidth-1;
|
||||
size : integer range 0 to (2**proc_busadr)-1;
|
||||
default : integer;
|
||||
acccesstype : regaccess_type;
|
||||
end record;
|
||||
|
||||
end package;
|
||||
|
||||
|
||||
-----------------------------------------------------------------
|
||||
--------------- Converter Bus -> Processor ----------------------
|
||||
-----------------------------------------------------------------
|
||||
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.pProc_bus.all;
|
||||
|
||||
entity eProc_bus is
|
||||
port
|
||||
(
|
||||
proc_din : out std_logic_vector(proc_buswidth-1 downto 0);
|
||||
proc_dout : in std_logic_vector(proc_buswidth-1 downto 0);
|
||||
proc_adr : in std_logic_vector(proc_busadr-1 downto 0);
|
||||
proc_rnw : in std_logic;
|
||||
proc_ena : in std_logic;
|
||||
proc_done : out std_logic;
|
||||
|
||||
proc_bus : inout proc_bus_type := ((others => 'Z'), (others => 'Z'), (others => 'Z'), 'Z', 'Z', 'Z')
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of eProc_bus is
|
||||
|
||||
begin
|
||||
|
||||
proc_din <= proc_bus.Dout;
|
||||
proc_done <= proc_bus.done;
|
||||
|
||||
proc_bus.adr <= proc_adr;
|
||||
proc_bus.rnw <= proc_rnw;
|
||||
proc_bus.ena <= proc_ena;
|
||||
proc_bus.Din <= proc_dout;
|
||||
|
||||
-- prevent simulation warnings
|
||||
proc_bus.Dout <= (others => 'Z');
|
||||
|
||||
end architecture;
|
||||
|
||||
-----------------------------------------------------------------
|
||||
--------------- Reg Interface -----------------------------------
|
||||
-----------------------------------------------------------------
|
||||
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.pProc_bus.all;
|
||||
use work.pRegmap.all;
|
||||
|
||||
entity eProcReg is
|
||||
generic
|
||||
(
|
||||
Reg : regmap_type;
|
||||
index : integer := 0
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
proc_bus : inout proc_bus_type := ((others => 'Z'), (others => 'Z'), (others => 'Z'), 'Z', 'Z', 'Z');
|
||||
Din : in std_logic_vector(Reg.upper downto Reg.lower);
|
||||
Dout : out std_logic_vector(Reg.upper downto Reg.lower);
|
||||
written : out std_logic := '0'
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of eProcReg is
|
||||
|
||||
signal Dout_buffer : std_logic_vector(Reg.upper downto Reg.lower) := std_logic_vector(to_unsigned(Reg.default,Reg.upper-Reg.lower+1));
|
||||
|
||||
signal Adr : std_logic_vector(proc_bus.adr'left downto 0);
|
||||
|
||||
begin
|
||||
|
||||
Adr <= std_logic_vector(to_unsigned(Reg.Adr + index, proc_bus.adr'length));
|
||||
|
||||
greadwrite : if (Reg.acccesstype = readwrite or Reg.acccesstype = writeonly) generate
|
||||
begin
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
if (proc_bus.Adr = Adr and proc_bus.rnw = '0' and proc_bus.ena = '1') then
|
||||
Dout_buffer <= proc_bus.Din(Reg.upper downto Reg.lower);
|
||||
written <= '1';
|
||||
else
|
||||
written <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
gpulse : if (Reg.acccesstype = pulse) generate
|
||||
begin
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
Dout_buffer <= (others => '0');
|
||||
if (proc_bus.Adr = Adr and proc_bus.rnw = '0' and proc_bus.ena = '1') then
|
||||
Dout_buffer <= proc_bus.Din(Reg.upper downto Reg.lower);
|
||||
written <= '1';
|
||||
else
|
||||
written <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
Dout <= Dout_buffer;
|
||||
|
||||
proc_bus.Dout <= (others => 'Z');
|
||||
|
||||
goutput : if (Reg.acccesstype = readwrite or Reg.acccesstype = readonly) generate
|
||||
begin
|
||||
proc_bus.Dout(Reg.upper downto Reg.lower) <= Din when proc_bus.Adr = Adr else (others => 'Z');
|
||||
end generate;
|
||||
|
||||
proc_bus.done <= '1' when proc_bus.Adr = Adr else 'Z';
|
||||
|
||||
-- prevent simulation warnings
|
||||
proc_bus.Adr <= (others => 'Z');
|
||||
proc_bus.Din <= (others => 'Z');
|
||||
proc_bus.rnw <= 'Z';
|
||||
|
||||
|
||||
end architecture;
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------
|
||||
--------------- Address enable ---------------------------------
|
||||
-----------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.pProc_bus.all;
|
||||
use work.pRegmap.all;
|
||||
|
||||
entity eProcAddrEna is
|
||||
generic
|
||||
(
|
||||
Reg : regmap_type
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
proc_bus : inout proc_bus_type := ((others => 'Z'), (others => 'Z'), (others => 'Z'), 'Z', 'Z', 'Z');
|
||||
ena : out std_logic;
|
||||
addr : out std_logic_vector(proc_busadr-1 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of eProcAddrEna is
|
||||
|
||||
signal proc_adr_buf :std_logic_vector(proc_busadr-1 downto 0) := (others => '0');
|
||||
|
||||
signal calc_addr : std_logic_vector(proc_busadr-1 downto 0);
|
||||
signal calc_ena : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
|
||||
|
||||
calc_addr <= std_logic_vector(unsigned(proc_adr_buf) - to_unsigned(Reg.Adr, proc_busadr));
|
||||
calc_ena <= '1' when to_integer(unsigned(proc_adr_buf)) >= Reg.Adr and to_integer(unsigned(proc_adr_buf)) < (Reg.Adr + Reg.size) else '0';
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
proc_adr_buf <= proc_bus.Adr;
|
||||
|
||||
if (to_integer(unsigned(calc_addr)) < Reg.size) then
|
||||
addr <= calc_addr;
|
||||
else
|
||||
addr <= (others => '0');
|
||||
end if;
|
||||
|
||||
ena <= calc_ena;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
|
||||
end architecture;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
386
sim/src/procbus/testprocessor.vhd
Normal file
386
sim/src/procbus/testprocessor.vhd
Normal file
@@ -0,0 +1,386 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library rs232;
|
||||
library mem;
|
||||
|
||||
library procbus;
|
||||
use procbus.pProc_bus.all;
|
||||
|
||||
entity eTestprocessor is
|
||||
generic
|
||||
(
|
||||
clk_speed : integer := 50000000;
|
||||
baud : integer := 115200;
|
||||
is_simu : std_logic := '0'
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
bootloader : in std_logic;
|
||||
debugaccess : in std_logic;
|
||||
command_in : in std_logic;
|
||||
command_out : out std_logic;
|
||||
|
||||
proc_bus : inout proc_bus_type := ((others => 'Z'), (others => 'Z'), (others => 'Z'), 'Z', 'Z', 'Z');
|
||||
|
||||
fifo_full_error : out std_logic;
|
||||
timeout_error : buffer std_logic := '0'
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of eTestprocessor is
|
||||
|
||||
type tState is
|
||||
(
|
||||
START,
|
||||
BOOTLOADER_READ,
|
||||
BOOTLOADER_READWAIT,
|
||||
BOOTLOADER_WRITEWAIT,
|
||||
BOTLOADER_WRITE_START,
|
||||
DEBUGIDLE,
|
||||
RECEIVELENGTH,
|
||||
BLOCKWRITE,
|
||||
BLOCKWRITE_WAIT,
|
||||
BLOCKREAD_READ,
|
||||
BLOCKREAD_WAIT,
|
||||
BLOCKREAD_SEND
|
||||
);
|
||||
signal state : tState := START;
|
||||
|
||||
signal startcounter : integer range 0 to 100000001 := 0;
|
||||
|
||||
signal boot_read_addr : unsigned(proc_busadr - 1 downto 0) := to_unsigned(2097152, proc_busadr); -- flash
|
||||
signal boot_write_addr : unsigned(proc_busadr - 1 downto 0) := to_unsigned(524288, proc_busadr); -- sram
|
||||
signal boot_cnt : integer range 0 to 65535 := 0;
|
||||
|
||||
signal receive_command : std_logic_vector(31 downto 0);
|
||||
signal receive_byte_nr : integer range 0 to 4 := 0;
|
||||
|
||||
signal rx_valid : std_logic;
|
||||
signal rx_byte : std_logic_vector(7 downto 0);
|
||||
|
||||
signal transmit_command : std_logic_vector(31 downto 0);
|
||||
signal transmit_byte_nr : integer range 0 to 4 := 4;
|
||||
signal sendbyte : std_logic_vector(7 downto 0) := (others => '0');
|
||||
signal tx_enable : std_logic := '0';
|
||||
signal tx_busy : std_logic;
|
||||
|
||||
signal proc_din : std_logic_vector(31 downto 0);
|
||||
signal proc_dout : std_logic_vector(31 downto 0) := (others => '0');
|
||||
signal proc_adr : std_logic_vector(proc_busadr - 1 downto 0) := (others => '0');
|
||||
signal proc_rnw : std_logic := '0';
|
||||
signal proc_ena : std_logic := '0';
|
||||
signal proc_done : std_logic;
|
||||
|
||||
signal blocklength_m1 : integer range 0 to 255 := 0;
|
||||
signal workcount : integer range 0 to 255 := 0;
|
||||
signal addr_buffer : std_logic_vector(proc_busadr - 1 downto 0) := (others => '0');
|
||||
|
||||
signal Fifo_writena : std_logic;
|
||||
signal Fifo_full : std_logic;
|
||||
signal Fifo_Dout : std_logic_vector(7 downto 0);
|
||||
signal Fifo_Rd : std_logic := '0';
|
||||
signal Fifo_Empty : std_logic;
|
||||
signal Fifo_valid : std_logic;
|
||||
|
||||
constant TIMEOUTVALUE : integer := 100000000;
|
||||
signal timeout : integer range 0 to TIMEOUTVALUE := 0;
|
||||
|
||||
|
||||
begin
|
||||
|
||||
iProc_bus : entity procbus.eProc_bus
|
||||
port map
|
||||
(
|
||||
proc_din => proc_din,
|
||||
proc_dout => proc_dout,
|
||||
proc_adr => proc_adr,
|
||||
proc_rnw => proc_rnw,
|
||||
proc_ena => proc_ena,
|
||||
proc_done => proc_done,
|
||||
proc_bus => proc_bus
|
||||
);
|
||||
|
||||
iReceiveFifo : entity mem.SyncFifo
|
||||
generic map
|
||||
(
|
||||
SIZE => 1024,
|
||||
DATAWIDTH => 8,
|
||||
NEARFULLDISTANCE => 128
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
reset => timeout_error,
|
||||
|
||||
Din => rx_byte,
|
||||
Wr => Fifo_writena,
|
||||
Full => Fifo_full,
|
||||
NearFull => open,
|
||||
|
||||
Dout => Fifo_Dout,
|
||||
Rd => Fifo_Rd,
|
||||
Empty => Fifo_Empty
|
||||
);
|
||||
|
||||
Fifo_writena <= rx_valid and (debugaccess or is_simu);
|
||||
fifo_full_error <= Fifo_full;
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
proc_ena <= '0';
|
||||
tx_enable <= '0';
|
||||
timeout_error <= '0';
|
||||
|
||||
Fifo_valid <= Fifo_rd;
|
||||
Fifo_rd <= '0';
|
||||
if (Fifo_Empty = '0' and Fifo_rd = '0' and Fifo_valid = '0' and (state = DEBUGIDLE or state = RECEIVELENGTH or state = BLOCKWRITE)) then
|
||||
Fifo_rd <= '1';
|
||||
end if;
|
||||
|
||||
if (timeout < TIMEOUTVALUE) then
|
||||
timeout <= timeout + 1;
|
||||
end if;
|
||||
|
||||
case state is
|
||||
|
||||
when START =>
|
||||
startcounter <= startcounter + 1;
|
||||
--if ((is_simu = '0' and startcounter = 100000000) or (is_simu = '1' and startcounter = 10000)) then
|
||||
if ((is_simu = '0' and startcounter = 100000000) or (is_simu = '1' and startcounter = 1)) then
|
||||
if (bootloader = '1') then
|
||||
state <= BOOTLOADER_READ;
|
||||
else
|
||||
state <= DEBUGIDLE;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when BOOTLOADER_READ =>
|
||||
proc_adr <= std_logic_vector(boot_read_addr);
|
||||
proc_rnw <= '1';
|
||||
proc_ena <= '1';
|
||||
state <= BOOTLOADER_READWAIT;
|
||||
boot_read_addr <= boot_read_addr + 1;
|
||||
|
||||
when BOOTLOADER_READWAIT =>
|
||||
if (proc_done = '1') then
|
||||
proc_dout <= proc_din;
|
||||
proc_adr <= std_logic_vector(boot_write_addr);
|
||||
proc_rnw <= '0';
|
||||
proc_ena <= '1';
|
||||
state <= BOOTLOADER_WRITEWAIT;
|
||||
boot_write_addr <= boot_write_addr + 1;
|
||||
end if;
|
||||
|
||||
when BOOTLOADER_WRITEWAIT =>
|
||||
if (proc_done = '1') then
|
||||
boot_cnt <= boot_cnt + 1;
|
||||
if ((is_simu = '0' and boot_cnt = 32767) or (is_simu = '1' and boot_cnt = 127)) then
|
||||
proc_dout <= x"00080000";
|
||||
proc_adr <= std_logic_vector(to_unsigned(1152, proc_busadr)); -- core addr
|
||||
proc_rnw <= '0';
|
||||
proc_ena <= '1';
|
||||
state <= BOTLOADER_WRITE_START;
|
||||
else
|
||||
state <= BOOTLOADER_READ;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when BOTLOADER_WRITE_START =>
|
||||
if (proc_done = '1') then
|
||||
proc_dout <= x"00000001";
|
||||
proc_adr <= std_logic_vector(to_unsigned(1024, proc_busadr)); -- core enable
|
||||
proc_rnw <= '0';
|
||||
proc_ena <= '1';
|
||||
state <= DEBUGIDLE;
|
||||
end if;
|
||||
|
||||
|
||||
-- receive register command
|
||||
when DEBUGIDLE =>
|
||||
blocklength_m1 <= 0;
|
||||
workcount <= 0;
|
||||
timeout <= 0;
|
||||
|
||||
if (Fifo_valid = '1') then
|
||||
receive_command((receive_byte_nr*8)+7 downto (receive_byte_nr*8)) <= Fifo_Dout;
|
||||
if (receive_byte_nr < 3) then
|
||||
receive_byte_nr <= receive_byte_nr + 1;
|
||||
else
|
||||
receive_byte_nr <= 0;
|
||||
addr_buffer <= Fifo_Dout(1 downto 0) & receive_command(23 downto 0);
|
||||
proc_rnw <= Fifo_Dout(6);
|
||||
|
||||
if (Fifo_Dout(7) = '0') then -- non block mode
|
||||
if (Fifo_Dout(6) = '1') then
|
||||
state <= BLOCKREAD_READ;
|
||||
else
|
||||
state <= BLOCKWRITE;
|
||||
end if;
|
||||
else -- block mode
|
||||
state <= RECEIVELENGTH;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when RECEIVELENGTH =>
|
||||
if (timeout = TIMEOUTVALUE) then
|
||||
state <= DEBUGIDLE;
|
||||
timeout_error <= '1';
|
||||
end if;
|
||||
|
||||
if (Fifo_valid = '1') then
|
||||
blocklength_m1 <= to_integer(unsigned(Fifo_Dout));
|
||||
if (receive_command(30) = '1') then
|
||||
state <= BLOCKREAD_READ;
|
||||
else
|
||||
state <= BLOCKWRITE;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- write
|
||||
when BLOCKWRITE =>
|
||||
if (timeout = TIMEOUTVALUE) then
|
||||
state <= DEBUGIDLE;
|
||||
timeout_error <= '1';
|
||||
end if;
|
||||
|
||||
if (Fifo_valid = '1') then
|
||||
receive_command((receive_byte_nr*8)+7 downto (receive_byte_nr*8)) <= Fifo_Dout;
|
||||
if (receive_byte_nr < 3) then
|
||||
receive_byte_nr <= receive_byte_nr + 1;
|
||||
else
|
||||
receive_byte_nr <= 0;
|
||||
proc_adr <= addr_buffer;
|
||||
proc_dout <= Fifo_Dout & receive_command(23 downto 0);
|
||||
proc_ena <= '1';
|
||||
addr_buffer <= std_logic_vector(unsigned(addr_buffer) + 1);
|
||||
state <= BLOCKWRITE_WAIT;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when BLOCKWRITE_WAIT =>
|
||||
if (timeout = TIMEOUTVALUE) then
|
||||
state <= DEBUGIDLE;
|
||||
timeout_error <= '1';
|
||||
end if;
|
||||
|
||||
if (proc_done = '1') then
|
||||
if (workcount >= blocklength_m1) then
|
||||
state <= DEBUGIDLE;
|
||||
else
|
||||
workcount <= workcount + 1;
|
||||
state <= BLOCKWRITE;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read
|
||||
when BLOCKREAD_READ =>
|
||||
proc_adr <= addr_buffer;
|
||||
proc_ena <= '1';
|
||||
addr_buffer <= std_logic_vector(unsigned(addr_buffer) + 1);
|
||||
state <= BLOCKREAD_WAIT;
|
||||
|
||||
when BLOCKREAD_WAIT =>
|
||||
if (timeout = TIMEOUTVALUE) then
|
||||
state <= DEBUGIDLE;
|
||||
timeout_error <= '1';
|
||||
end if;
|
||||
|
||||
if (proc_done = '1') then
|
||||
transmit_command <= proc_din;
|
||||
transmit_byte_nr <= 0;
|
||||
state <= BLOCKREAD_SEND;
|
||||
end if;
|
||||
|
||||
when BLOCKREAD_SEND =>
|
||||
if (timeout = TIMEOUTVALUE) then
|
||||
state <= DEBUGIDLE;
|
||||
timeout_error <= '1';
|
||||
end if;
|
||||
|
||||
if (tx_busy = '0') then
|
||||
transmit_byte_nr <= transmit_byte_nr + 1;
|
||||
sendbyte <= transmit_command((transmit_byte_nr*8)+7 downto (transmit_byte_nr*8));
|
||||
tx_enable <= '1';
|
||||
if (transmit_byte_nr = 3) then
|
||||
if (workcount >= blocklength_m1) then
|
||||
state <= DEBUGIDLE;
|
||||
else
|
||||
workcount <= workcount + 1;
|
||||
state <= BLOCKREAD_READ;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end case;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
gtestbench : if (is_simu = '1') generate
|
||||
begin
|
||||
|
||||
itbrs232_receiver : entity rs232.tbrs232_receiver
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
rx_byte => rx_byte,
|
||||
valid => rx_valid,
|
||||
rx => command_in
|
||||
);
|
||||
|
||||
itbrs232_transmitter : entity rs232.tbrs232_transmitter
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
busy => tx_busy,
|
||||
sendbyte => sendbyte,
|
||||
enable => tx_enable,
|
||||
tx => command_out
|
||||
);
|
||||
|
||||
|
||||
end generate;
|
||||
|
||||
gsynthesis : if (is_simu = '0') generate
|
||||
begin
|
||||
|
||||
irs232_receiver : entity rs232.rs232_receiver
|
||||
generic map
|
||||
(
|
||||
clk_speed => clk_speed,
|
||||
baud => baud
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
rx_byte => rx_byte,
|
||||
valid => rx_valid,
|
||||
rx => command_in
|
||||
);
|
||||
|
||||
irs232_transmitter : entity rs232.rs232_transmitter
|
||||
generic map
|
||||
(
|
||||
clk_speed => clk_speed,
|
||||
baud => baud
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
busy => tx_busy,
|
||||
sendbyte => sendbyte,
|
||||
enable => tx_enable,
|
||||
tx => command_out
|
||||
);
|
||||
|
||||
end generate;
|
||||
|
||||
|
||||
end architecture;
|
||||
|
||||
70
sim/src/reg_map/reg_gameboy.vhd
Normal file
70
sim/src/reg_map/reg_gameboy.vhd
Normal file
@@ -0,0 +1,70 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library procbus;
|
||||
use procbus.pProc_bus.all;
|
||||
use procbus.pRegmap.all;
|
||||
|
||||
package pReg_gameboy is
|
||||
|
||||
-- range 1048576 .. 2097151
|
||||
-- adr upper lower size default accesstype)
|
||||
constant Reg_GB_on : regmap_type := (1056768, 0, 0, 1, 0, readwrite); -- on = 1
|
||||
|
||||
constant Reg_GB_lockspeed : regmap_type := (1056769, 0, 0, 1, 0, readwrite); -- 1 = 100% speed
|
||||
|
||||
constant Reg_GB_flash_1m : regmap_type := (1056770, 0, 0, 1, 0, readwrite);
|
||||
|
||||
constant Reg_GB_CyclePrecalc : regmap_type := (1056771, 15, 0, 1, 100, readwrite);
|
||||
constant Reg_GB_CyclesMissing : regmap_type := (1056772, 31, 0, 1, 0, readonly);
|
||||
|
||||
constant Reg_GB_BusAddr : regmap_type := (1056773, 27, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_BusRnW : regmap_type := (1056773, 28, 28, 1, 0, readwrite);
|
||||
constant Reg_GB_BusACC : regmap_type := (1056773, 30, 29, 1, 0, readwrite);
|
||||
constant Reg_GB_BusWriteData : regmap_type := (1056774, 31, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_BusReadData : regmap_type := (1056775, 31, 0, 1, 0, readonly);
|
||||
|
||||
constant Reg_GB_MaxPakAddr : regmap_type := (1056776, 24, 0, 1, 0, readwrite);
|
||||
|
||||
constant Reg_GB_VsyncSpeed : regmap_type := (1056777, 31, 0, 1, 0, readwrite);
|
||||
|
||||
-- joypad
|
||||
constant Reg_GB_KeyUp : regmap_type := (1056778, 0, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyDown : regmap_type := (1056778, 1, 1, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyLeft : regmap_type := (1056778, 2, 2, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyRight : regmap_type := (1056778, 3, 3, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyA : regmap_type := (1056778, 4, 4, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyB : regmap_type := (1056778, 5, 5, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyL : regmap_type := (1056778, 6, 6, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyR : regmap_type := (1056778, 7, 7, 1, 0, readwrite);
|
||||
constant Reg_GB_KeyStart : regmap_type := (1056778, 8, 8, 1, 0, readwrite);
|
||||
constant Reg_GB_KeySelect : regmap_type := (1056778, 9, 9, 1, 0, readwrite);
|
||||
|
||||
-- special settngs
|
||||
constant Reg_GB_cputurbo : regmap_type := (1056780, 0, 0, 1, 0, readwrite); -- 1 = cpu free running, all other 16 mhz
|
||||
constant Reg_GB_SramFlashEna : regmap_type := (1056781, 0, 0, 1, 0, readwrite); -- 1 = enabled, 0 = disable (disable for copy protection in some games)
|
||||
constant Reg_GB_MemoryRemap : regmap_type := (1056782, 0, 0, 1, 0, readwrite); -- 1 = enabled, 0 = disable (enable for copy protection in some games)
|
||||
constant Reg_GB_SaveState : regmap_type := (1056783, 0, 0, 1, 0, Pulse);
|
||||
constant Reg_GB_LoadState : regmap_type := (1056784, 0, 0, 1, 0, Pulse);
|
||||
constant Reg_GB_FrameBlend : regmap_type := (1056785, 0, 0, 1, 0, readwrite); -- mix last and current frame
|
||||
constant Reg_GB_Pixelshade : regmap_type := (1056786, 2, 0, 1, 0, readwrite); -- pixel shade 1..4, 0 = off
|
||||
constant Reg_GB_SaveStateAddr : regmap_type := (1056787, 25, 0, 1, 0, readwrite); -- address to save/load savestate
|
||||
constant Reg_GB_Rewind_on : regmap_type := (1056788, 0, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_Rewind_active : regmap_type := (1056789, 0, 0, 1, 0, readwrite);
|
||||
|
||||
--debug
|
||||
constant Reg_GB_DEBUG_CPU_PC : regmap_type := (1056800, 31, 0, 1, 0, readonly);
|
||||
constant Reg_GB_DEBUG_CPU_MIX : regmap_type := (1056801, 31, 0, 1, 0, readonly);
|
||||
constant Reg_GB_DEBUG_IRQ : regmap_type := (1056802, 31, 0, 1, 0, readonly);
|
||||
constant Reg_GB_DEBUG_DMA : regmap_type := (1056803, 31, 0, 1, 0, readonly);
|
||||
constant Reg_GB_DEBUG_MEM : regmap_type := (1056804, 31, 0, 1, 0, readonly);
|
||||
|
||||
--cheats
|
||||
constant Reg_GB_CHEAT_FLAGS : regmap_type := (1056810, 31, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_CHEAT_ADDRESS : regmap_type := (1056811, 31, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_CHEAT_COMPARE : regmap_type := (1056812, 31, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_CHEAT_REPLACE : regmap_type := (1056813, 31, 0, 1, 0, readwrite);
|
||||
constant Reg_GB_CHEAT_RESET : regmap_type := (1056814, 0, 0, 1, 0, Pulse);
|
||||
|
||||
end package;
|
||||
79
sim/src/rs232/rs232_receiver.vhd
Normal file
79
sim/src/rs232/rs232_receiver.vhd
Normal file
@@ -0,0 +1,79 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
|
||||
entity rs232_receiver is
|
||||
generic
|
||||
(
|
||||
clk_speed : integer := 50000000;
|
||||
baud : integer := 115200
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
rx_byte : out std_logic_vector(7 downto 0);
|
||||
valid : out std_logic;
|
||||
rx : in std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of rs232_receiver is
|
||||
|
||||
constant bittime : integer := (clk_speed / baud)-1;
|
||||
|
||||
signal idle : std_logic := '1';
|
||||
|
||||
signal rx_ff : std_logic := '0';
|
||||
signal old_rx : std_logic := '0';
|
||||
|
||||
signal bitslow : integer range 0 to bittime+1 := 0;
|
||||
signal bitcount : integer range 0 to 8 := 0;
|
||||
|
||||
signal byte_rx : std_logic_vector(8 downto 0) := (others => '0');
|
||||
signal valid_buffer : std_logic := '0';
|
||||
|
||||
|
||||
begin
|
||||
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
valid_buffer <= '0';
|
||||
|
||||
rx_ff <= rx;
|
||||
old_rx <= rx_ff;
|
||||
|
||||
if (idle = '1' and rx_ff = '0' and old_rx = '1') then
|
||||
bitslow <= (bittime / 2) + 1;
|
||||
bitcount <= 0;
|
||||
idle <= '0';
|
||||
end if;
|
||||
|
||||
if (idle = '0') then
|
||||
bitslow <= bitslow + 1;
|
||||
if (bitslow = bittime) then
|
||||
bitslow <= 0;
|
||||
byte_rx(bitcount) <= rx_ff;
|
||||
if (bitcount < 8) then
|
||||
bitcount <= bitcount + 1;
|
||||
else
|
||||
bitcount <= 0;
|
||||
idle <= '1';
|
||||
valid_buffer <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
rx_byte <= byte_rx(8 downto 1);
|
||||
|
||||
valid <= valid_buffer;
|
||||
|
||||
|
||||
end architecture;
|
||||
69
sim/src/rs232/rs232_transmitter.vhd
Normal file
69
sim/src/rs232/rs232_transmitter.vhd
Normal file
@@ -0,0 +1,69 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
|
||||
entity rs232_transmitter is
|
||||
generic
|
||||
(
|
||||
clk_speed : integer := 50000000;
|
||||
baud : integer := 115200
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
busy : out std_logic := '0';
|
||||
sendbyte : in std_logic_vector(7 downto 0);
|
||||
enable : in std_logic;
|
||||
tx : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of rs232_transmitter is
|
||||
|
||||
constant bittime : integer := (clk_speed / baud)-1;
|
||||
|
||||
signal running : std_logic := '0';
|
||||
|
||||
signal bitslow : integer range 0 to bittime + 1 := 0;
|
||||
signal bitcount : integer range 0 to 9 := 0;
|
||||
|
||||
signal byte_tx : std_logic_vector(9 downto 0) := (others => '0');
|
||||
|
||||
|
||||
|
||||
begin
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
if (running = '0' and enable = '1') then
|
||||
running <= '1';
|
||||
bitcount <= 0;
|
||||
bitslow <= 0;
|
||||
byte_tx <= '1' & sendbyte & '0';
|
||||
end if;
|
||||
|
||||
if (running = '1') then
|
||||
bitslow <= bitslow + 1;
|
||||
if (bitslow = bittime) then
|
||||
bitslow <= 0;
|
||||
if (bitcount < 9) then
|
||||
bitcount <= bitcount + 1;
|
||||
else
|
||||
bitcount <= 0;
|
||||
running <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
busy <= '1' when running = '1' or enable = '1' else '0';
|
||||
|
||||
tx <= '1' when running = '0' else byte_tx(bitcount);
|
||||
|
||||
end architecture;
|
||||
40
sim/src/rs232/tbrs232_receiver.vhd
Normal file
40
sim/src/rs232/tbrs232_receiver.vhd
Normal file
@@ -0,0 +1,40 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
|
||||
entity tbrs232_receiver is
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
rx_byte : out std_logic_vector(7 downto 0) := (others => '0');
|
||||
valid : out std_logic := '0';
|
||||
rx : in std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of tbrs232_receiver is
|
||||
|
||||
|
||||
begin
|
||||
|
||||
process
|
||||
begin
|
||||
valid <= '0';
|
||||
|
||||
wait until rx = '0';
|
||||
|
||||
wait for 3 ps;
|
||||
for i in 0 to 7 loop
|
||||
rx_byte(i) <= rx;
|
||||
wait for 2 ps;
|
||||
end loop;
|
||||
|
||||
valid <= '1';
|
||||
wait until clk = '0';
|
||||
wait until clk = '1';
|
||||
valid <= '0';
|
||||
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
46
sim/src/rs232/tbrs232_transmitter.vhd
Normal file
46
sim/src/rs232/tbrs232_transmitter.vhd
Normal file
@@ -0,0 +1,46 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
|
||||
entity tbrs232_transmitter is
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
busy : out std_logic := '0';
|
||||
sendbyte : in std_logic_vector(7 downto 0);
|
||||
enable : in std_logic;
|
||||
tx : out std_logic := '1'
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of tbrs232_transmitter is
|
||||
|
||||
|
||||
begin
|
||||
|
||||
busy <= enable;
|
||||
|
||||
process
|
||||
begin
|
||||
tx <= '1';
|
||||
|
||||
if (enable = '1') then
|
||||
|
||||
tx <= '0';
|
||||
wait for 2 ps;
|
||||
for i in 0 to 7 loop
|
||||
tx <= sendbyte(i);
|
||||
wait for 2 ps;
|
||||
end loop;
|
||||
tx <= '1';
|
||||
|
||||
end if;
|
||||
|
||||
wait until clk = '0';
|
||||
wait until clk = '1';
|
||||
|
||||
end process;
|
||||
|
||||
|
||||
end architecture;
|
||||
108
sim/src/tb/framebuffer.vhd
Normal file
108
sim/src/tb/framebuffer.vhd
Normal file
@@ -0,0 +1,108 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
use STD.textio.all;
|
||||
|
||||
entity framebuffer is
|
||||
generic
|
||||
(
|
||||
FRAMESIZE_X : integer;
|
||||
FRAMESIZE_Y : integer
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
|
||||
pixel_in_x : in integer range 0 to (FRAMESIZE_X - 1);
|
||||
pixel_in_y : in integer range 0 to (FRAMESIZE_Y - 1);
|
||||
pixel_in_data : in std_logic_vector(14 downto 0);
|
||||
pixel_in_we : in std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of framebuffer is
|
||||
|
||||
-- data write
|
||||
signal pixel_in_addr : integer range 0 to (FRAMESIZE_X * FRAMESIZE_Y) - 1;
|
||||
signal pixel_in_data_1 : std_logic_vector(14 downto 0);
|
||||
signal pixel_in_we_1 : std_logic;
|
||||
|
||||
type tPixelArray is array(0 to (FRAMESIZE_X * FRAMESIZE_Y) - 1) of std_logic_vector(14 downto 0);
|
||||
signal PixelArray : tPixelArray := (others => (others => '0'));
|
||||
|
||||
begin
|
||||
|
||||
-- fill framebuffer
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
pixel_in_addr <= pixel_in_x + (pixel_in_y * 160);
|
||||
pixel_in_data_1 <= pixel_in_data;
|
||||
pixel_in_we_1 <= pixel_in_we;
|
||||
|
||||
if (pixel_in_we_1 = '1') then
|
||||
PixelArray(pixel_in_addr) <= pixel_in_data_1;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- synthesis translate_off
|
||||
|
||||
goutput : if 1 = 1 generate
|
||||
begin
|
||||
|
||||
process
|
||||
|
||||
file outfile: text;
|
||||
variable f_status: FILE_OPEN_STATUS;
|
||||
variable line_out : line;
|
||||
variable color : unsigned(31 downto 0);
|
||||
variable linecounter_int : integer;
|
||||
|
||||
begin
|
||||
|
||||
file_open(f_status, outfile, "gra_fb_out.gra", write_mode);
|
||||
file_close(outfile);
|
||||
|
||||
file_open(f_status, outfile, "gra_fb_out.gra", append_mode);
|
||||
write(line_out, string'("160#144"));
|
||||
writeline(outfile, line_out);
|
||||
|
||||
while (true) loop
|
||||
wait until ((pixel_in_x mod 160) = (160 - 1)) and pixel_in_we = '1';
|
||||
linecounter_int := pixel_in_y;
|
||||
|
||||
wait for 100 ns;
|
||||
|
||||
for x in 0 to 159 loop
|
||||
color := (31 downto 15 => '0') & unsigned(PixelArray(x + linecounter_int * 160));
|
||||
color := x"00" & unsigned(color(14 downto 10)) & "000" & unsigned(color(9 downto 5)) & "000" & unsigned(color(4 downto 0)) & "000";
|
||||
|
||||
write(line_out, to_integer(color));
|
||||
write(line_out, string'("#"));
|
||||
write(line_out, x);
|
||||
write(line_out, string'("#"));
|
||||
write(line_out, linecounter_int);
|
||||
writeline(outfile, line_out);
|
||||
|
||||
end loop;
|
||||
|
||||
file_close(outfile);
|
||||
file_open(f_status, outfile, "gra_fb_out.gra", append_mode);
|
||||
|
||||
end loop;
|
||||
|
||||
end process;
|
||||
|
||||
end generate goutput;
|
||||
|
||||
-- synthesis translate_on
|
||||
|
||||
end architecture;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
285
sim/src/tb/gb_bios.vhd
Normal file
285
sim/src/tb/gb_bios.vhd
Normal file
@@ -0,0 +1,285 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
entity gb_bios is
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
address : in std_logic_vector(7 downto 0);
|
||||
data : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of gb_bios is
|
||||
|
||||
type t_rom is array(0 to 255) of std_logic_vector(7 downto 0);
|
||||
signal rom : t_rom := (
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00",
|
||||
x"00"
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
data <= rom(to_integer(unsigned(address)));
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
13
sim/src/tb/globals.vhd
Normal file
13
sim/src/tb/globals.vhd
Normal file
@@ -0,0 +1,13 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
package globals is
|
||||
|
||||
signal COMMAND_FILE_ENDIAN : std_logic;
|
||||
signal COMMAND_FILE_NAME : string(1 to 1024);
|
||||
signal COMMAND_FILE_NAMELEN : integer;
|
||||
signal COMMAND_FILE_TARGET : integer;
|
||||
signal COMMAND_FILE_START : std_logic;
|
||||
signal COMMAND_FILE_ACK : std_logic;
|
||||
|
||||
end package globals;
|
||||
113
sim/src/tb/sdram_model.vhd
Normal file
113
sim/src/tb/sdram_model.vhd
Normal file
@@ -0,0 +1,113 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library tb;
|
||||
use tb.globals.all;
|
||||
|
||||
entity sdram_model is
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
cart_addr : in std_logic_vector(15 downto 0);
|
||||
cart_rd : in std_logic;
|
||||
cart_do : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of sdram_model is
|
||||
|
||||
-- not full size, because of memory required
|
||||
type t_data is array(0 to (2**23)-1) of integer;
|
||||
type bit_vector_file is file of bit_vector;
|
||||
|
||||
begin
|
||||
|
||||
process
|
||||
|
||||
variable data : t_data := (others => 0);
|
||||
|
||||
file infile : bit_vector_file;
|
||||
variable f_status : FILE_OPEN_STATUS;
|
||||
variable read_byte : std_logic_vector(7 downto 0);
|
||||
variable next_vector : bit_vector (0 downto 0);
|
||||
variable actual_len : natural;
|
||||
variable targetpos : integer;
|
||||
|
||||
-- copy from std_logic_arith, not used here because numeric std is also included
|
||||
function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is
|
||||
variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0);
|
||||
variable temp: integer;
|
||||
begin
|
||||
|
||||
temp := ARG;
|
||||
for i in 0 to SIZE-1 loop
|
||||
|
||||
if (temp mod 2) = 1 then
|
||||
result(i) := '1';
|
||||
else
|
||||
result(i) := '0';
|
||||
end if;
|
||||
|
||||
if temp > 0 then
|
||||
temp := temp / 2;
|
||||
elsif (temp > integer'low) then
|
||||
temp := (temp - 1) / 2; -- simulate ASR
|
||||
else
|
||||
temp := temp / 2; -- simulate ASR
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return result;
|
||||
end;
|
||||
|
||||
begin
|
||||
wait until rising_edge(clk);
|
||||
|
||||
if (cart_rd = '1') then
|
||||
cart_do <= x"FF";
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
cart_do <= std_logic_vector(to_unsigned(data(to_integer(unsigned(cart_addr))), 8));
|
||||
end if;
|
||||
|
||||
COMMAND_FILE_ACK <= '0';
|
||||
if COMMAND_FILE_START = '1' then
|
||||
|
||||
assert false report "received" severity note;
|
||||
assert false report COMMAND_FILE_NAME(1 to COMMAND_FILE_NAMELEN) severity note;
|
||||
|
||||
file_open(f_status, infile, COMMAND_FILE_NAME(1 to COMMAND_FILE_NAMELEN), read_mode);
|
||||
|
||||
targetpos := COMMAND_FILE_TARGET;
|
||||
|
||||
while (not endfile(infile)) loop
|
||||
|
||||
read(infile, next_vector, actual_len);
|
||||
|
||||
read_byte := CONV_STD_LOGIC_VECTOR(bit'pos(next_vector(0)), 8);
|
||||
|
||||
--report "read_byte=" & integer'image(to_integer(unsigned(read_byte)));
|
||||
|
||||
data(targetpos) := to_integer(unsigned(read_byte));
|
||||
targetpos := targetpos + 1;
|
||||
|
||||
end loop;
|
||||
|
||||
file_close(infile);
|
||||
|
||||
COMMAND_FILE_ACK <= '1';
|
||||
|
||||
end if;
|
||||
|
||||
|
||||
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
|
||||
|
||||
389
sim/src/tb/stringprocessor.vhd
Normal file
389
sim/src/tb/stringprocessor.vhd
Normal file
@@ -0,0 +1,389 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use STD.textio.all;
|
||||
|
||||
library procbus;
|
||||
use procbus.pProc_bus.all;
|
||||
|
||||
use work.globals.all;
|
||||
|
||||
entity estringprocessor is
|
||||
generic
|
||||
(
|
||||
clk_speed : integer := 50000000
|
||||
);
|
||||
port
|
||||
(
|
||||
ready : in std_logic;
|
||||
tx_command : out std_logic_vector(31 downto 0);
|
||||
tx_bytes : out integer range 0 to 4;
|
||||
tx_enable : out std_logic := '0';
|
||||
rx_command : in std_logic_vector(31 downto 0);
|
||||
rx_valid : in std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of estringprocessor is
|
||||
|
||||
constant clk_period : time := (1000000000 / clk_speed) * 1 ns;
|
||||
|
||||
signal string_command : string(1 to 3);
|
||||
|
||||
type t_internal_variables is array(0 to 256) of integer;
|
||||
signal internal_variables : t_internal_variables := (others => 0);
|
||||
|
||||
type r_thread_record is record
|
||||
id : integer;
|
||||
waittime : integer;
|
||||
waitcommand : line;
|
||||
end record;
|
||||
|
||||
type t_thread_buffers is array(0 to 255) of r_thread_record;
|
||||
|
||||
|
||||
procedure find_id
|
||||
(
|
||||
variable t_buf : inout t_thread_buffers;
|
||||
variable id : in integer;
|
||||
variable slot : out integer
|
||||
) is
|
||||
begin
|
||||
for i in 0 to 255 loop
|
||||
if (t_buf(i).id = id) then
|
||||
slot := i;
|
||||
exit;
|
||||
elsif (t_buf(i).id = -1) then
|
||||
t_buf(i).id := id;
|
||||
slot := i;
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
end procedure;
|
||||
|
||||
|
||||
|
||||
begin
|
||||
|
||||
|
||||
process
|
||||
|
||||
file infile : text;
|
||||
file outfile : text;
|
||||
variable f_status : FILE_OPEN_STATUS;
|
||||
variable newdat : LINE;
|
||||
variable endfound : boolean;
|
||||
variable buf : LINE;
|
||||
variable run : boolean := true;
|
||||
|
||||
variable line_out : line;
|
||||
variable debugline_out : line;
|
||||
variable command : string(1 to 3);
|
||||
|
||||
variable dev_null_str3 : string (1 to 3);
|
||||
variable dev_null_str6 : string (1 to 6);
|
||||
variable OK : boolean := FALSE;
|
||||
variable para_int1 : integer;
|
||||
variable para_int2 : integer;
|
||||
variable para_int3 : integer;
|
||||
variable para_int4 : integer;
|
||||
|
||||
variable address : integer;
|
||||
variable data : integer;
|
||||
variable count : integer;
|
||||
|
||||
variable thread_buffers : t_thread_buffers := (others => (-1, 0, null));
|
||||
|
||||
variable freerun : boolean := false;
|
||||
|
||||
begin
|
||||
|
||||
file_open(f_status, outfile, "input.txt", write_mode);
|
||||
file_close(outfile);
|
||||
file_open(f_status, outfile, "output.txt", write_mode);
|
||||
file_close(outfile);
|
||||
|
||||
file_open(f_status, infile, "input.txt", read_mode);
|
||||
|
||||
wait for 1000 ns;
|
||||
|
||||
while (run) loop
|
||||
|
||||
if not endfile(infile) then
|
||||
|
||||
endfound := false;
|
||||
buf := null;
|
||||
while (endfound = false) loop
|
||||
if not endfile(infile) then
|
||||
readline(infile,newdat);
|
||||
for i in 1 to newdat'length loop
|
||||
write(buf, newdat(i to i));
|
||||
if (newdat(i to i) = "&") then
|
||||
endfound := true;
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
command := buf(1 to 3);
|
||||
string_command <= command;
|
||||
|
||||
line_out := null;
|
||||
buf(buf'length) := ' ';
|
||||
write(line_out, buf(1 to buf'length));
|
||||
write(line_out, string'("# "));
|
||||
|
||||
if (command(1 to 3) = String'("set")) then
|
||||
-- command
|
||||
Read(buf, dev_null_str6);
|
||||
-- command nr
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- process id
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- target for reading
|
||||
Read(buf, para_int2, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- count
|
||||
Read(buf, count, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- address in target space
|
||||
Read(buf, address, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
|
||||
-- write address
|
||||
if (ready = '0') then
|
||||
wait until ready = '1';
|
||||
end if;
|
||||
tx_command <= "000000" & std_logic_vector(to_unsigned(address,proc_busadr));
|
||||
if (count > 1) then
|
||||
tx_command(31) <= '1';
|
||||
end if;
|
||||
tx_bytes <= 4;
|
||||
tx_enable <= '1';
|
||||
wait for clk_period*2;
|
||||
tx_enable <= '0';
|
||||
|
||||
-- write block size
|
||||
if (count > 1) then
|
||||
if (ready = '0') then
|
||||
wait until ready = '1';
|
||||
end if;
|
||||
tx_command <= x"000000" & std_logic_vector(to_unsigned(count - 1,8));
|
||||
tx_bytes <= 1;
|
||||
tx_enable <= '1';
|
||||
wait for clk_period*2;
|
||||
tx_enable <= '0';
|
||||
end if;
|
||||
|
||||
for i in 1 to count loop
|
||||
|
||||
-- value to write
|
||||
Read(buf, data, OK);
|
||||
if (i < count) then
|
||||
Read(buf, dev_null_str3);
|
||||
end if;
|
||||
|
||||
-- write data
|
||||
if (ready = '0') then
|
||||
wait until ready = '1';
|
||||
end if;
|
||||
tx_command <= std_logic_vector(to_signed(data,proc_buswidth));
|
||||
tx_bytes <= 4;
|
||||
tx_enable <= '1';
|
||||
wait for clk_period*2;
|
||||
tx_enable <= '0';
|
||||
wait for 20*clk_period; -- this is required, because there is no answer for write commands
|
||||
|
||||
address := address + 1;
|
||||
|
||||
end loop;
|
||||
|
||||
write(line_out, string'("&"));
|
||||
file_open(f_status, outfile, "output.txt", append_mode);
|
||||
writeline(outfile, line_out);
|
||||
file_close(outfile);
|
||||
end if;
|
||||
|
||||
if (command(1 to 3) = String'("get")) then
|
||||
-- command
|
||||
Read(buf, dev_null_str6);
|
||||
-- command nr
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- process id
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- target for reading
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- count
|
||||
Read(buf, count, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- address in target space
|
||||
Read(buf, address, OK);
|
||||
|
||||
-- write address
|
||||
if (ready = '0') then
|
||||
wait until ready = '1';
|
||||
end if;
|
||||
tx_command <= "010000" & std_logic_vector(to_unsigned(address,proc_busadr));
|
||||
if (count > 1) then
|
||||
tx_command(31) <= '1';
|
||||
end if;
|
||||
tx_bytes <= 4;
|
||||
tx_enable <= '1';
|
||||
wait for clk_period*2;
|
||||
tx_enable <= '0';
|
||||
|
||||
-- write block size
|
||||
if (count > 1) then
|
||||
if (ready = '0') then
|
||||
wait until ready = '1';
|
||||
end if;
|
||||
tx_command <= x"000000" & std_logic_vector(to_unsigned(count - 1,8));
|
||||
tx_bytes <= 1;
|
||||
tx_enable <= '1';
|
||||
wait for clk_period*2;
|
||||
tx_enable <= '0';
|
||||
end if;
|
||||
|
||||
for i in 1 to count loop
|
||||
|
||||
if (rx_valid = '0') then
|
||||
wait until rx_valid = '1';
|
||||
end if;
|
||||
data := to_integer(signed(rx_command(31 downto 0)));
|
||||
wait until rx_valid = '0';
|
||||
|
||||
write(line_out, data);
|
||||
write(line_out, string'("#"));
|
||||
|
||||
address := address + 1;
|
||||
|
||||
end loop;
|
||||
|
||||
write(line_out, string'("&"));
|
||||
file_open(f_status, outfile, "output.txt", append_mode);
|
||||
writeline(outfile, line_out);
|
||||
file_close(outfile);
|
||||
end if;
|
||||
|
||||
if (command(1 to 3) = String'("fil")) then
|
||||
-- command
|
||||
Read(buf, dev_null_str6);
|
||||
-- command nr
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- process id
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- endianess
|
||||
Read(buf, para_int2, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- address in target space
|
||||
Read(buf, address, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
|
||||
COMMAND_FILE_NAME <= (others => ' ');
|
||||
COMMAND_FILE_NAME(1 to buf'length) <= buf(1 to buf'length);
|
||||
COMMAND_FILE_NAMELEN <= buf'length;
|
||||
COMMAND_FILE_TARGET <= address;
|
||||
if (para_int2 = 1) then
|
||||
COMMAND_FILE_ENDIAN <= '1';
|
||||
else
|
||||
COMMAND_FILE_ENDIAN <= '0';
|
||||
end if;
|
||||
COMMAND_FILE_START <= '1';
|
||||
wait until COMMAND_FILE_ACK = '1';
|
||||
COMMAND_FILE_START <= '0';
|
||||
wait for 20 ns;
|
||||
|
||||
write(line_out, string'("&"));
|
||||
file_open(f_status, outfile, "output.txt", append_mode);
|
||||
writeline(outfile, line_out);
|
||||
file_close(outfile);
|
||||
end if;
|
||||
|
||||
if (command(1 to 3) = String'("brk")) then
|
||||
run := false;
|
||||
end if;
|
||||
|
||||
if (command(1 to 3) = String'("wtn")) then
|
||||
-- command
|
||||
Read(buf, dev_null_str6);
|
||||
-- command nr
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- process id
|
||||
Read(buf, para_int1, OK);
|
||||
Read(buf, dev_null_str3);
|
||||
-- time to wait
|
||||
Read(buf, para_int2, OK);
|
||||
|
||||
|
||||
write(line_out, string'("&"));
|
||||
if (para_int2 = -1) then
|
||||
freerun := true;
|
||||
find_id(thread_buffers, para_int1, para_int3);
|
||||
thread_buffers(para_int3).waittime := 2;
|
||||
thread_buffers(para_int3).waitcommand := line_out;
|
||||
else
|
||||
find_id(thread_buffers, para_int1, para_int3);
|
||||
thread_buffers(para_int3).waittime := para_int2;
|
||||
thread_buffers(para_int3).waitcommand := line_out;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
wait for 1 ps;
|
||||
|
||||
end if;
|
||||
|
||||
OK := false;
|
||||
for i in 0 to 255 loop
|
||||
if (thread_buffers(i).id /= -1) then
|
||||
if (thread_buffers(i).waittime = 1) then
|
||||
file_open(f_status, outfile, "output.txt", append_mode);
|
||||
writeline(outfile, thread_buffers(i).waitcommand);
|
||||
file_close(outfile);
|
||||
end if;
|
||||
if (thread_buffers(i).waittime > 0) then
|
||||
OK := true;
|
||||
thread_buffers(i).waittime := thread_buffers(i).waittime - 1;
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
if (OK = true or freerun = true) then
|
||||
wait for 1 ns;
|
||||
end if;
|
||||
|
||||
end loop;
|
||||
|
||||
file_close(infile);
|
||||
|
||||
wait;
|
||||
|
||||
end process;
|
||||
|
||||
|
||||
|
||||
|
||||
end architecture;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
263
sim/src/tb/tb.vhd
Normal file
263
sim/src/tb/tb.vhd
Normal file
@@ -0,0 +1,263 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library tb;
|
||||
library gameboy;
|
||||
|
||||
library procbus;
|
||||
use procbus.pProc_bus.all;
|
||||
use procbus.pRegmap.all;
|
||||
|
||||
library reg_map;
|
||||
use reg_map.pReg_gameboy.all;
|
||||
|
||||
entity etb is
|
||||
end entity;
|
||||
|
||||
architecture arch of etb is
|
||||
|
||||
constant clk_speed : integer := 100000000;
|
||||
constant baud : integer := 25000000;
|
||||
|
||||
signal clk100 : std_logic := '1';
|
||||
|
||||
signal reset : std_logic := '1';
|
||||
signal clksys : std_logic := '1';
|
||||
|
||||
signal clkdiv : unsigned(2 downto 0) := (others => '0');
|
||||
signal nextdiv : unsigned(2 downto 0) := (others => '0');
|
||||
|
||||
signal ce : std_logic := '1';
|
||||
signal ce_2x : std_logic := '1';
|
||||
|
||||
signal command_in : std_logic;
|
||||
signal command_out : std_logic;
|
||||
signal command_out_filter : std_logic;
|
||||
|
||||
signal proc_bus_in : proc_bus_type;
|
||||
|
||||
signal lcd_clkena : std_logic;
|
||||
signal lcd_clkena_1 : std_logic := '0';
|
||||
signal lcd_data : std_logic_vector(14 downto 0);
|
||||
signal lcd_mode : std_logic_vector(1 downto 0);
|
||||
signal lcd_on : std_logic;
|
||||
signal lcd_vsync : std_logic;
|
||||
signal lcd_vsync_1 : std_logic := '0';
|
||||
|
||||
signal gbc_bios_addr : std_logic_vector(11 downto 0);
|
||||
signal gbc_bios_do : std_logic_vector(7 downto 0);
|
||||
|
||||
signal cart_addr : std_logic_vector(15 downto 0);
|
||||
signal cart_rd : std_logic;
|
||||
signal cart_wr : std_logic;
|
||||
signal cart_act : std_logic;
|
||||
signal cart_do : std_logic_vector(7 downto 0);
|
||||
signal cart_di : std_logic_vector(7 downto 0);
|
||||
|
||||
|
||||
signal pixel_out_x : integer range 0 to 159;
|
||||
signal pixel_out_y : integer range 0 to 143;
|
||||
signal pixel_out_data : std_logic_vector(14 downto 0);
|
||||
signal pixel_out_we : std_logic := '0';
|
||||
|
||||
|
||||
-- settings
|
||||
signal GB_on : std_logic_vector(Reg_GB_on.upper downto Reg_GB_on.lower) := (others => '0');
|
||||
|
||||
|
||||
begin
|
||||
|
||||
reset <= not GB_on(0);
|
||||
clksys <= not clksys after 15 ns;
|
||||
|
||||
clk100 <= not clk100 after 5 ns;
|
||||
|
||||
-- registers
|
||||
iReg_GBA_on : entity procbus.eProcReg generic map (Reg_GB_on ) port map (clk100, proc_bus_in, GB_on, GB_on);
|
||||
|
||||
cart_act <= cart_rd or cart_wr;
|
||||
|
||||
ispeedcontrol : entity gameboy.speedcontrol
|
||||
port map
|
||||
(
|
||||
clk_sys => clksys,
|
||||
pause => '0',
|
||||
speedup => '1',
|
||||
cart_act => cart_act,
|
||||
ce => ce,
|
||||
ce_2x => ce_2x
|
||||
);
|
||||
|
||||
|
||||
isdram_model : entity tb.sdram_model
|
||||
port map
|
||||
(
|
||||
clk => clksys,
|
||||
cart_addr => cart_addr,
|
||||
cart_rd => cart_rd,
|
||||
cart_do => cart_do
|
||||
);
|
||||
|
||||
--itetris : entity gameboy.tetris
|
||||
--port map
|
||||
--(
|
||||
-- clk => clksys,
|
||||
-- address => cart_addr(14 downto 0),
|
||||
-- data => cart_do
|
||||
--);
|
||||
|
||||
igb : entity gameboy.gb
|
||||
port map
|
||||
(
|
||||
reset => reset,
|
||||
|
||||
clk_sys => clksys,
|
||||
ce => ce,
|
||||
ce_2x => ce_2x,
|
||||
--ce_sound => ce_2x,
|
||||
|
||||
fast_boot => '1',
|
||||
joystick => x"00",
|
||||
isGBC => '0',
|
||||
isGBC_game => '0',
|
||||
|
||||
-- cartridge interface
|
||||
-- can adress up to 1MB ROM
|
||||
cart_addr => cart_addr,
|
||||
cart_rd => cart_rd,
|
||||
cart_wr => cart_wr,
|
||||
cart_do => cart_do,
|
||||
cart_di => cart_di,
|
||||
|
||||
--gbc bios interface
|
||||
gbc_bios_addr => gbc_bios_addr,
|
||||
gbc_bios_do => gbc_bios_do,
|
||||
|
||||
-- audio
|
||||
audio_l => open,
|
||||
audio_r => open,
|
||||
|
||||
-- lcd interface
|
||||
lcd_clkena => lcd_clkena,
|
||||
lcd_data => lcd_data,
|
||||
lcd_mode => lcd_mode,
|
||||
lcd_on => lcd_on,
|
||||
lcd_vsync => lcd_vsync,
|
||||
|
||||
joy_p54 => open,
|
||||
joy_din => "0000",
|
||||
|
||||
speed => open, --GBC
|
||||
|
||||
gg_reset => reset,
|
||||
gg_en => '0',
|
||||
gg_code => (128 downto 0 => '0'),
|
||||
gg_available => open,
|
||||
|
||||
--serial port
|
||||
sc_int_clock2 => open,
|
||||
serial_clk_in => '0',
|
||||
serial_clk_out => open,
|
||||
serial_data_in => '0',
|
||||
serial_data_out => open
|
||||
);
|
||||
|
||||
igb_bios : entity tb.gb_bios
|
||||
port map
|
||||
(
|
||||
clk => clksys,
|
||||
address => gbc_bios_addr(7 downto 0),
|
||||
data => gbc_bios_do
|
||||
);
|
||||
|
||||
process(clksys)
|
||||
begin
|
||||
if rising_edge(clksys) then
|
||||
pixel_out_we <= '0';
|
||||
lcd_vsync_1 <= lcd_vsync;
|
||||
lcd_clkena_1 <= lcd_clkena;
|
||||
if (lcd_on = '1') then
|
||||
if (lcd_vsync = '1' and lcd_vsync_1 = '0') then
|
||||
pixel_out_x <= 0;
|
||||
pixel_out_y <= 0;
|
||||
elsif (lcd_clkena_1 = '1' and lcd_clkena = '0') then
|
||||
pixel_out_x <= 0;
|
||||
pixel_out_we <= '1';
|
||||
if (pixel_out_y < 143) then
|
||||
pixel_out_y <= pixel_out_y + 1;
|
||||
end if;
|
||||
elsif (lcd_clkena = '1' and ce = '1') then
|
||||
if (pixel_out_x < 159) then
|
||||
pixel_out_x <= pixel_out_x + 1;
|
||||
end if;
|
||||
pixel_out_we <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
case (lcd_data(1 downto 0)) is
|
||||
when "00" => pixel_out_data <= "11111" & "11111" & "11111";
|
||||
when "01" => pixel_out_data <= "10000" & "10000" & "10000";
|
||||
when "10" => pixel_out_data <= "01000" & "01000" & "01000";
|
||||
when "11" => pixel_out_data <= "00000" & "00000" & "00000";
|
||||
when others => pixel_out_data <= "00000" & "00000" & "11111";
|
||||
end case;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
iframebuffer : entity work.framebuffer
|
||||
generic map
|
||||
(
|
||||
FRAMESIZE_X => 160,
|
||||
FRAMESIZE_Y => 144
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => clksys,
|
||||
|
||||
pixel_in_x => pixel_out_x,
|
||||
pixel_in_y => pixel_out_y,
|
||||
pixel_in_data => pixel_out_data,
|
||||
pixel_in_we => pixel_out_we
|
||||
);
|
||||
|
||||
iTestprocessor : entity procbus.eTestprocessor
|
||||
generic map
|
||||
(
|
||||
clk_speed => clk_speed,
|
||||
baud => baud,
|
||||
is_simu => '1'
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => clk100,
|
||||
bootloader => '0',
|
||||
debugaccess => '1',
|
||||
command_in => command_in,
|
||||
command_out => command_out,
|
||||
|
||||
proc_bus => proc_bus_in,
|
||||
|
||||
fifo_full_error => open,
|
||||
timeout_error => open
|
||||
);
|
||||
|
||||
command_out_filter <= '0' when command_out = 'Z' else command_out;
|
||||
|
||||
itb_interpreter : entity tb.etb_interpreter
|
||||
generic map
|
||||
(
|
||||
clk_speed => clk_speed,
|
||||
baud => baud
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => clk100,
|
||||
command_in => command_in,
|
||||
command_out => command_out_filter
|
||||
);
|
||||
|
||||
end architecture;
|
||||
|
||||
|
||||
125
sim/src/tb/tb_interpreter.vhd
Normal file
125
sim/src/tb/tb_interpreter.vhd
Normal file
@@ -0,0 +1,125 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
library rs232;
|
||||
library tb;
|
||||
|
||||
entity etb_interpreter is
|
||||
generic
|
||||
(
|
||||
clk_speed : integer := 50000000;
|
||||
baud : integer := 115200
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
command_in : out std_logic;
|
||||
command_out : in std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of etb_interpreter is
|
||||
|
||||
signal slow_counter : unsigned(3 downto 0) := (others => '0');
|
||||
|
||||
signal addr_counter : integer := 0;
|
||||
|
||||
signal idle : std_logic := '1';
|
||||
|
||||
signal transmit_command : std_logic_vector(31 downto 0) := (others => '0');
|
||||
signal transmit_byte_nr : integer := 0;
|
||||
signal sendbyte : std_logic_vector(7 downto 0) := (others => '0');
|
||||
signal tx_enable : std_logic := '0';
|
||||
signal tx_busy : std_logic;
|
||||
|
||||
signal receive_command : std_logic_vector(31 downto 0) := (others => '0');
|
||||
signal receive_byte_nr : integer := 0;
|
||||
signal receive_valid : std_logic := '0';
|
||||
|
||||
signal rx_valid : std_logic;
|
||||
signal rx_byte : std_logic_vector(7 downto 0);
|
||||
|
||||
signal proc_command : std_logic_vector(31 downto 0);
|
||||
signal proc_bytes : integer range 0 to 4;
|
||||
signal proc_enable : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
-- tx side
|
||||
tx_enable <= '0';
|
||||
|
||||
if (idle = '1' and proc_enable = '1') then
|
||||
addr_counter <= addr_counter + 1;
|
||||
transmit_command <= proc_command;
|
||||
transmit_byte_nr <= 0;
|
||||
idle <= '0';
|
||||
elsif (idle = '0') then
|
||||
if (tx_busy = '0') then
|
||||
transmit_byte_nr <= transmit_byte_nr + 1;
|
||||
sendbyte <= transmit_command((transmit_byte_nr*8)+7 downto (transmit_byte_nr*8));
|
||||
tx_enable <= '1';
|
||||
if (transmit_byte_nr = (proc_bytes - 1)) then
|
||||
idle <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- rx side
|
||||
receive_valid <= '0';
|
||||
if (rx_valid = '1') then
|
||||
receive_byte_nr <= receive_byte_nr + 1;
|
||||
receive_command((receive_byte_nr*8)+7 downto (receive_byte_nr*8)) <= rx_byte;
|
||||
if (receive_byte_nr = 3) then
|
||||
receive_byte_nr <= 0;
|
||||
receive_valid <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
istringprocessor: entity tb.estringprocessor
|
||||
generic map
|
||||
(
|
||||
clk_speed => clk_speed
|
||||
)
|
||||
port map
|
||||
(
|
||||
ready => idle,
|
||||
tx_command => proc_command,
|
||||
tx_bytes => proc_bytes,
|
||||
tx_enable => proc_enable,
|
||||
rx_command => receive_command,
|
||||
rx_valid => receive_valid
|
||||
);
|
||||
|
||||
|
||||
itbrs232_transmitter : entity rs232.tbrs232_transmitter
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
busy => tx_busy,
|
||||
sendbyte => sendbyte,
|
||||
enable => tx_enable,
|
||||
tx => command_in
|
||||
);
|
||||
|
||||
itbrs232_receiver : entity rs232.tbrs232_receiver
|
||||
port map
|
||||
(
|
||||
clk => clk,
|
||||
rx_byte => rx_byte,
|
||||
valid => rx_valid,
|
||||
rx => command_out
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
end architecture;
|
||||
15
sim/tests/gb_bootrom.lua
Normal file
15
sim/tests/gb_bootrom.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
require("vsim_comm")
|
||||
require("luareg")
|
||||
|
||||
wait_ns(10000)
|
||||
|
||||
reg_set(0, gameboy.Reg_GB_on)
|
||||
|
||||
reg_set_file("tests\\tetris.gb", 0, 0, 0)
|
||||
|
||||
wait_ns(10000)
|
||||
reg_set(1, gameboy.Reg_GB_on)
|
||||
|
||||
print("GB ON")
|
||||
|
||||
brk()
|
||||
44
sim/tests/luareg.lua
Normal file
44
sim/tests/luareg.lua
Normal file
@@ -0,0 +1,44 @@
|
||||
--space.name = {address, upper, lower, size, default}
|
||||
gameboy = {}
|
||||
gameboy.Reg_GB_on = {1056768,0,0,1,0,"gameboy.Reg_GB_on"} -- on = 1
|
||||
gameboy.Reg_GB_lockspeed = {1056769,0,0,1,0,"gameboy.Reg_GB_lockspeed"} -- 1 = 100% speed
|
||||
gameboy.Reg_GB_flash_1m = {1056770,0,0,1,0,"gameboy.Reg_GB_flash_1m"}
|
||||
gameboy.Reg_GB_CyclePrecalc = {1056771,15,0,1,100,"gameboy.Reg_GB_CyclePrecalc"}
|
||||
gameboy.Reg_GB_CyclesMissing = {1056772,31,0,1,0,"gameboy.Reg_GB_CyclesMissing"}
|
||||
gameboy.Reg_GB_BusAddr = {1056773,27,0,1,0,"gameboy.Reg_GB_BusAddr"}
|
||||
gameboy.Reg_GB_BusRnW = {1056773,28,28,1,0,"gameboy.Reg_GB_BusRnW"}
|
||||
gameboy.Reg_GB_BusACC = {1056773,30,29,1,0,"gameboy.Reg_GB_BusACC"}
|
||||
gameboy.Reg_GB_BusWriteData = {1056774,31,0,1,0,"gameboy.Reg_GB_BusWriteData"}
|
||||
gameboy.Reg_GB_BusReadData = {1056775,31,0,1,0,"gameboy.Reg_GB_BusReadData"}
|
||||
gameboy.Reg_GB_MaxPakAddr = {1056776,24,0,1,0,"gameboy.Reg_GB_MaxPakAddr"}
|
||||
gameboy.Reg_GB_VsyncSpeed = {1056777,31,0,1,0,"gameboy.Reg_GB_VsyncSpeed"}
|
||||
gameboy.Reg_GB_KeyUp = {1056778,0,0,1,0,"gameboy.Reg_GB_KeyUp"}
|
||||
gameboy.Reg_GB_KeyDown = {1056778,1,1,1,0,"gameboy.Reg_GB_KeyDown"}
|
||||
gameboy.Reg_GB_KeyLeft = {1056778,2,2,1,0,"gameboy.Reg_GB_KeyLeft"}
|
||||
gameboy.Reg_GB_KeyRight = {1056778,3,3,1,0,"gameboy.Reg_GB_KeyRight"}
|
||||
gameboy.Reg_GB_KeyA = {1056778,4,4,1,0,"gameboy.Reg_GB_KeyA"}
|
||||
gameboy.Reg_GB_KeyB = {1056778,5,5,1,0,"gameboy.Reg_GB_KeyB"}
|
||||
gameboy.Reg_GB_KeyL = {1056778,6,6,1,0,"gameboy.Reg_GB_KeyL"}
|
||||
gameboy.Reg_GB_KeyR = {1056778,7,7,1,0,"gameboy.Reg_GB_KeyR"}
|
||||
gameboy.Reg_GB_KeyStart = {1056778,8,8,1,0,"gameboy.Reg_GB_KeyStart"}
|
||||
gameboy.Reg_GB_KeySelect = {1056778,9,9,1,0,"gameboy.Reg_GB_KeySelect"}
|
||||
gameboy.Reg_GB_cputurbo = {1056780,0,0,1,0,"gameboy.Reg_GB_cputurbo"} -- 1 = cpu free running, all other 16 mhz
|
||||
gameboy.Reg_GB_SramFlashEna = {1056781,0,0,1,0,"gameboy.Reg_GB_SramFlashEna"} -- 1 = enabled, 0 = disable (disable for copy protection in some games)
|
||||
gameboy.Reg_GB_MemoryRemap = {1056782,0,0,1,0,"gameboy.Reg_GB_MemoryRemap"} -- 1 = enabled, 0 = disable (enable for copy protection in some games)
|
||||
gameboy.Reg_GB_SaveState = {1056783,0,0,1,0,"gameboy.Reg_GB_SaveState"}
|
||||
gameboy.Reg_GB_LoadState = {1056784,0,0,1,0,"gameboy.Reg_GB_LoadState"}
|
||||
gameboy.Reg_GB_FrameBlend = {1056785,0,0,1,0,"gameboy.Reg_GB_FrameBlend"} -- mix last and current frame
|
||||
gameboy.Reg_GB_Pixelshade = {1056786,2,0,1,0,"gameboy.Reg_GB_Pixelshade"} -- pixel shade 1..4, 0 = off
|
||||
gameboy.Reg_GB_SaveStateAddr = {1056787,25,0,1,0,"gameboy.Reg_GB_SaveStateAddr"} -- address to save/load savestate
|
||||
gameboy.Reg_GB_Rewind_on = {1056788,0,0,1,0,"gameboy.Reg_GB_Rewind_on"}
|
||||
gameboy.Reg_GB_Rewind_active = {1056789,0,0,1,0,"gameboy.Reg_GB_Rewind_active"}
|
||||
gameboy.Reg_GB_DEBUG_CPU_PC = {1056800,31,0,1,0,"gameboy.Reg_GB_DEBUG_CPU_PC"}
|
||||
gameboy.Reg_GB_DEBUG_CPU_MIX = {1056801,31,0,1,0,"gameboy.Reg_GB_DEBUG_CPU_MIX"}
|
||||
gameboy.Reg_GB_DEBUG_IRQ = {1056802,31,0,1,0,"gameboy.Reg_GB_DEBUG_IRQ"}
|
||||
gameboy.Reg_GB_DEBUG_DMA = {1056803,31,0,1,0,"gameboy.Reg_GB_DEBUG_DMA"}
|
||||
gameboy.Reg_GB_DEBUG_MEM = {1056804,31,0,1,0,"gameboy.Reg_GB_DEBUG_MEM"}
|
||||
gameboy.Reg_GB_CHEAT_FLAGS = {1056810,31,0,1,0,"gameboy.Reg_GB_CHEAT_FLAGS"}
|
||||
gameboy.Reg_GB_CHEAT_ADDRESS = {1056811,31,0,1,0,"gameboy.Reg_GB_CHEAT_ADDRESS"}
|
||||
gameboy.Reg_GB_CHEAT_COMPARE = {1056812,31,0,1,0,"gameboy.Reg_GB_CHEAT_COMPARE"}
|
||||
gameboy.Reg_GB_CHEAT_REPLACE = {1056813,31,0,1,0,"gameboy.Reg_GB_CHEAT_REPLACE"}
|
||||
gameboy.Reg_GB_CHEAT_RESET = {1056814,0,0,1,0,"gameboy.Reg_GB_CHEAT_RESET"}
|
||||
417
sim/tests/vsim_comm.lua
Normal file
417
sim/tests/vsim_comm.lua
Normal file
@@ -0,0 +1,417 @@
|
||||
function string:split(sep)
|
||||
local sep, fields = sep or ":", {}
|
||||
local pattern = string.format("([^%s]+)", sep)
|
||||
self:gsub(pattern, function(c) fields[#fields+1] = c end)
|
||||
return fields
|
||||
end
|
||||
|
||||
function conv_neg(x)
|
||||
if (x < 0) then
|
||||
return (2147483647 + (2147483649 - ((x * (-1)) )))
|
||||
else
|
||||
return x
|
||||
end
|
||||
end
|
||||
|
||||
function conv_to_neg(x)
|
||||
if (x > 2147483647) then
|
||||
return x - (2* 2147483648)
|
||||
else
|
||||
return x
|
||||
end
|
||||
end
|
||||
|
||||
function binary_and(a,b)
|
||||
local r = 0
|
||||
local neg = 1
|
||||
if (a < 0) then
|
||||
a = a * (-1)
|
||||
neg = neg * (-1)
|
||||
end
|
||||
if (b < 0) then
|
||||
b = b * (-1)
|
||||
neg = neg * (-1)
|
||||
end
|
||||
for i = 31, 0, -1 do
|
||||
local x = 2^i
|
||||
if (a >= x and b>=x) then
|
||||
r = r + 2^i
|
||||
end
|
||||
if (a >= x) then
|
||||
a = a - x
|
||||
end
|
||||
if (b >= x) then
|
||||
b = b - x
|
||||
end
|
||||
end
|
||||
return r * neg
|
||||
end
|
||||
|
||||
function binary_or(a,b)
|
||||
local r = 0
|
||||
local neg = 1
|
||||
if (a < 0) then
|
||||
a = a * (-1)
|
||||
neg = neg * (-1)
|
||||
end
|
||||
if (b < 0) then
|
||||
b = b * (-1)
|
||||
neg = neg * (-1)
|
||||
end
|
||||
for i = 31, 0, -1 do
|
||||
local x = 2^i
|
||||
if (a >= x or b>=x) then
|
||||
r = r + 2^i
|
||||
end
|
||||
if (a >= x) then
|
||||
a = a - x
|
||||
end
|
||||
if (b >= x) then
|
||||
b = b - x
|
||||
end
|
||||
end
|
||||
return r * neg
|
||||
end
|
||||
--------------
|
||||
-- file access
|
||||
--------------
|
||||
|
||||
inputfile = "../input.txt"
|
||||
outputfile = "../output.txt"
|
||||
|
||||
blockwritesize = 128
|
||||
wait_on_writeblock = true
|
||||
|
||||
function write_one(command)
|
||||
|
||||
local file = nil
|
||||
while (file == nil) do
|
||||
file=io.open(inputfile,"a+")
|
||||
end
|
||||
|
||||
io.output(file)
|
||||
|
||||
io.write(command)
|
||||
io.write("\n")
|
||||
|
||||
io.close(file)
|
||||
|
||||
end
|
||||
|
||||
function read_one(command)
|
||||
|
||||
local read_line = ""
|
||||
|
||||
command = string.sub(command, 1, #command - 1)
|
||||
|
||||
--print("#command: "..#command)
|
||||
|
||||
if (endpointer > 1000) then
|
||||
endpointer = endpointer - 1000
|
||||
else
|
||||
endpointer = 0
|
||||
end
|
||||
|
||||
while read_line ~= command do
|
||||
|
||||
local file = nil
|
||||
while (file == nil) do
|
||||
file=io.open(outputfile,"r")
|
||||
end
|
||||
|
||||
file:seek("set", endpointer)
|
||||
|
||||
local line = file:read()
|
||||
|
||||
while (line ~= nil) do
|
||||
|
||||
local buf_line = line
|
||||
|
||||
local ix = #command + 1
|
||||
while ix < #buf_line do
|
||||
if (string.sub(buf_line,ix,ix) == "#") then
|
||||
break
|
||||
end
|
||||
ix = ix + 1
|
||||
end
|
||||
|
||||
result = string.sub(buf_line,ix + 2,#buf_line - 1)
|
||||
buf_line = string.sub(buf_line,0,ix - 2)
|
||||
|
||||
--print("########")
|
||||
--print(line)
|
||||
--print(command)
|
||||
--print(buf_line)
|
||||
--print("Result:"..result)
|
||||
|
||||
if (buf_line == command) then
|
||||
read_line = buf_line
|
||||
break;
|
||||
end
|
||||
|
||||
line = file:read()
|
||||
|
||||
end
|
||||
|
||||
new_endpointer = file:seek("end")
|
||||
io.close(file)
|
||||
|
||||
end
|
||||
|
||||
endpointer = new_endpointer
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- connect commands
|
||||
-------------------
|
||||
|
||||
function reg_get_block_connection(reg, index, size)
|
||||
command_nr = command_nr + 1
|
||||
if (index == null) then index = 0 end
|
||||
|
||||
block = {}
|
||||
local readindex = 0
|
||||
local dataleft = size
|
||||
while (dataleft > 0) do
|
||||
|
||||
local blocksize = math.min(dataleft, 128)
|
||||
|
||||
command = "get # "..command_nr.." # "..process_id.." # ".."1".." # "..blocksize.." # "..(reg[1] + index).."&"
|
||||
write_one(command)
|
||||
values = read_one(command)
|
||||
|
||||
blockraw = values:split("#")
|
||||
for i = 1, blocksize do
|
||||
block[readindex] = tonumber(blockraw[i])
|
||||
readindex = readindex + 1
|
||||
end
|
||||
|
||||
dataleft = dataleft - blocksize
|
||||
index = index + blocksize
|
||||
|
||||
end
|
||||
|
||||
return block
|
||||
end
|
||||
|
||||
function reg_get_connection(reg, index)
|
||||
block = reg_get_block_connection(reg, index, 1)
|
||||
return block[0]
|
||||
end
|
||||
|
||||
function reg_set_block_connection(values, reg, index)
|
||||
if (index == null) then index = 0 end
|
||||
command_nr = command_nr + 1
|
||||
local length = (#values + 1)
|
||||
command = "set # "..command_nr.." # "..process_id.." # ".."1".." # "..math.min(blockwritesize, length).." # "..(reg[1] + index)
|
||||
local writecount = 0
|
||||
for i = 0, #values do
|
||||
value = conv_to_neg(values[i])
|
||||
command = command.." # "..value
|
||||
writecount = writecount + 1
|
||||
if (writecount == blockwritesize) then
|
||||
command = command.."&"
|
||||
write_one(command)
|
||||
if (wait_on_writeblock) then
|
||||
read_one(command)
|
||||
end
|
||||
writecount = 0
|
||||
index = index + blockwritesize
|
||||
command_nr = command_nr + 1
|
||||
length = length - blockwritesize
|
||||
command = "set # "..command_nr.." # "..process_id.." # ".."1".." # "..math.min(blockwritesize, length).." # "..(reg[1] + index)
|
||||
end
|
||||
end
|
||||
if (length > 0) then
|
||||
command = command.."&"
|
||||
write_one(command)
|
||||
if (wait_on_writeblock) then
|
||||
read_one(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function reg_set_connection(value, reg, index)
|
||||
values = {}
|
||||
values[0] = value
|
||||
reg_set_block_connection(values, reg, index)
|
||||
end
|
||||
|
||||
-----------
|
||||
-- commands
|
||||
-----------
|
||||
|
||||
function reg_filter(reg, value)
|
||||
|
||||
filter = 0
|
||||
for i = reg[3], reg[2] do
|
||||
filter = filter + 2^i;
|
||||
end
|
||||
|
||||
value = conv_neg(value)
|
||||
value = binary_and(value,filter);
|
||||
value = value / (2 ^ reg[3]);
|
||||
|
||||
return value
|
||||
|
||||
end
|
||||
|
||||
function reg_get(reg, index)
|
||||
value = reg_get_connection(reg, index)
|
||||
|
||||
value = reg_filter(reg, value)
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
function reg_get_block(reg, index, size)
|
||||
|
||||
block = reg_get_block_connection(reg, index, size)
|
||||
for i = 0, size - 1 do
|
||||
value = block[i]
|
||||
|
||||
filter = 0
|
||||
for i = reg[3], reg[2] do
|
||||
filter = filter + 2^i;
|
||||
end
|
||||
|
||||
value = conv_neg(value)
|
||||
value = binary_and(value,filter);
|
||||
value = value / (2 ^ reg[3]);
|
||||
|
||||
block[i] = value
|
||||
end
|
||||
|
||||
return block
|
||||
end
|
||||
|
||||
function reg_set_block(block, reg, index)
|
||||
reg_set_block_connection(block, reg, index)
|
||||
end
|
||||
|
||||
|
||||
function reg_set(value, reg, index)
|
||||
if (index == null) then index = 0 end
|
||||
|
||||
if (value < 100) then
|
||||
--print ("Address "..(reg[1] + index).."["..reg[2]..".."..reg[3].."] => "..value)
|
||||
else
|
||||
--print ("Address "..(reg[1] + index).."["..reg[2]..".."..reg[3].."] => 0x"..string.format("%X", value))
|
||||
end
|
||||
|
||||
-- find out if parameter is the only one in this register
|
||||
local singlereg = true
|
||||
local fullname = reg[6]
|
||||
local sectionname = fullname:split(".")[1]
|
||||
local secttable = _G[sectionname]
|
||||
for name, register in pairs(secttable) do
|
||||
if (register[1] == reg[1]) then
|
||||
if (register[6] ~= reg[6]) then
|
||||
singlereg = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
oldval = 0
|
||||
|
||||
if (singlereg == false) then
|
||||
|
||||
oldval = reg_get_connection(reg, index)
|
||||
|
||||
--print ("oldval= "..oldval.." at "..(reg[1]+index))
|
||||
|
||||
filter = 0
|
||||
for i = 0, reg[3] - 1 do
|
||||
filter = filter + 2^i;
|
||||
end
|
||||
for i = reg[2] + 1, 31 do
|
||||
filter = filter + 2^i;
|
||||
end
|
||||
oldval = binary_and(oldval,filter);
|
||||
|
||||
--print ("oldval filtered= "..oldval.." at "..(reg[1]+index).." with filter "..filter)
|
||||
|
||||
end
|
||||
|
||||
value = value * (2 ^ reg[3])
|
||||
value = binary_or(value, oldval);
|
||||
|
||||
reg_set_connection(value, reg, index)
|
||||
end
|
||||
|
||||
|
||||
function compare_reg(target, reg, index)
|
||||
if (index == null) then index = 0 end
|
||||
value = reg_get(reg, index)
|
||||
if (value == target) then
|
||||
if (value < 100 and target < 100) then
|
||||
print (reg[6].." -> Address "..(reg[1] + index).."["..reg[2]..".."..reg[3].."] = "..value.." - OK")
|
||||
else
|
||||
print (reg[6].." -> Address "..(reg[1] + index).."["..reg[2]..".."..reg[3].."] = 0x"..string.format("%X", value).." - OK")
|
||||
end
|
||||
return true
|
||||
else
|
||||
testerrorcount = testerrorcount + 1
|
||||
if (value < 100 and target < 100) then
|
||||
print (reg[6].." -> Address "..(reg[1] + index).."["..reg[2]..".."..reg[3].."] = "..value.." | should be = "..target.." - ERROR")
|
||||
else
|
||||
print (reg[6].." -> Address "..(reg[1] + index).."["..reg[2]..".."..reg[3].."] = 0x"..string.format("%X", tonumber(value)).." | should be = 0x"..string.format("%X", tonumber(target)).." - ERROR")
|
||||
end
|
||||
return false;
|
||||
end
|
||||
end
|
||||
|
||||
function reg_set_file(filename, baseaddress, index, endian)
|
||||
if (index == null) then index = 0 end
|
||||
if (endian == null) then endian = 0 end
|
||||
command_nr = command_nr + 1
|
||||
command = "fil # "..command_nr.." # "..process_id.." # "..endian.." # "..(baseaddress + index).." # "..filename
|
||||
command = command.."&"
|
||||
write_one(command)
|
||||
if (wait_on_writeblock) then
|
||||
read_one(command)
|
||||
end
|
||||
end
|
||||
|
||||
function wait_ns(waittime)
|
||||
command_nr = command_nr + 1
|
||||
command = "wtn # "..command_nr.." # "..process_id.." # "..waittime.."&"
|
||||
write_one(command)
|
||||
read_one(command)
|
||||
end
|
||||
|
||||
function brk()
|
||||
command_nr = command_nr + 1
|
||||
command = "brk&"
|
||||
write_one(command)
|
||||
end
|
||||
|
||||
function sleep(n) -- seconds
|
||||
local t0 = os.clock()
|
||||
while os.clock() - t0 <= n do end
|
||||
end
|
||||
|
||||
----------
|
||||
-- init
|
||||
----------
|
||||
|
||||
|
||||
seed = os.time() + os.clock() * 1000
|
||||
math.randomseed(seed)
|
||||
process_id = math.random(2147483647)
|
||||
process_id = math.random(2147483647)
|
||||
process_id = math.random(2147483647)
|
||||
process_id = math.random(2147483647)
|
||||
process_id = math.random(2147483647)
|
||||
|
||||
endpointer = 0
|
||||
|
||||
command_nr = 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
55
sim/vcom_all.bat
Normal file
55
sim/vcom_all.bat
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
vcom -93 -quiet -work sim/tb ^
|
||||
src/tb/globals.vhd
|
||||
|
||||
vcom -93 -quiet -work sim/mem ^
|
||||
src/mem/SyncFifo.vhd
|
||||
|
||||
vcom -quiet -work sim/rs232 ^
|
||||
src/rs232/rs232_receiver.vhd ^
|
||||
src/rs232/rs232_transmitter.vhd ^
|
||||
src/rs232/tbrs232_receiver.vhd ^
|
||||
src/rs232/tbrs232_transmitter.vhd
|
||||
|
||||
vcom -quiet -work sim/procbus ^
|
||||
src/procbus/proc_bus.vhd ^
|
||||
src/procbus/testprocessor.vhd
|
||||
|
||||
vcom -quiet -work sim/reg_map ^
|
||||
src/reg_map/reg_gameboy.vhd
|
||||
|
||||
vcom -quiet -work sim/gameboy ^
|
||||
../rtl/T80/T80_Pack.vhd ^
|
||||
../rtl/T80/T80_Reg.vhd ^
|
||||
../rtl/T80/T80_MCode.vhd ^
|
||||
../rtl/T80/T80_ALU.vhd ^
|
||||
../rtl/T80/T80.vhd ^
|
||||
../rtl/T80/GBse.vhd
|
||||
|
||||
vcom -quiet -work sim/gameboy ^
|
||||
../rtl/gbc_snd.vhd ^
|
||||
../rtl/boot_rom.vhd ^
|
||||
../rtl/speedcontrol.vhd ^
|
||||
../rtl/spram.vhd
|
||||
|
||||
vlog -sv -quiet -work sim/gameboy ^
|
||||
../rtl/sprites.v ^
|
||||
../rtl/timer.v ^
|
||||
../rtl/video.v ^
|
||||
../rtl/link.v ^
|
||||
../rtl/hdma.v
|
||||
|
||||
vlog -sv -O0 -quiet -work sim/gameboy ^
|
||||
../rtl/gb.v
|
||||
|
||||
vlog -sv -quiet -work sim/gameboy ^
|
||||
src/gameboy/cheatcodes.sv
|
||||
|
||||
vcom -quiet -work sim/tb ^
|
||||
src/tb/stringprocessor.vhd ^
|
||||
src/tb/tb_interpreter.vhd ^
|
||||
src/tb/framebuffer.vhd ^
|
||||
src/tb/gb_bios.vhd ^
|
||||
src/tb/sdram_model.vhd ^
|
||||
src/tb/tb.vhd
|
||||
|
||||
23
sim/vmap_all.bat
Normal file
23
sim/vmap_all.bat
Normal file
@@ -0,0 +1,23 @@
|
||||
RMDIR /s /q sim
|
||||
MKDIR sim
|
||||
|
||||
vmap altera_mf altera_mf
|
||||
|
||||
vlib sim/mem
|
||||
vmap mem sim/mem
|
||||
|
||||
vlib sim/rs232
|
||||
vmap rs232 sim/rs232
|
||||
|
||||
vlib sim/procbus
|
||||
vmap procbus sim/procbus
|
||||
|
||||
vlib sim/reg_map
|
||||
vmap reg_map sim/reg_map
|
||||
|
||||
vlib sim/gameboy
|
||||
vmap gameboy sim/gameboy
|
||||
|
||||
vlib sim/tb
|
||||
vmap tb sim/tb
|
||||
|
||||
1
sim/vsim_start.bat
Normal file
1
sim/vsim_start.bat
Normal file
@@ -0,0 +1 @@
|
||||
vsim -novopt tb.etb -t 1ps -suppress 8684
|
||||
Reference in New Issue
Block a user