Merge pull request #114 from RobertPeip/simulation

Simulation
This commit is contained in:
Alexey Melnikov
2020-12-16 03:38:43 +08:00
committed by GitHub
32 changed files with 3200 additions and 120 deletions

View File

@@ -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 /////////////////////////////////

View File

@@ -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

View File

@@ -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 ),

View File

@@ -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

View File

@@ -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
View 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;

View File

@@ -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

View File

@@ -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

Binary file not shown.

48
sim/readme.md Normal file
View 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.

View 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
View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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
View 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
View 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
View 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
View 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;

View 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
View 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;

View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
vsim -novopt tb.etb -t 1ps -suppress 8684