From 9a68d962331145cb8cf8f313e04da5fbeb2a5e49 Mon Sep 17 00:00:00 2001 From: David Banks Date: Sat, 27 Jun 2015 11:07:58 +0100 Subject: [PATCH] Initial checking of Z80 work; slight refactor of BusMonCore; version updated to 0.41 Change-Id: I95f574abb93e84ffb5ca44c45b4c9aa8304e2e58 --- .gitignore | 21 + Z80CpuMon.xise | 588 ++++++ firmware/AtomBusMon.c | 103 +- firmware/{Makefile.cpu => Makefile.6502cpu} | 12 +- firmware/{Makefile => Makefile.6502mon} | 13 +- firmware/Makefile.z80cpu | 52 + src/AtomBusMon.vhd | 10 +- src/AtomCpuMon.vhd | 10 +- src/BusMonCore.vhd | 24 +- src/T80/T80.vhd | 1107 ++++++++++ src/T80/T80_ALU.vhd | 371 ++++ src/T80/T80_MCode.vhd | 2024 +++++++++++++++++++ src/T80/T80_Pack.vhd | 229 +++ src/T80/T80_Reg.vhd | 114 ++ src/T80/T80_RegX.vhd | 176 ++ src/T80/T80a.vhd | 286 +++ src/Z80CpuMon.bmm | 38 + src/Z80CpuMon.ucf | 83 + src/Z80CpuMon.vhd | 266 +++ 19 files changed, 5462 insertions(+), 65 deletions(-) create mode 100644 Z80CpuMon.xise rename firmware/{Makefile.cpu => Makefile.6502cpu} (76%) rename firmware/{Makefile => Makefile.6502mon} (77%) create mode 100644 firmware/Makefile.z80cpu create mode 100644 src/T80/T80.vhd create mode 100644 src/T80/T80_ALU.vhd create mode 100644 src/T80/T80_MCode.vhd create mode 100644 src/T80/T80_Pack.vhd create mode 100644 src/T80/T80_Reg.vhd create mode 100644 src/T80/T80_RegX.vhd create mode 100644 src/T80/T80a.vhd create mode 100644 src/Z80CpuMon.bmm create mode 100644 src/Z80CpuMon.ucf create mode 100644 src/Z80CpuMon.vhd diff --git a/.gitignore b/.gitignore index 9484486..6561607 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,26 @@ AtomBusMon_guide.ncd AtomBusMon_summary.html src/AtomBusMon_bd.bmm src/AtomCpuMon_bd.bmm +src/AtomCpuMon_bd.bmm +src/Z80CpuMon_bd.bmm *~ #* +firmware/*.o +firmware/*.bit +firmware/avr_progmem.* +ipcore_dir/WatchEvents.asy +ipcore_dir/WatchEvents.gise +ipcore_dir/WatchEvents.ncf +ipcore_dir/WatchEvents.ngc +ipcore_dir/WatchEvents.sym +ipcore_dir/WatchEvents.vho +ipcore_dir/WatchEvents.xco +ipcore_dir/WatchEvents/ +ipcore_dir/WatchEvents_flist.txt +ipcore_dir/WatchEvents_xmdf.tcl +ipcore_dir/_xmsgs/ +ipcore_dir/coregen.cgp +ipcore_dir/coregen.log +ipcore_dir/create_WatchEvents.tcl +ipcore_dir/edit_WatchEvents.tcl +ipcore_dir/tmp/ diff --git a/Z80CpuMon.xise b/Z80CpuMon.xise new file mode 100644 index 0000000..e29d073 --- /dev/null +++ b/Z80CpuMon.xise @@ -0,0 +1,588 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/firmware/AtomBusMon.c b/firmware/AtomBusMon.c index c49ebc1..327c9d3 100644 --- a/firmware/AtomBusMon.c +++ b/firmware/AtomBusMon.c @@ -7,7 +7,14 @@ #include "hd44780.h" #include "status.h" -#ifdef EMBEDDED_6502 + +#if (CPU == Z80) +#define NAME "ICE-T80" +#else +#define NAME "ICE-T65" +#endif + +#ifdef CPUEMBEDDED unsigned int disMem(unsigned int addr); @@ -330,15 +337,19 @@ char *triggerStrings[NUM_TRIGGERS] = { }; -#define VERSION "0.37" +#define VERSION "0.41" -#ifdef EMBEDDED_6502 +#ifdef CPUEMBEDDED #define NUM_CMDS 27 #else #define NUM_CMDS 19 #endif +#if (CPU == Z80) +#define MAXBKPTS 1 +#else #define MAXBKPTS 8 +#endif int numbkpts = 0; @@ -350,6 +361,7 @@ unsigned int memAddr = 0; char statusString[8] = "NV-BDIZC"; unsigned int breakpoints[MAXBKPTS] = { +#if (CPU != Z80) 0, 0, 0, @@ -357,10 +369,12 @@ unsigned int breakpoints[MAXBKPTS] = { 0, 0, 0, +#endif 0 }; unsigned int masks[MAXBKPTS] = { +#if (CPU != Z80) 0, 0, 0, @@ -368,10 +382,12 @@ unsigned int masks[MAXBKPTS] = { 0, 0, 0, +#endif 0 }; unsigned int modes[MAXBKPTS] = { +#if (CPU != Z80) 0, 0, 0, @@ -379,10 +395,12 @@ unsigned int modes[MAXBKPTS] = { 0, 0, 0, +#endif 0 }; int triggers[MAXBKPTS] = { +#if (CPU != Z80) 0, 0, 0, @@ -390,6 +408,7 @@ int triggers[MAXBKPTS] = { 0, 0, 0, +#endif 0 }; @@ -397,7 +416,7 @@ int triggers[MAXBKPTS] = { char *cmdStrings[NUM_CMDS] = { "help", "continue", -#ifdef EMBEDDED_6502 +#ifdef CPUEMBEDDED "regs", "mem", "dis", @@ -515,8 +534,13 @@ void setTrace(long i) { } void version() { - log0("Atom Bus Monitor version %s\n", VERSION); +#ifdef CPUEMBEDDED + log0("%s In-Circuit Emulator version %s\n", NAME, VERSION); +#else + log0("%s Bus Monitor version %s\n", NAME, VERSION); +#endif log0("Compiled at %s on %s\n",__TIME__,__DATE__); + log0("%d watches/breakpoints implemented\n",MAXBKPTS); } @@ -606,29 +630,25 @@ int logDetails() { } logMode(mode); log0(" hit at %04X", i_addr); - if (mode & BW_MEM_MASK) { - if (mode & W_MEM_MASK) { - log0(" writing"); - } else { - log0(" reading"); - } - log0(" %04X = %02X\n", b_addr, b_data); - if (mode & B_MASK) { - logCycleCount(OFFSET_BW_CNTL, OFFSET_BW_CNTH); - } -#ifdef EMBEDDED_6502 - if (mode & B_MEM_MASK) { - // It's only safe to do this for brkpts, as it makes memory accesses - disMem(i_addr); - } -#endif + if (mode & W_MEM_MASK) { + log0(" writing"); } else { - log0("\n"); + log0(" reading"); } + log0(" %04X = %02X\n", b_addr, b_data); + if (mode & B_MASK) { + logCycleCount(OFFSET_BW_CNTL, OFFSET_BW_CNTH); + } +#ifdef CPUEMBEDDED + if (mode & B_MEM_MASK) { + // It's only safe to do this for brkpts, as it makes memory accesses + disMem(i_addr); + } +#endif return watch; } -#ifdef EMBEDDED_6502 +#ifdef CPUEMBEDDED void loadData(unsigned int data) { int i; for (i = 0; i <= 7; i++) { @@ -756,7 +776,7 @@ void logAddr() { #endif // Update the serial console logCycleCount(OFFSET_CNTL, OFFSET_CNTH); -#ifdef EMBEDDED_6502 +#ifdef CPUEMBEDDED //log0("%04X\n", i_addr); disMem(memAddr); #else @@ -793,7 +813,7 @@ void doCmdStep(char *params) { j = trace; for (i = 1; i <= instructions; i++) { - // Step the 6502 + // Step the CPU hwCmd(CMD_STEP, 0); if (i == instructions || (trace && (--j == 0))) { Delay_us(10); @@ -804,7 +824,7 @@ void doCmdStep(char *params) { } void doCmdReset(char *params) { - log0("Resetting 6502\n"); + log0("Resetting CPU\n"); hwCmd(CMD_RESET, 1); Delay_us(50); hwCmd(CMD_STEP, 0); @@ -812,15 +832,15 @@ void doCmdReset(char *params) { hwCmd(CMD_RESET, 0); } -#ifdef EMBEDDED_6502 +#ifdef CPUEMBEDDED void doCmdRegs(char *params) { int i; - log0("6502 Registers:\n"); - log0(" A=%02X X=%02X Y=%02X SP=01%02X PC=%04X\n", + log0("CPU Registers:\n"); + log0(" A=%02X X=%02X Y=%02X SP=%04X PC=%04X\n", hwRead8(OFFSET_REG_A), hwRead8(OFFSET_REG_X), hwRead8(OFFSET_REG_Y), - hwRead8(OFFSET_REG_SPL), + hwRead16(OFFSET_REG_SPL), hwRead16(OFFSET_REG_PCL)); unsigned int p = hwRead8(OFFSET_REG_P); char *sp = statusString; @@ -1210,10 +1230,9 @@ void doCmdContinue(char *params) { #ifdef LCD unsigned int i_addr; #endif - - // Step the 6502, otherwise the breakpoint happends again immediately - hwCmd(CMD_STEP, 0); - + int reset = 0; + sscanf(params, "%d", &reset); + // Disable breakpoints to allow loading hwCmd(CMD_BRKPT_ENABLE, 0); @@ -1225,14 +1244,25 @@ void doCmdContinue(char *params) { shiftBreakpointRegister(0, 0, 0, 0); } + // Step the 6502, otherwise the breakpoint happends again immediately + hwCmd(CMD_STEP, 0); + // Enable breakpoints hwCmd(CMD_BRKPT_ENABLE, 1); // Disable single stepping setSingle(0); + // Reset if required + if (reset) { + log0("Resetting CPU\n"); + hwCmd(CMD_RESET, 1); + Delay_us(100); + hwCmd(CMD_RESET, 0); + } + // Wait for breakpoint to become active - log0("6502 free running...\n"); + log0("CPU free running...\n"); int cont = 1; do { // Update the LCD display @@ -1268,7 +1298,6 @@ void doCmdContinue(char *params) { logAddr(); } - void initialize() { CTRL_DDR = 255; STATUS_DDR = MUXSEL_MASK; @@ -1289,7 +1318,7 @@ void initialize() { void (*cmdFuncs[NUM_CMDS])(char *params) = { doCmdHelp, doCmdContinue, -#ifdef EMBEDDED_6502 +#ifdef CPUEMBEDDED doCmdRegs, doCmdMem, doCmdDis, diff --git a/firmware/Makefile.cpu b/firmware/Makefile.6502cpu similarity index 76% rename from firmware/Makefile.cpu rename to firmware/Makefile.6502cpu index 9df9d23..c539779 100644 --- a/firmware/Makefile.cpu +++ b/firmware/Makefile.6502cpu @@ -23,16 +23,14 @@ F_CPU=15855484 CC=avr-gcc OBJCOPY=avr-objcopy -CFLAGS=-DEMBEDDED_6502=1 -DF_CPU=${F_CPU}UL -DSERIAL_STATUS -DCOOKED_SERIAL -DNOUSART1 -mmcu=$(MCU) -Wall -Os -mcall-prologues +CFLAGS=-DCPU=6502 -DCPUEMBEDDED -DF_CPU=${F_CPU}UL -DSERIAL_STATUS -DCOOKED_SERIAL -DNOUSART1 -mmcu=$(MCU) -Wall -Os -mcall-prologues OBJECTS=AtomBusMon.o hd44780.o status.o -load: avr.bit -# sudo $(PROG) -v -f avr.bit -# sudo $(PROG) -v -b $(BSCAN) -f avr.bit -sa -r +build: avr6502cpu.bit -avr.bit: avr_progmem.mem - $(DATA2MEM) -bm $(BMM_FILE) -bd avr_progmem.mem -bt $(BIT_FILE) -o b avr.bit +avr6502cpu.bit: avr_progmem.mem + $(DATA2MEM) -bm $(BMM_FILE) -bd avr_progmem.mem -bt $(BIT_FILE) -o b avr6502cpu.bit avr_progmem.mem: avr_progmem.hex $(SREC_CAT) $< -Intel -Byte_Swap 2 -Data_Only -o tmp.mem -vmem 8 @@ -52,4 +50,4 @@ avr_progmem.out : $(OBJECTS) .phony: clean clean: - rm -f avr.bit avr_progmem.mem avr_progmem.hex avr_progmem.out avr_progmem.map *.o + rm -f avr6502cpu.bit avr_progmem.mem avr_progmem.hex avr_progmem.out avr_progmem.map *.o diff --git a/firmware/Makefile b/firmware/Makefile.6502mon similarity index 77% rename from firmware/Makefile rename to firmware/Makefile.6502mon index 3b6e512..ee36576 100644 --- a/firmware/Makefile +++ b/firmware/Makefile.6502mon @@ -23,23 +23,20 @@ F_CPU=15855484 CC=avr-gcc OBJCOPY=avr-objcopy -CFLAGS=-DF_CPU=${F_CPU}UL -DSERIAL_STATUS -DCOOKED_SERIAL -DNOUSART1 -mmcu=$(MCU) -Wall -Os -mcall-prologues +CFLAGS=-DCPU=6502 -DF_CPU=${F_CPU}UL -DSERIAL_STATUS -DCOOKED_SERIAL -DNOUSART1 -mmcu=$(MCU) -Wall -Os -mcall-prologues OBJECTS=AtomBusMon.o hd44780.o status.o -load: avr.bit -# sudo $(PROG) -v -f avr.bit -# sudo $(PROG) -v -b $(BSCAN) -f avr.bit -sa -r +build: avr6502mon.bit -avr.bit: avr_progmem.mem - $(DATA2MEM) -bm $(BMM_FILE) -bd avr_progmem.mem -bt $(BIT_FILE) -o b avr.bit +avr6502mon.bit: avr_progmem.mem + $(DATA2MEM) -bm $(BMM_FILE) -bd avr_progmem.mem -bt $(BIT_FILE) -o b avr6502mon.bit avr_progmem.mem: avr_progmem.hex $(SREC_CAT) $< -Intel -Byte_Swap 2 -Data_Only -o tmp.mem -vmem 8 $(GAWK) ' BEGIN{FS=" ";} { $$1= ""; print}' tmp.mem > $@ rm tmp.mem - avr_progmem.hex : avr_progmem.out $(OBJCOPY) -R .eeprom -O ihex avr_progmem.out avr_progmem.hex avr_progmem.out : $(OBJECTS) @@ -52,4 +49,4 @@ avr_progmem.out : $(OBJECTS) .phony: clean clean: - rm -f avr.bit avr_progmem.mem avr_progmem.hex avr_progmem.out avr_progmem.map *.o + rm -f avr6502mon.bit avr_progmem.mem avr_progmem.hex avr_progmem.out avr_progmem.map *.o diff --git a/firmware/Makefile.z80cpu b/firmware/Makefile.z80cpu new file mode 100644 index 0000000..36ce42e --- /dev/null +++ b/firmware/Makefile.z80cpu @@ -0,0 +1,52 @@ +# Paths that will need changing + +ATOMFPGA=$(HOME)/atom/AtomBusMon +PAPILIO_LOADER=/opt/GadgetFactory/papilio-loader/programmer +XILINX=/opt/Xilinx/14.7 + +# Shouldn't need to make changes below this point + +BIT_FILE=$(ATOMFPGA)/working/Z80CpuMon.bit +BMM_FILE=$(ATOMFPGA)/src/Z80CpuMon_bd.bmm + + +# Papilio dev environment +PROG=${PAPILIO_LOADER}/linux32/papilio-prog +BSCAN=${PAPILIO_LOADER}/bscan_spi_xc3s500e.bit +SREC_CAT=srec_cat +GAWK=gawk +DATA2MEM=${XILINX}/ISE_DS/ISE/bin/lin/data2mem + +# AVR dev environment +MCU=atmega103 +F_CPU=15855484 +CC=avr-gcc +OBJCOPY=avr-objcopy + +CFLAGS=-DCPU=Z80 -DCPUEMBEDDED -DF_CPU=${F_CPU}UL -DSERIAL_STATUS -DCOOKED_SERIAL -DNOUSART1 -mmcu=$(MCU) -Wall -Os -mcall-prologues + +OBJECTS=AtomBusMon.o hd44780.o status.o + +build: avrz80cpu.bit + +avrz80cpu.bit: avr_progmem.mem + $(DATA2MEM) -bm $(BMM_FILE) -bd avr_progmem.mem -bt $(BIT_FILE) -o b avrz80cpu.bit + +avr_progmem.mem: avr_progmem.hex + $(SREC_CAT) $< -Intel -Byte_Swap 2 -Data_Only -o tmp.mem -vmem 8 + $(GAWK) ' BEGIN{FS=" ";} { $$1= ""; print}' tmp.mem > $@ + rm tmp.mem + +avr_progmem.hex : avr_progmem.out + $(OBJCOPY) -R .eeprom -O ihex avr_progmem.out avr_progmem.hex +avr_progmem.out : $(OBJECTS) + $(CC) $(CFLAGS) -o avr_progmem.out -Wl,-Map,avr_progmem.map $^ +%.o : %.c + $(CC) $(CFLAGS) -Os -c $< +%.o : %.S + $(CC) $(CFLAGS) -Os -c $< + +.phony: clean + +clean: + rm -f avrz80cpu.bit avr_progmem.mem avr_progmem.hex avr_progmem.out avr_progmem.map *.o diff --git a/src/AtomBusMon.vhd b/src/AtomBusMon.vhd index 80f186e..8d5fada 100644 --- a/src/AtomBusMon.vhd +++ b/src/AtomBusMon.vhd @@ -70,10 +70,12 @@ begin Addr => Addr, Data => (others => '0'), Phi2 => Phi2, - RNW => RNW, + Rd_n => not RNW, + Wr_n => RNW, Sync => Sync, Rdy => Rdy, - nRST => nRST, + nRSTin => nRST, + nRSTout => nRST, Regs => (others => '0'), RdOut => open, WrOut => open, @@ -94,7 +96,9 @@ begin led8 => led8, tmosi => tmosi, tdin => tdin, - tcclk => tcclk + tcclk => tcclk, + SS_Step => open, + SS_Single => open ); end behavioral; diff --git a/src/AtomCpuMon.vhd b/src/AtomCpuMon.vhd index 31c59b6..f6a2de1 100644 --- a/src/AtomCpuMon.vhd +++ b/src/AtomCpuMon.vhd @@ -105,10 +105,12 @@ begin Addr => Addr_int, Data => Data, Phi2 => busmon_clk, - RNW => R_W_n_int, + Rd_n => not R_W_n_int, + Wr_n => R_W_n_int, Sync => Sync_int, Rdy => Rdy_int, - nRST => Res_n, + nRSTin => Res_n, + nRSTout => Res_n, trig => trig, lcd_rs => open, lcd_rw => open, @@ -129,7 +131,9 @@ begin WrOut => memory_wr, AddrOut => memory_addr, DataOut => memory_dout, - DataIn => memory_din + DataIn => memory_din, + SS_Step => open, + SS_Single => open ); GenT65Core: if UseT65Core generate diff --git a/src/BusMonCore.vhd b/src/BusMonCore.vhd index 8106733..a6dc748 100644 --- a/src/BusMonCore.vhd +++ b/src/BusMonCore.vhd @@ -35,10 +35,12 @@ entity BusMonCore is Addr : in std_logic_vector(15 downto 0); Data : in std_logic_vector(7 downto 0); Phi2 : in std_logic; - RNW : in std_logic; + Rd_n : in std_logic; + Wr_n : in std_logic; Sync : in std_logic; Rdy : out std_logic; - nRST : inout std_logic; + nRSTin : in std_logic; + nRSTout : out std_logic; -- 6502 Registers -- unused in pure bus monitor mode @@ -52,6 +54,10 @@ entity BusMonCore is DataOut : out std_logic_vector(7 downto 0); DataIn : in std_logic_vector(7 downto 0); + -- Single Step interface + SS_Single : out std_logic; + SS_Step : out std_logic; + -- External trigger inputs trig : in std_logic_vector(1 downto 0); @@ -334,7 +340,7 @@ begin status := "1001"; end if; else - if (RNW = '1') then + if (Rd_n = '0') then if (reg_mode_bar = '1') then bactive := '1'; status := "0010"; @@ -343,7 +349,8 @@ begin wactive := '1'; status := "1010"; end if; - else + end if; + if (Wr_n = '0') then if (reg_mode_baw = '1') then bactive := '1'; status := "0100"; @@ -381,7 +388,7 @@ begin if rising_edge(Phi2) then -- Cycle counter, wraps every 16s at 1MHz - if (nRST = '0') then + if (nRSTin = '0') then cycleCount <= (others => '0'); elsif (Rdy_int = '1') then cycleCount <= cycleCount + 1; @@ -396,6 +403,7 @@ begin memory_rd <= '0'; memory_wr <= '0'; auto_inc <= '0'; + SS_Step <= '0'; if (cmd_edge2 = '0' and cmd_edge1 = '1') then if (cmd(4 downto 1) = "0000") then single <= cmd(0); @@ -449,15 +457,16 @@ begin if ((single = '0') or (cmd_edge2 = '0' and cmd_edge1 = '1' and cmd = "01000")) then Rdy_int <= (not brkpt_active); + SS_Step <= '1'; else Rdy_int <= (not Sync); end if; -- 6502 Reset needs to be open collector if (reset = '1') then - nRST <= '0'; + nRSTout <= '0'; else - nRST <= 'Z'; + nRSTout <= 'Z'; end if; -- Latch instruction address for the whole cycle @@ -494,6 +503,7 @@ begin WrOut <= memory_wr; AddrOut <= addr_dout_reg(23 downto 8); DataOut <= addr_dout_reg(7 downto 0); + SS_Single <= single; end behavioral; diff --git a/src/T80/T80.vhd b/src/T80/T80.vhd new file mode 100644 index 0000000..b9746b6 --- /dev/null +++ b/src/T80/T80.vhd @@ -0,0 +1,1107 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 303 add undocumented DDCB and FDCB opcodes by TobiFlex 20.04.2010 +-- Ver 302 fixed IO cycle timing, tested thanks to Alessandro. +-- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle +-- Ver 300 started tidyup. Rmoved some auto_wait bits from 0247 which caused problems +-- +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- Z80 compatible microprocessor core +-- +-- Version : 0247 +-- +-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t80/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0208 : First complete release +-- +-- 0210 : Fixed wait and halt +-- +-- 0211 : Fixed Refresh addition and IM 1 +-- +-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test +-- +-- 0232 : Removed refresh address output for Mode > 1 and added DJNZ M1_n fix by Mike Johnson +-- +-- 0235 : Added clock enable and IM 2 fix by Mike Johnson +-- +-- 0237 : Changed 8080 I/O address output, added IntE output +-- +-- 0238 : Fixed (IX/IY+d) timing and 16 bit ADC and SBC zero flag +-- +-- 0240 : Added interrupt ack fix by Mike Johnson, changed (IX/IY+d) timing and changed flags in GB mode +-- +-- 0242 : Added I/O wait, fixed refresh address, moved some registers to RAM +-- +-- 0247 : Fixed bus req/ack cycle +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T80_Pack.all; + +entity T80 is + generic( + Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB + IOWait : integer := 0; -- 1 => Single cycle I/O, 1 => Std I/O cycle + Flag_C : integer := 0; + Flag_N : integer := 1; + Flag_P : integer := 2; + Flag_X : integer := 3; + Flag_H : integer := 4; + Flag_Y : integer := 5; + Flag_Z : integer := 6; + Flag_S : integer := 7 + ); + port( + RESET_n : in std_logic; + CLK_n : in std_logic; + CEN : in std_logic; + WAIT_n : in std_logic; + INT_n : in std_logic; + NMI_n : in std_logic; + BUSRQ_n : in std_logic; + M1_n : out std_logic; + IORQ : out std_logic; + NoRead : out std_logic; + Write : out std_logic; + RFSH_n : out std_logic; + HALT_n : out std_logic; + BUSAK_n : out std_logic; + A : out std_logic_vector(15 downto 0); + DInst : in std_logic_vector(7 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + MC : out std_logic_vector(2 downto 0); + TS : out std_logic_vector(2 downto 0); + IntCycle_n : out std_logic; + IntE : out std_logic; + Stop : out std_logic; + Regs : out std_logic_vector(63 downto 0) + + ); +end T80; + +architecture rtl of T80 is + + -- Registers + signal ACC, F : std_logic_vector(7 downto 0); + signal Ap, Fp : std_logic_vector(7 downto 0); + signal I : std_logic_vector(7 downto 0); + signal R : unsigned(7 downto 0); + signal SP, PC : unsigned(15 downto 0); + + signal RegDIH : std_logic_vector(7 downto 0); + signal RegDIL : std_logic_vector(7 downto 0); + signal RegBusA : std_logic_vector(15 downto 0); + signal RegBusB : std_logic_vector(15 downto 0); + signal RegBusC : std_logic_vector(15 downto 0); + signal RegAddrA_r : std_logic_vector(2 downto 0); + signal RegAddrA : std_logic_vector(2 downto 0); + signal RegAddrB_r : std_logic_vector(2 downto 0); + signal RegAddrB : std_logic_vector(2 downto 0); + signal RegAddrC : std_logic_vector(2 downto 0); + signal RegWEH : std_logic; + signal RegWEL : std_logic; + signal Alternate : std_logic; + + -- Help Registers + signal TmpAddr : std_logic_vector(15 downto 0); -- Temporary address register + signal IR : std_logic_vector(7 downto 0); -- Instruction register + signal ISet : std_logic_vector(1 downto 0); -- Instruction set selector + signal RegBusA_r : std_logic_vector(15 downto 0); + + signal ID16 : signed(15 downto 0); + signal Save_Mux : std_logic_vector(7 downto 0); + + signal TState : unsigned(2 downto 0); + signal MCycle : std_logic_vector(2 downto 0); + signal IntE_FF1 : std_logic; + signal IntE_FF2 : std_logic; + signal Halt_FF : std_logic; + signal BusReq_s : std_logic; + signal BusAck : std_logic; + signal ClkEn : std_logic; + signal NMI_s : std_logic; + signal INT_s : std_logic; + signal IStatus : std_logic_vector(1 downto 0); + + signal DI_Reg : std_logic_vector(7 downto 0); + signal T_Res : std_logic; + signal XY_State : std_logic_vector(1 downto 0); + signal Pre_XY_F_M : std_logic_vector(2 downto 0); + signal NextIs_XY_Fetch : std_logic; + signal XY_Ind : std_logic; + signal No_BTR : std_logic; + signal BTR_r : std_logic; + signal Auto_Wait : std_logic; + signal Auto_Wait_t1 : std_logic; + signal Auto_Wait_t2 : std_logic; + signal IncDecZ : std_logic; + + -- ALU signals + signal BusB : std_logic_vector(7 downto 0); + signal BusA : std_logic_vector(7 downto 0); + signal ALU_Q : std_logic_vector(7 downto 0); + signal F_Out : std_logic_vector(7 downto 0); + + -- Registered micro code outputs + signal Read_To_Reg_r : std_logic_vector(4 downto 0); + signal Arith16_r : std_logic; + signal Z16_r : std_logic; + signal ALU_Op_r : std_logic_vector(3 downto 0); + signal Save_ALU_r : std_logic; + signal PreserveC_r : std_logic; + signal MCycles : std_logic_vector(2 downto 0); + + -- Micro code outputs + signal MCycles_d : std_logic_vector(2 downto 0); + signal TStates : std_logic_vector(2 downto 0); + signal IntCycle : std_logic; + signal NMICycle : std_logic; + signal Inc_PC : std_logic; + signal Inc_WZ : std_logic; + signal IncDec_16 : std_logic_vector(3 downto 0); + signal Prefix : std_logic_vector(1 downto 0); + signal Read_To_Acc : std_logic; + signal Read_To_Reg : std_logic; + signal Set_BusB_To : std_logic_vector(3 downto 0); + signal Set_BusA_To : std_logic_vector(3 downto 0); + signal ALU_Op : std_logic_vector(3 downto 0); + signal Save_ALU : std_logic; + signal PreserveC : std_logic; + signal Arith16 : std_logic; + signal Set_Addr_To : std_logic_vector(2 downto 0); + signal Jump : std_logic; + signal JumpE : std_logic; + signal JumpXY : std_logic; + signal Call : std_logic; + signal RstP : std_logic; + signal LDZ : std_logic; + signal LDW : std_logic; + signal LDSPHL : std_logic; + signal IORQ_i : std_logic; + signal Special_LD : std_logic_vector(2 downto 0); + signal ExchangeDH : std_logic; + signal ExchangeRp : std_logic; + signal ExchangeAF : std_logic; + signal ExchangeRS : std_logic; + signal I_DJNZ : std_logic; + signal I_CPL : std_logic; + signal I_CCF : std_logic; + signal I_SCF : std_logic; + signal I_RETN : std_logic; + signal I_BT : std_logic; + signal I_BC : std_logic; + signal I_BTR : std_logic; + signal I_RLD : std_logic; + signal I_RRD : std_logic; + signal I_INRC : std_logic; + signal SetDI : std_logic; + signal SetEI : std_logic; + signal IMode : std_logic_vector(1 downto 0); + signal Halt : std_logic; + signal XYbit_undoc : std_logic; + + +begin + + Regs(31 downto 0) <= (others => '0'); + Regs(47 downto 32) <= std_logic_vector(SP); + Regs(63 downto 48) <= std_logic_vector(PC); + + + mcode : T80_MCode + generic map( + Mode => Mode, + Flag_C => Flag_C, + Flag_N => Flag_N, + Flag_P => Flag_P, + Flag_X => Flag_X, + Flag_H => Flag_H, + Flag_Y => Flag_Y, + Flag_Z => Flag_Z, + Flag_S => Flag_S) + port map( + IR => IR, + ISet => ISet, + MCycle => MCycle, + F => F, + NMICycle => NMICycle, + IntCycle => IntCycle, + XY_State => XY_State, + MCycles => MCycles_d, + TStates => TStates, + Prefix => Prefix, + Inc_PC => Inc_PC, + Inc_WZ => Inc_WZ, + IncDec_16 => IncDec_16, + Read_To_Acc => Read_To_Acc, + Read_To_Reg => Read_To_Reg, + Set_BusB_To => Set_BusB_To, + Set_BusA_To => Set_BusA_To, + ALU_Op => ALU_Op, + Save_ALU => Save_ALU, + PreserveC => PreserveC, + Arith16 => Arith16, + Set_Addr_To => Set_Addr_To, + IORQ => IORQ_i, + Jump => Jump, + JumpE => JumpE, + JumpXY => JumpXY, + Call => Call, + RstP => RstP, + LDZ => LDZ, + LDW => LDW, + LDSPHL => LDSPHL, + Special_LD => Special_LD, + ExchangeDH => ExchangeDH, + ExchangeRp => ExchangeRp, + ExchangeAF => ExchangeAF, + ExchangeRS => ExchangeRS, + I_DJNZ => I_DJNZ, + I_CPL => I_CPL, + I_CCF => I_CCF, + I_SCF => I_SCF, + I_RETN => I_RETN, + I_BT => I_BT, + I_BC => I_BC, + I_BTR => I_BTR, + I_RLD => I_RLD, + I_RRD => I_RRD, + I_INRC => I_INRC, + SetDI => SetDI, + SetEI => SetEI, + IMode => IMode, + Halt => Halt, + NoRead => NoRead, + Write => Write, + XYbit_undoc => XYbit_undoc); + + alu : T80_ALU + generic map( + Mode => Mode, + Flag_C => Flag_C, + Flag_N => Flag_N, + Flag_P => Flag_P, + Flag_X => Flag_X, + Flag_H => Flag_H, + Flag_Y => Flag_Y, + Flag_Z => Flag_Z, + Flag_S => Flag_S) + port map( + Arith16 => Arith16_r, + Z16 => Z16_r, + ALU_Op => ALU_Op_r, + IR => IR(5 downto 0), + ISet => ISet, + BusA => BusA, + BusB => BusB, + F_In => F, + Q => ALU_Q, + F_Out => F_Out); + + ClkEn <= CEN and not BusAck; + + T_Res <= '1' when TState = unsigned(TStates) else '0'; + + NextIs_XY_Fetch <= '1' when XY_State /= "00" and XY_Ind = '0' and + ((Set_Addr_To = aXY) or + (MCycle = "001" and IR = "11001011") or + (MCycle = "001" and IR = "00110110")) else '0'; + + Save_Mux <= BusB when ExchangeRp = '1' else + DI_Reg when Save_ALU_r = '0' else + ALU_Q; + + process (RESET_n, CLK_n) + begin + if RESET_n = '0' then + PC <= (others => '0'); -- Program Counter + A <= (others => '0'); + TmpAddr <= (others => '0'); + IR <= "00000000"; + ISet <= "00"; + XY_State <= "00"; + IStatus <= "00"; + MCycles <= "000"; + DO <= "00000000"; + + ACC <= (others => '1'); + F <= (others => '1'); + Ap <= (others => '1'); + Fp <= (others => '1'); + I <= (others => '0'); + R <= (others => '0'); + SP <= (others => '1'); + Alternate <= '0'; + + Read_To_Reg_r <= "00000"; + F <= (others => '1'); + Arith16_r <= '0'; + BTR_r <= '0'; + Z16_r <= '0'; + ALU_Op_r <= "0000"; + Save_ALU_r <= '0'; + PreserveC_r <= '0'; + XY_Ind <= '0'; + + elsif CLK_n'event and CLK_n = '1' then + + if ClkEn = '1' then + + ALU_Op_r <= "0000"; + Save_ALU_r <= '0'; + Read_To_Reg_r <= "00000"; + + MCycles <= MCycles_d; + + if Mode = 3 then + IStatus <= "10"; + elsif IMode /= "11" then + IStatus <= IMode; + end if; + + Arith16_r <= Arith16; + PreserveC_r <= PreserveC; + if ISet = "10" and ALU_OP(2) = '0' and ALU_OP(0) = '1' and MCycle = "011" then + Z16_r <= '1'; + else + Z16_r <= '0'; + end if; + + if MCycle = "001" and TState(2) = '0' then + -- MCycle = 1 and TState = 1, 2, or 3 + + if TState = 2 and Wait_n = '1' then + if Mode < 2 then + A(7 downto 0) <= std_logic_vector(R); + A(15 downto 8) <= I; + R(6 downto 0) <= R(6 downto 0) + 1; + end if; + + if Jump = '0' and Call = '0' and NMICycle = '0' and IntCycle = '0' and not (Halt_FF = '1' or Halt = '1') then + PC <= PC + 1; + end if; + + if IntCycle = '1' and IStatus = "01" then + IR <= "11111111"; + elsif Halt_FF = '1' or (IntCycle = '1' and IStatus = "10") or NMICycle = '1' then + IR <= "00000000"; + else + IR <= DInst; + end if; + + ISet <= "00"; + if Prefix /= "00" then + if Prefix = "11" then + if IR(5) = '1' then + XY_State <= "10"; + else + XY_State <= "01"; + end if; + else + if Prefix = "10" then + XY_State <= "00"; + XY_Ind <= '0'; + end if; + ISet <= Prefix; + end if; + else + XY_State <= "00"; + XY_Ind <= '0'; + end if; + end if; + + else + -- either (MCycle > 1) OR (MCycle = 1 AND TState > 3) + + if MCycle = "110" then + XY_Ind <= '1'; + if Prefix = "01" then + ISet <= "01"; + end if; + end if; + + if T_Res = '1' then + BTR_r <= (I_BT or I_BC or I_BTR) and not No_BTR; + if Jump = '1' then + A(15 downto 8) <= DI_Reg; + A(7 downto 0) <= TmpAddr(7 downto 0); + PC(15 downto 8) <= unsigned(DI_Reg); + PC(7 downto 0) <= unsigned(TmpAddr(7 downto 0)); + elsif JumpXY = '1' then + A <= RegBusC; + PC <= unsigned(RegBusC); + elsif Call = '1' or RstP = '1' then + A <= TmpAddr; + PC <= unsigned(TmpAddr); + elsif MCycle = MCycles and NMICycle = '1' then + A <= "0000000001100110"; + PC <= "0000000001100110"; + elsif MCycle = "011" and IntCycle = '1' and IStatus = "10" then + A(15 downto 8) <= I; + A(7 downto 0) <= TmpAddr(7 downto 0); + PC(15 downto 8) <= unsigned(I); + PC(7 downto 0) <= unsigned(TmpAddr(7 downto 0)); + else + case Set_Addr_To is + when aXY => + if XY_State = "00" then + A <= RegBusC; + else + if NextIs_XY_Fetch = '1' then + A <= std_logic_vector(PC); + else + A <= TmpAddr; + end if; + end if; + when aIOA => + if Mode = 3 then + -- Memory map I/O on GBZ80 + A(15 downto 8) <= (others => '1'); + elsif Mode = 2 then + -- Duplicate I/O address on 8080 + A(15 downto 8) <= DI_Reg; + else + A(15 downto 8) <= ACC; + end if; + A(7 downto 0) <= DI_Reg; + when aSP => + A <= std_logic_vector(SP); + when aBC => + if Mode = 3 and IORQ_i = '1' then + -- Memory map I/O on GBZ80 + A(15 downto 8) <= (others => '1'); + A(7 downto 0) <= RegBusC(7 downto 0); + else + A <= RegBusC; + end if; + when aDE => + A <= RegBusC; + when aZI => + if Inc_WZ = '1' then + A <= std_logic_vector(unsigned(TmpAddr) + 1); + else + A(15 downto 8) <= DI_Reg; + A(7 downto 0) <= TmpAddr(7 downto 0); + end if; + when others => + A <= std_logic_vector(PC); + end case; + end if; + + Save_ALU_r <= Save_ALU; + ALU_Op_r <= ALU_Op; + + if I_CPL = '1' then + -- CPL + ACC <= not ACC; + F(Flag_Y) <= not ACC(5); + F(Flag_H) <= '1'; + F(Flag_X) <= not ACC(3); + F(Flag_N) <= '1'; + end if; + if I_CCF = '1' then + -- CCF + F(Flag_C) <= not F(Flag_C); + F(Flag_Y) <= ACC(5); + F(Flag_H) <= F(Flag_C); + F(Flag_X) <= ACC(3); + F(Flag_N) <= '0'; + end if; + if I_SCF = '1' then + -- SCF + F(Flag_C) <= '1'; + F(Flag_Y) <= ACC(5); + F(Flag_H) <= '0'; + F(Flag_X) <= ACC(3); + F(Flag_N) <= '0'; + end if; + end if; + + if TState = 2 and Wait_n = '1' then + if ISet = "01" and MCycle = "111" then + IR <= DInst; + end if; + if JumpE = '1' then + PC <= unsigned(signed(PC) + signed(DI_Reg)); + elsif Inc_PC = '1' then + PC <= PC + 1; + end if; + if BTR_r = '1' then + PC <= PC - 2; + end if; + if RstP = '1' then + TmpAddr <= (others => '0'); + TmpAddr(5 downto 3) <= IR(5 downto 3); + end if; + end if; + if TState = 3 and MCycle = "110" then + TmpAddr <= std_logic_vector(signed(RegBusC) + signed(DI_Reg)); + end if; + + if (TState = 2 and Wait_n = '1') or (TState = 4 and MCycle = "001") then + if IncDec_16(2 downto 0) = "111" then + if IncDec_16(3) = '1' then + SP <= SP - 1; + else + SP <= SP + 1; + end if; + end if; + end if; + + if LDSPHL = '1' then + SP <= unsigned(RegBusC); + end if; + if ExchangeAF = '1' then + Ap <= ACC; + ACC <= Ap; + Fp <= F; + F <= Fp; + end if; + if ExchangeRS = '1' then + Alternate <= not Alternate; + end if; + end if; + + if TState = 3 then + if LDZ = '1' then + TmpAddr(7 downto 0) <= DI_Reg; + end if; + if LDW = '1' then + TmpAddr(15 downto 8) <= DI_Reg; + end if; + + if Special_LD(2) = '1' then + case Special_LD(1 downto 0) is + when "00" => + ACC <= I; + F(Flag_P) <= IntE_FF2; + if I = X"00" then + F(Flag_Z) <= '1'; + else + F(Flag_Z) <= '0'; + end if; + F(Flag_S) <= I(7); + when "01" => + ACC <= std_logic_vector(R); + F(Flag_P) <= IntE_FF2; + if R = X"00" then + F(Flag_Z) <= '1'; + else + F(Flag_Z) <= '0'; + end if; + F(Flag_S) <= R(7); + when "10" => + I <= ACC; + when others => + R <= unsigned(ACC); + end case; + end if; + end if; + + if (I_DJNZ = '0' and Save_ALU_r = '1') or ALU_Op_r = "1001" then + if Mode = 3 then + F(6) <= F_Out(6); + F(5) <= F_Out(5); + F(7) <= F_Out(7); + if PreserveC_r = '0' then + F(4) <= F_Out(4); + end if; + else + F(7 downto 1) <= F_Out(7 downto 1); + if PreserveC_r = '0' then + F(Flag_C) <= F_Out(0); + end if; + end if; + end if; + if T_Res = '1' and I_INRC = '1' then + F(Flag_H) <= '0'; + F(Flag_N) <= '0'; + if DI_Reg(7 downto 0) = "00000000" then + F(Flag_Z) <= '1'; + else + F(Flag_Z) <= '0'; + end if; + F(Flag_S) <= DI_Reg(7); + F(Flag_P) <= not (DI_Reg(0) xor DI_Reg(1) xor DI_Reg(2) xor DI_Reg(3) xor + DI_Reg(4) xor DI_Reg(5) xor DI_Reg(6) xor DI_Reg(7)); + end if; + + if TState = 1 then + DO <= BusB; + if I_RLD = '1' then + DO(3 downto 0) <= BusA(3 downto 0); + DO(7 downto 4) <= BusB(3 downto 0); + end if; + if I_RRD = '1' then + DO(3 downto 0) <= BusB(7 downto 4); + DO(7 downto 4) <= BusA(3 downto 0); + end if; + end if; + + if T_Res = '1' then + Read_To_Reg_r(3 downto 0) <= Set_BusA_To; + Read_To_Reg_r(4) <= Read_To_Reg; + if Read_To_Acc = '1' then + Read_To_Reg_r(3 downto 0) <= "0111"; + Read_To_Reg_r(4) <= '1'; + end if; + end if; + + if TState = 1 and I_BT = '1' then + F(Flag_X) <= ALU_Q(3); + F(Flag_Y) <= ALU_Q(1); + F(Flag_H) <= '0'; + F(Flag_N) <= '0'; + end if; + if I_BC = '1' or I_BT = '1' then + F(Flag_P) <= IncDecZ; + end if; + + if (TState = 1 and Save_ALU_r = '0') or + (Save_ALU_r = '1' and ALU_OP_r /= "0111") then + case Read_To_Reg_r is + when "10111" => + ACC <= Save_Mux; + when "10110" => + DO <= Save_Mux; + when "11000" => + SP(7 downto 0) <= unsigned(Save_Mux); + when "11001" => + SP(15 downto 8) <= unsigned(Save_Mux); + when "11011" => + F <= Save_Mux; + when others => + end case; + if XYbit_undoc = '1' then + DO <= ALU_Q; + end if; + end if; + + end if; + + end if; + + end process; + +--------------------------------------------------------------------------- +-- +-- BC('), DE('), HL('), IX and IY +-- +--------------------------------------------------------------------------- + process (CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if ClkEn = '1' then + -- Bus A / Write + RegAddrA_r <= Alternate & Set_BusA_To(2 downto 1); + if XY_Ind = '0' and XY_State /= "00" and Set_BusA_To(2 downto 1) = "10" then + RegAddrA_r <= XY_State(1) & "11"; + end if; + + -- Bus B + RegAddrB_r <= Alternate & Set_BusB_To(2 downto 1); + if XY_Ind = '0' and XY_State /= "00" and Set_BusB_To(2 downto 1) = "10" then + RegAddrB_r <= XY_State(1) & "11"; + end if; + + -- Address from register + RegAddrC <= Alternate & Set_Addr_To(1 downto 0); + -- Jump (HL), LD SP,HL + if (JumpXY = '1' or LDSPHL = '1') then + RegAddrC <= Alternate & "10"; + end if; + if ((JumpXY = '1' or LDSPHL = '1') and XY_State /= "00") or (MCycle = "110") then + RegAddrC <= XY_State(1) & "11"; + end if; + + if I_DJNZ = '1' and Save_ALU_r = '1' and Mode < 2 then + IncDecZ <= F_Out(Flag_Z); + end if; + if (TState = 2 or (TState = 3 and MCycle = "001")) and IncDec_16(2 downto 0) = "100" then + if ID16 = 0 then + IncDecZ <= '0'; + else + IncDecZ <= '1'; + end if; + end if; + + RegBusA_r <= RegBusA; + end if; + end if; + end process; + + RegAddrA <= + -- 16 bit increment/decrement + Alternate & IncDec_16(1 downto 0) when (TState = 2 or + (TState = 3 and MCycle = "001" and IncDec_16(2) = '1')) and XY_State = "00" else + XY_State(1) & "11" when (TState = 2 or + (TState = 3 and MCycle = "001" and IncDec_16(2) = '1')) and IncDec_16(1 downto 0) = "10" else + -- EX HL,DL + Alternate & "10" when ExchangeDH = '1' and TState = 3 else + Alternate & "01" when ExchangeDH = '1' and TState = 4 else + -- Bus A / Write + RegAddrA_r; + + RegAddrB <= + -- EX HL,DL + Alternate & "01" when ExchangeDH = '1' and TState = 3 else + -- Bus B + RegAddrB_r; + + ID16 <= signed(RegBusA) - 1 when IncDec_16(3) = '1' else + signed(RegBusA) + 1; + + process (Save_ALU_r, Auto_Wait_t1, ALU_OP_r, Read_To_Reg_r, + ExchangeDH, IncDec_16, MCycle, TState, Wait_n) + begin + RegWEH <= '0'; + RegWEL <= '0'; + if (TState = 1 and Save_ALU_r = '0') or + (Save_ALU_r = '1' and ALU_OP_r /= "0111") then + case Read_To_Reg_r is + when "10000" | "10001" | "10010" | "10011" | "10100" | "10101" => + RegWEH <= not Read_To_Reg_r(0); + RegWEL <= Read_To_Reg_r(0); + when others => + end case; + end if; + + if ExchangeDH = '1' and (TState = 3 or TState = 4) then + RegWEH <= '1'; + RegWEL <= '1'; + end if; + + if IncDec_16(2) = '1' and ((TState = 2 and Wait_n = '1' and MCycle /= "001") or (TState = 3 and MCycle = "001")) then + case IncDec_16(1 downto 0) is + when "00" | "01" | "10" => + RegWEH <= '1'; + RegWEL <= '1'; + when others => + end case; + end if; + end process; + + process (Save_Mux, RegBusB, RegBusA_r, ID16, + ExchangeDH, IncDec_16, MCycle, TState, Wait_n) + begin + RegDIH <= Save_Mux; + RegDIL <= Save_Mux; + + if ExchangeDH = '1' and TState = 3 then + RegDIH <= RegBusB(15 downto 8); + RegDIL <= RegBusB(7 downto 0); + end if; + if ExchangeDH = '1' and TState = 4 then + RegDIH <= RegBusA_r(15 downto 8); + RegDIL <= RegBusA_r(7 downto 0); + end if; + + if IncDec_16(2) = '1' and ((TState = 2 and MCycle /= "001") or (TState = 3 and MCycle = "001")) then + RegDIH <= std_logic_vector(ID16(15 downto 8)); + RegDIL <= std_logic_vector(ID16(7 downto 0)); + end if; + end process; + + RegFile : T80_Reg + port map( + Clk => CLK_n, + CEN => ClkEn, + WEH => RegWEH, + WEL => RegWEL, + AddrA => RegAddrA, + AddrB => RegAddrB, + AddrC => RegAddrC, + DIH => RegDIH, + DIL => RegDIL, + DOAH => RegBusA(15 downto 8), + DOAL => RegBusA(7 downto 0), + DOBH => RegBusB(15 downto 8), + DOBL => RegBusB(7 downto 0), + DOCH => RegBusC(15 downto 8), + DOCL => RegBusC(7 downto 0)); + +--------------------------------------------------------------------------- +-- +-- Buses +-- +--------------------------------------------------------------------------- + process (CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if ClkEn = '1' then + case Set_BusB_To is + when "0111" => + BusB <= ACC; + when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" => + if Set_BusB_To(0) = '1' then + BusB <= RegBusB(7 downto 0); + else + BusB <= RegBusB(15 downto 8); + end if; + when "0110" => + BusB <= DI_Reg; + when "1000" => + BusB <= std_logic_vector(SP(7 downto 0)); + when "1001" => + BusB <= std_logic_vector(SP(15 downto 8)); + when "1010" => + BusB <= "00000001"; + when "1011" => + BusB <= F; + when "1100" => + BusB <= std_logic_vector(PC(7 downto 0)); + when "1101" => + BusB <= std_logic_vector(PC(15 downto 8)); + when "1110" => + BusB <= "00000000"; + when others => + BusB <= "--------"; + end case; + + case Set_BusA_To is + when "0111" => + BusA <= ACC; + when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" => + if Set_BusA_To(0) = '1' then + BusA <= RegBusA(7 downto 0); + else + BusA <= RegBusA(15 downto 8); + end if; + when "0110" => + BusA <= DI_Reg; + when "1000" => + BusA <= std_logic_vector(SP(7 downto 0)); + when "1001" => + BusA <= std_logic_vector(SP(15 downto 8)); + when "1010" => + BusA <= "00000000"; + when others => + BusA <= "--------"; + end case; + if XYbit_undoc = '1' then + BusA <= DI_Reg; + BusB <= DI_Reg; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------------------- +-- +-- Generate external control signals +-- +--------------------------------------------------------------------------- + process (RESET_n, CLK_n) + begin + if RESET_n = '0' then + RFSH_n <= '1'; + elsif CLK_n'event and CLK_n = '1' then + if CEN = '1' then + if MCycle = "001" and ((TState = 2 and Wait_n = '1') or TState = 3) then + RFSH_n <= '0'; + else + RFSH_n <= '1'; + end if; + end if; + end if; + end process; + + MC <= std_logic_vector(MCycle); + TS <= std_logic_vector(TState); + DI_Reg <= DI; + HALT_n <= not Halt_FF; + BUSAK_n <= not BusAck; + IntCycle_n <= not IntCycle; + IntE <= IntE_FF1; + IORQ <= IORQ_i; + Stop <= I_DJNZ; + +------------------------------------------------------------------------- +-- +-- Syncronise inputs +-- +------------------------------------------------------------------------- + process (RESET_n, CLK_n) + variable OldNMI_n : std_logic; + begin + if RESET_n = '0' then + BusReq_s <= '0'; + INT_s <= '0'; + NMI_s <= '0'; + OldNMI_n := '0'; + elsif CLK_n'event and CLK_n = '1' then + if CEN = '1' then + BusReq_s <= not BUSRQ_n; + INT_s <= not INT_n; + if NMICycle = '1' then + NMI_s <= '0'; + elsif NMI_n = '0' and OldNMI_n = '1' then + NMI_s <= '1'; + end if; + OldNMI_n := NMI_n; + end if; + end if; + end process; + +------------------------------------------------------------------------- +-- +-- Main state machine +-- +------------------------------------------------------------------------- + process (RESET_n, CLK_n) + begin + if RESET_n = '0' then + MCycle <= "001"; + TState <= "000"; + Pre_XY_F_M <= "000"; + Halt_FF <= '0'; + BusAck <= '0'; + NMICycle <= '0'; + IntCycle <= '0'; + IntE_FF1 <= '0'; + IntE_FF2 <= '0'; + No_BTR <= '0'; + Auto_Wait_t1 <= '0'; + Auto_Wait_t2 <= '0'; + M1_n <= '1'; + elsif CLK_n'event and CLK_n = '1' then + if CEN = '1' then + Auto_Wait_t1 <= Auto_Wait; + Auto_Wait_t2 <= Auto_Wait_t1; + No_BTR <= (I_BT and (not IR(4) or not F(Flag_P))) or + (I_BC and (not IR(4) or F(Flag_Z) or not F(Flag_P))) or + (I_BTR and (not IR(4) or F(Flag_Z))); + if TState = 2 then + if SetEI = '1' then + IntE_FF1 <= '1'; + IntE_FF2 <= '1'; + end if; + if I_RETN = '1' then + IntE_FF1 <= IntE_FF2; + end if; + end if; + if TState = 3 then + if SetDI = '1' then + IntE_FF1 <= '0'; + IntE_FF2 <= '0'; + end if; + end if; + if IntCycle = '1' or NMICycle = '1' then + Halt_FF <= '0'; + end if; + if MCycle = "001" and TState = 2 and Wait_n = '1' then + M1_n <= '1'; + end if; + if BusReq_s = '1' and BusAck = '1' then + else + BusAck <= '0'; + if TState = 2 and Wait_n = '0' then + elsif T_Res = '1' then + if Halt = '1' then + Halt_FF <= '1'; + end if; + if BusReq_s = '1' then + BusAck <= '1'; + else + TState <= "001"; + if NextIs_XY_Fetch = '1' then + MCycle <= "110"; + Pre_XY_F_M <= MCycle; + if IR = "00110110" and Mode = 0 then + Pre_XY_F_M <= "010"; + end if; + elsif (MCycle = "111") or + (MCycle = "110" and Mode = 1 and ISet /= "01") then + MCycle <= std_logic_vector(unsigned(Pre_XY_F_M) + 1); + elsif (MCycle = MCycles) or + No_BTR = '1' or + (MCycle = "010" and I_DJNZ = '1' and IncDecZ = '1') then + M1_n <= '0'; + MCycle <= "001"; + IntCycle <= '0'; + NMICycle <= '0'; + if NMI_s = '1' and Prefix = "00" then + NMICycle <= '1'; + IntE_FF1 <= '0'; + elsif (IntE_FF1 = '1' and INT_s = '1') and Prefix = "00" and SetEI = '0' then + IntCycle <= '1'; + IntE_FF1 <= '0'; + IntE_FF2 <= '0'; + end if; + else + MCycle <= std_logic_vector(unsigned(MCycle) + 1); + end if; + end if; + else + if Auto_Wait = '1' nand Auto_Wait_t2 = '0' then + + TState <= TState + 1; + end if; + end if; + end if; + if TState = 0 then + M1_n <= '0'; + end if; + end if; + end if; + end process; + + process (IntCycle, NMICycle, MCycle) + begin + Auto_Wait <= '0'; + if IntCycle = '1' or NMICycle = '1' then + if MCycle = "001" then + Auto_Wait <= '1'; + end if; + end if; + end process; + +end; diff --git a/src/T80/T80_ALU.vhd b/src/T80/T80_ALU.vhd new file mode 100644 index 0000000..17b9f0f --- /dev/null +++ b/src/T80/T80_ALU.vhd @@ -0,0 +1,371 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle +-- Ver 300 started tidyup +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- Z80 compatible microprocessor core +-- +-- Version : 0247 +-- +-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t80/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test +-- +-- 0238 : Fixed zero flag for 16 bit SBC and ADC +-- +-- 0240 : Added GB operations +-- +-- 0242 : Cleanup +-- +-- 0247 : Cleanup +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity T80_ALU is + generic( + Mode : integer := 0; + Flag_C : integer := 0; + Flag_N : integer := 1; + Flag_P : integer := 2; + Flag_X : integer := 3; + Flag_H : integer := 4; + Flag_Y : integer := 5; + Flag_Z : integer := 6; + Flag_S : integer := 7 + ); + port( + Arith16 : in std_logic; + Z16 : in std_logic; + ALU_Op : in std_logic_vector(3 downto 0); + IR : in std_logic_vector(5 downto 0); + ISet : in std_logic_vector(1 downto 0); + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + F_In : in std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0); + F_Out : out std_logic_vector(7 downto 0) + ); +end T80_ALU; + +architecture rtl of T80_ALU is + + procedure AddSub(A : std_logic_vector; + B : std_logic_vector; + Sub : std_logic; + Carry_In : std_logic; + signal Res : out std_logic_vector; + signal Carry : out std_logic) is + + variable B_i : unsigned(A'length - 1 downto 0); + variable Res_i : unsigned(A'length + 1 downto 0); + begin + if Sub = '1' then + B_i := not unsigned(B); + else + B_i := unsigned(B); + end if; + + Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1"); + Carry <= Res_i(A'length + 1); + Res <= std_logic_vector(Res_i(A'length downto 1)); + end; + + -- AddSub variables (temporary signals) + signal UseCarry : std_logic; + signal Carry7_v : std_logic; + signal Overflow_v : std_logic; + signal HalfCarry_v : std_logic; + signal Carry_v : std_logic; + signal Q_v : std_logic_vector(7 downto 0); + + signal BitMask : std_logic_vector(7 downto 0); + +begin + + with IR(5 downto 3) select BitMask <= "00000001" when "000", + "00000010" when "001", + "00000100" when "010", + "00001000" when "011", + "00010000" when "100", + "00100000" when "101", + "01000000" when "110", + "10000000" when others; + + UseCarry <= not ALU_Op(2) and ALU_Op(0); + AddSub(BusA(3 downto 0), BusB(3 downto 0), ALU_Op(1), ALU_Op(1) xor (UseCarry and F_In(Flag_C)), Q_v(3 downto 0), HalfCarry_v); + AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v); + AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v); + + -- bug fix - parity flag is just parity for 8080, also overflow for Z80 + process (Carry_v, Carry7_v, Q_v) + begin + if(Mode=2) then + OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor + Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7)); else + OverFlow_v <= Carry_v xor Carry7_v; + end if; + end process; + + process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16) + variable Q_t : std_logic_vector(7 downto 0); + variable DAA_Q : unsigned(8 downto 0); + begin + Q_t := "--------"; + F_Out <= F_In; + DAA_Q := "---------"; + case ALU_Op is + when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" => + F_Out(Flag_N) <= '0'; + F_Out(Flag_C) <= '0'; + case ALU_OP(2 downto 0) is + when "000" | "001" => -- ADD, ADC + Q_t := Q_v; + F_Out(Flag_C) <= Carry_v; + F_Out(Flag_H) <= HalfCarry_v; + F_Out(Flag_P) <= OverFlow_v; + when "010" | "011" | "111" => -- SUB, SBC, CP + Q_t := Q_v; + F_Out(Flag_N) <= '1'; + F_Out(Flag_C) <= not Carry_v; + F_Out(Flag_H) <= not HalfCarry_v; + F_Out(Flag_P) <= OverFlow_v; + when "100" => -- AND + Q_t(7 downto 0) := BusA and BusB; + F_Out(Flag_H) <= '1'; + when "101" => -- XOR + Q_t(7 downto 0) := BusA xor BusB; + F_Out(Flag_H) <= '0'; + when others => -- OR "110" + Q_t(7 downto 0) := BusA or BusB; + F_Out(Flag_H) <= '0'; + end case; + if ALU_Op(2 downto 0) = "111" then -- CP + F_Out(Flag_X) <= BusB(3); + F_Out(Flag_Y) <= BusB(5); + else + F_Out(Flag_X) <= Q_t(3); + F_Out(Flag_Y) <= Q_t(5); + end if; + if Q_t(7 downto 0) = "00000000" then + F_Out(Flag_Z) <= '1'; + if Z16 = '1' then + F_Out(Flag_Z) <= F_In(Flag_Z); -- 16 bit ADC,SBC + end if; + else + F_Out(Flag_Z) <= '0'; + end if; + F_Out(Flag_S) <= Q_t(7); + case ALU_Op(2 downto 0) is + when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP + when others => + F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor + Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7)); + end case; + if Arith16 = '1' then + F_Out(Flag_S) <= F_In(Flag_S); + F_Out(Flag_Z) <= F_In(Flag_Z); + F_Out(Flag_P) <= F_In(Flag_P); + end if; + when "1100" => + -- DAA + F_Out(Flag_H) <= F_In(Flag_H); + F_Out(Flag_C) <= F_In(Flag_C); + DAA_Q(7 downto 0) := unsigned(BusA); + DAA_Q(8) := '0'; + if F_In(Flag_N) = '0' then + -- After addition + -- Alow > 9 or H = 1 + if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then + if (DAA_Q(3 downto 0) > 9) then + F_Out(Flag_H) <= '1'; + else + F_Out(Flag_H) <= '0'; + end if; + DAA_Q := DAA_Q + 6; + end if; + -- new Ahigh > 9 or C = 1 + if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then + DAA_Q := DAA_Q + 96; -- 0x60 + end if; + else + -- After subtraction + if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then + if DAA_Q(3 downto 0) > 5 then + F_Out(Flag_H) <= '0'; + end if; + DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6; + end if; + if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then + DAA_Q := DAA_Q - 352; -- 0x160 + end if; + end if; + F_Out(Flag_X) <= DAA_Q(3); + F_Out(Flag_Y) <= DAA_Q(5); + F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8); + Q_t := std_logic_vector(DAA_Q(7 downto 0)); + if DAA_Q(7 downto 0) = "00000000" then + F_Out(Flag_Z) <= '1'; + else + F_Out(Flag_Z) <= '0'; + end if; + F_Out(Flag_S) <= DAA_Q(7); + F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor + DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7)); + when "1101" | "1110" => + -- RLD, RRD + Q_t(7 downto 4) := BusA(7 downto 4); + if ALU_Op(0) = '1' then + Q_t(3 downto 0) := BusB(7 downto 4); + else + Q_t(3 downto 0) := BusB(3 downto 0); + end if; + F_Out(Flag_H) <= '0'; + F_Out(Flag_N) <= '0'; + F_Out(Flag_X) <= Q_t(3); + F_Out(Flag_Y) <= Q_t(5); + if Q_t(7 downto 0) = "00000000" then + F_Out(Flag_Z) <= '1'; + else + F_Out(Flag_Z) <= '0'; + end if; + F_Out(Flag_S) <= Q_t(7); + F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor + Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7)); + when "1001" => + -- BIT + Q_t(7 downto 0) := BusB and BitMask; + F_Out(Flag_S) <= Q_t(7); + if Q_t(7 downto 0) = "00000000" then + F_Out(Flag_Z) <= '1'; + F_Out(Flag_P) <= '1'; + else + F_Out(Flag_Z) <= '0'; + F_Out(Flag_P) <= '0'; + end if; + F_Out(Flag_H) <= '1'; + F_Out(Flag_N) <= '0'; + F_Out(Flag_X) <= '0'; + F_Out(Flag_Y) <= '0'; + if IR(2 downto 0) /= "110" then + F_Out(Flag_X) <= BusB(3); + F_Out(Flag_Y) <= BusB(5); + end if; + when "1010" => + -- SET + Q_t(7 downto 0) := BusB or BitMask; + when "1011" => + -- RES + Q_t(7 downto 0) := BusB and not BitMask; + when "1000" => + -- ROT + case IR(5 downto 3) is + when "000" => -- RLC + Q_t(7 downto 1) := BusA(6 downto 0); + Q_t(0) := BusA(7); + F_Out(Flag_C) <= BusA(7); + when "010" => -- RL + Q_t(7 downto 1) := BusA(6 downto 0); + Q_t(0) := F_In(Flag_C); + F_Out(Flag_C) <= BusA(7); + when "001" => -- RRC + Q_t(6 downto 0) := BusA(7 downto 1); + Q_t(7) := BusA(0); + F_Out(Flag_C) <= BusA(0); + when "011" => -- RR + Q_t(6 downto 0) := BusA(7 downto 1); + Q_t(7) := F_In(Flag_C); + F_Out(Flag_C) <= BusA(0); + when "100" => -- SLA + Q_t(7 downto 1) := BusA(6 downto 0); + Q_t(0) := '0'; + F_Out(Flag_C) <= BusA(7); + when "110" => -- SLL (Undocumented) / SWAP + if Mode = 3 then + Q_t(7 downto 4) := BusA(3 downto 0); + Q_t(3 downto 0) := BusA(7 downto 4); + F_Out(Flag_C) <= '0'; + else + Q_t(7 downto 1) := BusA(6 downto 0); + Q_t(0) := '1'; + F_Out(Flag_C) <= BusA(7); + end if; + when "101" => -- SRA + Q_t(6 downto 0) := BusA(7 downto 1); + Q_t(7) := BusA(7); + F_Out(Flag_C) <= BusA(0); + when others => -- SRL + Q_t(6 downto 0) := BusA(7 downto 1); + Q_t(7) := '0'; + F_Out(Flag_C) <= BusA(0); + end case; + F_Out(Flag_H) <= '0'; + F_Out(Flag_N) <= '0'; + F_Out(Flag_X) <= Q_t(3); + F_Out(Flag_Y) <= Q_t(5); + F_Out(Flag_S) <= Q_t(7); + if Q_t(7 downto 0) = "00000000" then + F_Out(Flag_Z) <= '1'; + else + F_Out(Flag_Z) <= '0'; + end if; + F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor + Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7)); + if ISet = "00" then + F_Out(Flag_P) <= F_In(Flag_P); + F_Out(Flag_S) <= F_In(Flag_S); + F_Out(Flag_Z) <= F_In(Flag_Z); + end if; + when others => + null; + end case; + Q <= Q_t; + end process; +end; diff --git a/src/T80/T80_MCode.vhd b/src/T80/T80_MCode.vhd new file mode 100644 index 0000000..cb42a61 --- /dev/null +++ b/src/T80/T80_MCode.vhd @@ -0,0 +1,2024 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 303 add undocumented DDCB and FDCB opcodes by TobiFlex 20.04.2010 +-- Ver 302 fixed IO cycle timing, tested thanks to Alessandro. +-- Ver 300 started tidyup +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- Z80 compatible microprocessor core +-- +-- Version : 0242 +-- +-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t80/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0208 : First complete release +-- +-- 0211 : Fixed IM 1 +-- +-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test +-- +-- 0235 : Added IM 2 fix by Mike Johnson +-- +-- 0238 : Added NoRead signal +-- +-- 0238b: Fixed instruction timing for POP and DJNZ +-- +-- 0240 : Added (IX/IY+d) states, removed op-codes from mode 2 and added all remaining mode 3 op-codes + +-- 0240mj1 fix for HL inc/dec for INI, IND, INIR, INDR, OUTI, OUTD, OTIR, OTDR +-- +-- 0242 : Fixed I/O instruction timing, cleanup +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T80_Pack.all; + +entity T80_MCode is + generic( + Mode : integer := 0; + Flag_C : integer := 0; + Flag_N : integer := 1; + Flag_P : integer := 2; + Flag_X : integer := 3; + Flag_H : integer := 4; + Flag_Y : integer := 5; + Flag_Z : integer := 6; + Flag_S : integer := 7 + ); + port( + IR : in std_logic_vector(7 downto 0); + ISet : in std_logic_vector(1 downto 0); + MCycle : in std_logic_vector(2 downto 0); + F : in std_logic_vector(7 downto 0); + NMICycle : in std_logic; + IntCycle : in std_logic; + XY_State : in std_logic_vector(1 downto 0); + MCycles : out std_logic_vector(2 downto 0); + TStates : out std_logic_vector(2 downto 0); + Prefix : out std_logic_vector(1 downto 0); -- None,CB,ED,DD/FD + Inc_PC : out std_logic; + Inc_WZ : out std_logic; + IncDec_16 : out std_logic_vector(3 downto 0); -- BC,DE,HL,SP 0 is inc + Read_To_Reg : out std_logic; + Read_To_Acc : out std_logic; + Set_BusA_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F + Set_BusB_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0 + ALU_Op : out std_logic_vector(3 downto 0); + -- ADD, ADC, SUB, SBC, AND, XOR, OR, CP, ROT, BIT, SET, RES, DAA, RLD, RRD, None + Save_ALU : out std_logic; + PreserveC : out std_logic; + Arith16 : out std_logic; + Set_Addr_To : out std_logic_vector(2 downto 0); -- aNone,aXY,aIOA,aSP,aBC,aDE,aZI + IORQ : out std_logic; + Jump : out std_logic; + JumpE : out std_logic; + JumpXY : out std_logic; + Call : out std_logic; + RstP : out std_logic; + LDZ : out std_logic; + LDW : out std_logic; + LDSPHL : out std_logic; + Special_LD : out std_logic_vector(2 downto 0); -- A,I;A,R;I,A;R,A;None + ExchangeDH : out std_logic; + ExchangeRp : out std_logic; + ExchangeAF : out std_logic; + ExchangeRS : out std_logic; + I_DJNZ : out std_logic; + I_CPL : out std_logic; + I_CCF : out std_logic; + I_SCF : out std_logic; + I_RETN : out std_logic; + I_BT : out std_logic; + I_BC : out std_logic; + I_BTR : out std_logic; + I_RLD : out std_logic; + I_RRD : out std_logic; + I_INRC : out std_logic; + SetDI : out std_logic; + SetEI : out std_logic; + IMode : out std_logic_vector(1 downto 0); + Halt : out std_logic; + NoRead : out std_logic; + Write : out std_logic; + XYbit_undoc : out std_logic + ); +end T80_MCode; + +architecture rtl of T80_MCode is + + function is_cc_true( + F : std_logic_vector(7 downto 0); + cc : bit_vector(2 downto 0) + ) return boolean is + begin + if Mode = 3 then + case cc is + when "000" => return F(7) = '0'; -- NZ + when "001" => return F(7) = '1'; -- Z + when "010" => return F(4) = '0'; -- NC + when "011" => return F(4) = '1'; -- C + when "100" => return false; + when "101" => return false; + when "110" => return false; + when "111" => return false; + end case; + else + case cc is + when "000" => return F(6) = '0'; -- NZ + when "001" => return F(6) = '1'; -- Z + when "010" => return F(0) = '0'; -- NC + when "011" => return F(0) = '1'; -- C + when "100" => return F(2) = '0'; -- PO + when "101" => return F(2) = '1'; -- PE + when "110" => return F(7) = '0'; -- P + when "111" => return F(7) = '1'; -- M + end case; + end if; + end; + +begin + + process (IR, ISet, MCycle, F, NMICycle, IntCycle) + variable DDD : std_logic_vector(2 downto 0); + variable SSS : std_logic_vector(2 downto 0); + variable DPair : std_logic_vector(1 downto 0); + variable IRB : bit_vector(7 downto 0); + begin + DDD := IR(5 downto 3); + SSS := IR(2 downto 0); + DPair := IR(5 downto 4); + IRB := to_bitvector(IR); + + MCycles <= "001"; + if MCycle = "001" then + TStates <= "100"; + else + TStates <= "011"; + end if; + Prefix <= "00"; + Inc_PC <= '0'; + Inc_WZ <= '0'; + IncDec_16 <= "0000"; + Read_To_Acc <= '0'; + Read_To_Reg <= '0'; + Set_BusB_To <= "0000"; + Set_BusA_To <= "0000"; + ALU_Op <= "0" & IR(5 downto 3); + Save_ALU <= '0'; + PreserveC <= '0'; + Arith16 <= '0'; + IORQ <= '0'; + Set_Addr_To <= aNone; + Jump <= '0'; + JumpE <= '0'; + JumpXY <= '0'; + Call <= '0'; + RstP <= '0'; + LDZ <= '0'; + LDW <= '0'; + LDSPHL <= '0'; + Special_LD <= "000"; + ExchangeDH <= '0'; + ExchangeRp <= '0'; + ExchangeAF <= '0'; + ExchangeRS <= '0'; + I_DJNZ <= '0'; + I_CPL <= '0'; + I_CCF <= '0'; + I_SCF <= '0'; + I_RETN <= '0'; + I_BT <= '0'; + I_BC <= '0'; + I_BTR <= '0'; + I_RLD <= '0'; + I_RRD <= '0'; + I_INRC <= '0'; + SetDI <= '0'; + SetEI <= '0'; + IMode <= "11"; + Halt <= '0'; + NoRead <= '0'; + Write <= '0'; + XYbit_undoc <= '0'; + + case ISet is + when "00" => + +------------------------------------------------------------------------------ +-- +-- Unprefixed instructions +-- +------------------------------------------------------------------------------ + + case IRB is +-- 8 BIT LOAD GROUP + when "01000000"|"01000001"|"01000010"|"01000011"|"01000100"|"01000101"|"01000111" + |"01001000"|"01001001"|"01001010"|"01001011"|"01001100"|"01001101"|"01001111" + |"01010000"|"01010001"|"01010010"|"01010011"|"01010100"|"01010101"|"01010111" + |"01011000"|"01011001"|"01011010"|"01011011"|"01011100"|"01011101"|"01011111" + |"01100000"|"01100001"|"01100010"|"01100011"|"01100100"|"01100101"|"01100111" + |"01101000"|"01101001"|"01101010"|"01101011"|"01101100"|"01101101"|"01101111" + |"01111000"|"01111001"|"01111010"|"01111011"|"01111100"|"01111101"|"01111111" => + -- LD r,r' + Set_BusB_To(2 downto 0) <= SSS; + ExchangeRp <= '1'; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + when "00000110"|"00001110"|"00010110"|"00011110"|"00100110"|"00101110"|"00111110" => + -- LD r,n + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + when others => null; + end case; + when "01000110"|"01001110"|"01010110"|"01011110"|"01100110"|"01101110"|"01111110" => + -- LD r,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + when others => null; + end case; + when "01110000"|"01110001"|"01110010"|"01110011"|"01110100"|"01110101"|"01110111" => + -- LD (HL),r + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + when 2 => + Write <= '1'; + when others => null; + end case; + when "00110110" => + -- LD (HL),n + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aXY; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + when 3 => + Write <= '1'; + when others => null; + end case; + when "00001010" => + -- LD A,(BC) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + Read_To_Acc <= '1'; + when others => null; + end case; + when "00011010" => + -- LD A,(DE) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aDE; + when 2 => + Read_To_Acc <= '1'; + when others => null; + end case; + when "00111010" => + if Mode = 3 then + -- LDD A,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Read_To_Acc <= '1'; + IncDec_16 <= "1110"; + when others => null; + end case; + else + -- LD A,(nn) + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + when 4 => + Read_To_Acc <= '1'; + when others => null; + end case; + end if; + when "00000010" => + -- LD (BC),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + when others => null; + end case; + when "00010010" => + -- LD (DE),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aDE; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + when others => null; + end case; + when "00110010" => + if Mode = 3 then + -- LDD (HL),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + IncDec_16 <= "1110"; + when others => null; + end case; + else + -- LD (nn),A + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + Set_BusB_To <= "0111"; + when 4 => + Write <= '1'; + when others => null; + end case; + end if; + +-- 16 BIT LOAD GROUP + when "00000001"|"00010001"|"00100001"|"00110001" => + -- LD dd,nn + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "1000"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '1'; + end if; + when 3 => + Inc_PC <= '1'; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "1001"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '0'; + end if; + when others => null; + end case; + when "00101010" => + if Mode = 3 then + -- LDI A,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Read_To_Acc <= '1'; + IncDec_16 <= "0110"; + when others => null; + end case; + else + -- LD HL,(nn) + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + when 4 => + Set_BusA_To(2 downto 0) <= "101"; -- L + Read_To_Reg <= '1'; + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + when 5 => + Set_BusA_To(2 downto 0) <= "100"; -- H + Read_To_Reg <= '1'; + when others => null; + end case; + end if; + when "00100010" => + if Mode = 3 then + -- LDI (HL),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + IncDec_16 <= "0110"; + when others => null; + end case; + else + -- LD (nn),HL + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + Set_BusB_To <= "0101"; -- L + when 4 => + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + Write <= '1'; + Set_BusB_To <= "0100"; -- H + when 5 => + Write <= '1'; + when others => null; + end case; + end if; + when "11111001" => + -- LD SP,HL + TStates <= "110"; + LDSPHL <= '1'; + when "11000101"|"11010101"|"11100101"|"11110101" => + -- PUSH qq + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_TO <= aSP; + if DPAIR = "11" then + Set_BusB_To <= "0111"; + else + Set_BusB_To(2 downto 1) <= DPAIR; + Set_BusB_To(0) <= '0'; + Set_BusB_To(3) <= '0'; + end if; + when 2 => + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + if DPAIR = "11" then + Set_BusB_To <= "1011"; + else + Set_BusB_To(2 downto 1) <= DPAIR; + Set_BusB_To(0) <= '1'; + Set_BusB_To(3) <= '0'; + end if; + Write <= '1'; + when 3 => + Write <= '1'; + when others => null; + end case; + when "11000001"|"11010001"|"11100001"|"11110001" => + -- POP qq + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "1011"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '1'; + end if; + when 3 => + IncDec_16 <= "0111"; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "0111"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '0'; + end if; + when others => null; + end case; + +-- EXCHANGE, BLOCK TRANSFER AND SEARCH GROUP + when "11101011" => + if Mode /= 3 then + -- EX DE,HL + ExchangeDH <= '1'; + end if; + when "00001000" => + if Mode = 3 then + -- LD (nn),SP + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + Set_BusB_To <= "1000"; + when 4 => + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + Write <= '1'; + Set_BusB_To <= "1001"; + when 5 => + Write <= '1'; + when others => null; + end case; + elsif Mode < 2 then + -- EX AF,AF' + ExchangeAF <= '1'; + end if; + when "11011001" => + if Mode = 3 then + -- RETI + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + --I_RETN <= '1'; + SetEI <= '1'; + when others => null; + end case; + elsif Mode < 2 then + -- EXX + ExchangeRS <= '1'; + end if; + when "11100011" => + if Mode /= 3 then + -- EX (SP),HL + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aSP; + when 2 => + Read_To_Reg <= '1'; + Set_BusA_To <= "0101"; + Set_BusB_To <= "0101"; + Set_Addr_To <= aSP; + when 3 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + TStates <= "100"; + Write <= '1'; + when 4 => + Read_To_Reg <= '1'; + Set_BusA_To <= "0100"; + Set_BusB_To <= "0100"; + Set_Addr_To <= aSP; + when 5 => + IncDec_16 <= "1111"; + TStates <= "101"; + Write <= '1'; + when others => null; + end case; + end if; + +-- 8 BIT ARITHMETIC AND LOGICAL GROUP + when "10000000"|"10000001"|"10000010"|"10000011"|"10000100"|"10000101"|"10000111" + |"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001111" + |"10010000"|"10010001"|"10010010"|"10010011"|"10010100"|"10010101"|"10010111" + |"10011000"|"10011001"|"10011010"|"10011011"|"10011100"|"10011101"|"10011111" + |"10100000"|"10100001"|"10100010"|"10100011"|"10100100"|"10100101"|"10100111" + |"10101000"|"10101001"|"10101010"|"10101011"|"10101100"|"10101101"|"10101111" + |"10110000"|"10110001"|"10110010"|"10110011"|"10110100"|"10110101"|"10110111" + |"10111000"|"10111001"|"10111010"|"10111011"|"10111100"|"10111101"|"10111111" => + -- ADD A,r + -- ADC A,r + -- SUB A,r + -- SBC A,r + -- AND A,r + -- OR A,r + -- XOR A,r + -- CP A,r + Set_BusB_To(2 downto 0) <= SSS; + Set_BusA_To(2 downto 0) <= "111"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + when "10000110"|"10001110"|"10010110"|"10011110"|"10100110"|"10101110"|"10110110"|"10111110" => + -- ADD A,(HL) + -- ADC A,(HL) + -- SUB A,(HL) + -- SBC A,(HL) + -- AND A,(HL) + -- OR A,(HL) + -- XOR A,(HL) + -- CP A,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusA_To(2 downto 0) <= "111"; + when others => null; + end case; + when "11000110"|"11001110"|"11010110"|"11011110"|"11100110"|"11101110"|"11110110"|"11111110" => + -- ADD A,n + -- ADC A,n + -- SUB A,n + -- SBC A,n + -- AND A,n + -- OR A,n + -- XOR A,n + -- CP A,n + MCycles <= "010"; + if MCycle = "010" then + Inc_PC <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusA_To(2 downto 0) <= "111"; + end if; + when "00000100"|"00001100"|"00010100"|"00011100"|"00100100"|"00101100"|"00111100" => + -- INC r + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + ALU_Op <= "0000"; + when "00110100" => + -- INC (HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + TStates <= "100"; + Set_Addr_To <= aXY; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + ALU_Op <= "0000"; + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + when 3 => + Write <= '1'; + when others => null; + end case; + when "00000101"|"00001101"|"00010101"|"00011101"|"00100101"|"00101101"|"00111101" => + -- DEC r + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + ALU_Op <= "0010"; + when "00110101" => + -- DEC (HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + TStates <= "100"; + Set_Addr_To <= aXY; + ALU_Op <= "0010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + when 3 => + Write <= '1'; + when others => null; + end case; + +-- GENERAL PURPOSE ARITHMETIC AND CPU CONTROL GROUPS + when "00100111" => + -- DAA + Set_BusA_To(2 downto 0) <= "111"; + Read_To_Reg <= '1'; + ALU_Op <= "1100"; + Save_ALU <= '1'; + when "00101111" => + -- CPL + I_CPL <= '1'; + when "00111111" => + -- CCF + I_CCF <= '1'; + when "00110111" => + -- SCF + I_SCF <= '1'; + when "00000000" => + if NMICycle = '1' then + -- NMI + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1101"; + when 2 => + TStates <= "100"; + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 3 => + TStates <= "100"; + Write <= '1'; + when others => null; + end case; + elsif IntCycle = '1' then + -- INT (IM 2) + if mode = 3 then + MCycles <= "011"; + else + MCycles <= "101"; + end if; + case to_integer(unsigned(MCycle)) is + when 1 => + LDZ <= '1'; + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1101"; + when 2 => + TStates <= "100"; + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 3 => + TStates <= "100"; + Write <= '1'; + when 4 => + Inc_PC <= '1'; + LDZ <= '1'; + when 5 => + Jump <= '1'; + when others => null; + end case; + else + -- NOP + end if; + when "01110110" => + -- HALT + Halt <= '1'; + when "11110011" => + -- DI + SetDI <= '1'; + when "11111011" => + -- EI + SetEI <= '1'; + +-- 16 BIT ARITHMETIC GROUP + when "00001001"|"00011001"|"00101001"|"00111001" => + -- ADD HL,ss + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + ALU_Op <= "0000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "101"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + when others => + Set_BusB_To <= "1000"; + end case; + TStates <= "100"; + Arith16 <= '1'; + when 3 => + NoRead <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0001"; + Set_BusA_To(2 downto 0) <= "100"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + when others => + Set_BusB_To <= "1001"; + end case; + Arith16 <= '1'; + when others => + end case; + when "00000011"|"00010011"|"00100011"|"00110011" => + -- INC ss + TStates <= "110"; + IncDec_16(3 downto 2) <= "01"; + IncDec_16(1 downto 0) <= DPair; + when "00001011"|"00011011"|"00101011"|"00111011" => + -- DEC ss + TStates <= "110"; + IncDec_16(3 downto 2) <= "11"; + IncDec_16(1 downto 0) <= DPair; + +-- ROTATE AND SHIFT GROUP + when "00000111" + -- RLCA + |"00010111" + -- RLA + |"00001111" + -- RRCA + |"00011111" => + -- RRA + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + +-- JUMP GROUP + when "11000011" => + -- JP nn + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Inc_PC <= '1'; + Jump <= '1'; + when others => null; + end case; + when "11000010"|"11001010"|"11010010"|"11011010"|"11100010"|"11101010"|"11110010"|"11111010" => + if IR(5) = '1' and Mode = 3 then + case IRB(4 downto 3) is + when "00" => + -- LD ($FF00+C),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + IORQ <= '1'; + when others => + end case; + when "01" => + -- LD (nn),A + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + Set_BusB_To <= "0111"; + when 4 => + Write <= '1'; + when others => null; + end case; + when "10" => + -- LD A,($FF00+C) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + Read_To_Acc <= '1'; + IORQ <= '1'; + when others => + end case; + when "11" => + -- LD A,(nn) + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + when 4 => + Read_To_Acc <= '1'; + when others => null; + end case; + end case; + else + -- JP cc,nn + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Inc_PC <= '1'; + if is_cc_true(F, to_bitvector(IR(5 downto 3))) then + Jump <= '1'; + end if; + when others => null; + end case; + end if; + when "00011000" => + if Mode /= 2 then + -- JR e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00111000" => + if Mode /= 2 then + -- JR C,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_C) = '0' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00110000" => + if Mode /= 2 then + -- JR NC,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_C) = '1' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00101000" => + if Mode /= 2 then + -- JR Z,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_Z) = '0' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00100000" => + if Mode /= 2 then + -- JR NZ,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_Z) = '1' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "11101001" => + -- JP (HL) + JumpXY <= '1'; + when "00010000" => + if Mode = 3 then + I_DJNZ <= '1'; + elsif Mode < 2 then + -- DJNZ,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + I_DJNZ <= '1'; + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= "000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0010"; + when 2 => + I_DJNZ <= '1'; + Inc_PC <= '1'; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + +-- CALL AND RETURN GROUP + when "11001101" => + -- CALL nn + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + IncDec_16 <= "1111"; + Inc_PC <= '1'; + TStates <= "100"; + Set_Addr_To <= aSP; + LDW <= '1'; + Set_BusB_To <= "1101"; + when 4 => + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 5 => + Write <= '1'; + Call <= '1'; + when others => null; + end case; + when "11000100"|"11001100"|"11010100"|"11011100"|"11100100"|"11101100"|"11110100"|"11111100" => + if IR(5) = '0' or Mode /= 3 then + -- CALL cc,nn + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Inc_PC <= '1'; + LDW <= '1'; + if is_cc_true(F, to_bitvector(IR(5 downto 3))) then + IncDec_16 <= "1111"; + Set_Addr_TO <= aSP; + TStates <= "100"; + Set_BusB_To <= "1101"; + else + MCycles <= "011"; + end if; + when 4 => + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 5 => + Write <= '1'; + Call <= '1'; + when others => null; + end case; + end if; + when "11001001" => + -- RET + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + when others => null; + end case; + when "11000000"|"11001000"|"11010000"|"11011000"|"11100000"|"11101000"|"11110000"|"11111000" => + if IR(5) = '1' and Mode = 3 then + case IRB(4 downto 3) is + when "00" => + -- LD ($FF00+nn),A + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + Set_BusB_To <= "0111"; + when 3 => + Write <= '1'; + when others => null; + end case; + when "01" => + -- ADD SP,n + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + ALU_Op <= "0000"; + Inc_PC <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To <= "1000"; + Set_BusB_To <= "0110"; + when 3 => + NoRead <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0001"; + Set_BusA_To <= "1001"; + Set_BusB_To <= "1110"; -- Incorrect unsigned !!!!!!!!!!!!!!!!!!!!! + when others => + end case; + when "10" => + -- LD A,($FF00+nn) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + when 3 => + Read_To_Acc <= '1'; + when others => null; + end case; + when "11" => + -- LD HL,SP+n -- Not correct !!!!!!!!!!!!!!!!!!! + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + when 4 => + Set_BusA_To(2 downto 0) <= "101"; -- L + Read_To_Reg <= '1'; + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + when 5 => + Set_BusA_To(2 downto 0) <= "100"; -- H + Read_To_Reg <= '1'; + when others => null; + end case; + end case; + else + -- RET cc + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + if is_cc_true(F, to_bitvector(IR(5 downto 3))) then + Set_Addr_TO <= aSP; + else + MCycles <= "001"; + end if; + TStates <= "101"; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + when others => null; + end case; + end if; + when "11000111"|"11001111"|"11010111"|"11011111"|"11100111"|"11101111"|"11110111"|"11111111" => + -- RST p + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1101"; + when 2 => + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 3 => + Write <= '1'; + RstP <= '1'; + when others => null; + end case; + +-- INPUT AND OUTPUT GROUP + when "11011011" => + if Mode /= 3 then + -- IN A,(n) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + when 3 => + Read_To_Acc <= '1'; + IORQ <= '1'; + TStates <= "100"; -- MIKEJ should be 4 for IO cycle + when others => null; + end case; + end if; + when "11010011" => + if Mode /= 3 then + -- OUT (n),A + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + Set_BusB_To <= "0111"; + when 3 => + Write <= '1'; + IORQ <= '1'; + TStates <= "100"; -- MIKEJ should be 4 for IO cycle + when others => null; + end case; + end if; + +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- MULTIBYTE INSTRUCTIONS +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + + when "11001011" => + if Mode /= 2 then + Prefix <= "01"; + end if; + + when "11101101" => + if Mode < 2 then + Prefix <= "10"; + end if; + + when "11011101"|"11111101" => + if Mode < 2 then + Prefix <= "11"; + end if; + + end case; + + when "01" => + +------------------------------------------------------------------------------ +-- +-- CB prefixed instructions +-- +------------------------------------------------------------------------------ + + Set_BusA_To(2 downto 0) <= IR(2 downto 0); + Set_BusB_To(2 downto 0) <= IR(2 downto 0); + + case IRB is + when "00000000"|"00000001"|"00000010"|"00000011"|"00000100"|"00000101"|"00000111" + |"00010000"|"00010001"|"00010010"|"00010011"|"00010100"|"00010101"|"00010111" + |"00001000"|"00001001"|"00001010"|"00001011"|"00001100"|"00001101"|"00001111" + |"00011000"|"00011001"|"00011010"|"00011011"|"00011100"|"00011101"|"00011111" + |"00100000"|"00100001"|"00100010"|"00100011"|"00100100"|"00100101"|"00100111" + |"00101000"|"00101001"|"00101010"|"00101011"|"00101100"|"00101101"|"00101111" + |"00110000"|"00110001"|"00110010"|"00110011"|"00110100"|"00110101"|"00110111" + |"00111000"|"00111001"|"00111010"|"00111011"|"00111100"|"00111101"|"00111111" => + -- RLC r + -- RL r + -- RRC r + -- RR r + -- SLA r + -- SRA r + -- SRL r + -- SLL r (Undocumented) / SWAP r + if XY_State="00" then + if MCycle = "001" then + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + end if; + else + -- R/S (IX+d),Reg, undocumented + MCycles <= "011"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end if; + + + when "00000110"|"00010110"|"00001110"|"00011110"|"00101110"|"00111110"|"00100110"|"00110110" => + -- RLC (HL) + -- RL (HL) + -- RRC (HL) + -- RR (HL) + -- SRA (HL) + -- SRL (HL) + -- SLA (HL) + -- SLL (HL) (Undocumented) / SWAP (HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 | 7 => + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => + end case; + when "01000000"|"01000001"|"01000010"|"01000011"|"01000100"|"01000101"|"01000111" + |"01001000"|"01001001"|"01001010"|"01001011"|"01001100"|"01001101"|"01001111" + |"01010000"|"01010001"|"01010010"|"01010011"|"01010100"|"01010101"|"01010111" + |"01011000"|"01011001"|"01011010"|"01011011"|"01011100"|"01011101"|"01011111" + |"01100000"|"01100001"|"01100010"|"01100011"|"01100100"|"01100101"|"01100111" + |"01101000"|"01101001"|"01101010"|"01101011"|"01101100"|"01101101"|"01101111" + |"01110000"|"01110001"|"01110010"|"01110011"|"01110100"|"01110101"|"01110111" + |"01111000"|"01111001"|"01111010"|"01111011"|"01111100"|"01111101"|"01111111" => + -- BIT b,r + if XY_State="00" then + if MCycle = "001" then + Set_BusB_To(2 downto 0) <= IR(2 downto 0); + ALU_Op <= "1001"; + end if; + else + -- BIT b,(IX+d), undocumented + MCycles <= "010"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1001"; + TStates <= "100"; + when others => null; + end case; + end if; + when "01000110"|"01001110"|"01010110"|"01011110"|"01100110"|"01101110"|"01110110"|"01111110" => + -- BIT b,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1001"; + TStates <= "100"; + when others => null; + end case; + when "11000000"|"11000001"|"11000010"|"11000011"|"11000100"|"11000101"|"11000111" + |"11001000"|"11001001"|"11001010"|"11001011"|"11001100"|"11001101"|"11001111" + |"11010000"|"11010001"|"11010010"|"11010011"|"11010100"|"11010101"|"11010111" + |"11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011111" + |"11100000"|"11100001"|"11100010"|"11100011"|"11100100"|"11100101"|"11100111" + |"11101000"|"11101001"|"11101010"|"11101011"|"11101100"|"11101101"|"11101111" + |"11110000"|"11110001"|"11110010"|"11110011"|"11110100"|"11110101"|"11110111" + |"11111000"|"11111001"|"11111010"|"11111011"|"11111100"|"11111101"|"11111111" => + -- SET b,r + if XY_State="00" then + if MCycle = "001" then + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + end if; + else + -- SET b,(IX+d),Reg, undocumented + MCycles <= "011"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end if; + when "11000110"|"11001110"|"11010110"|"11011110"|"11100110"|"11101110"|"11110110"|"11111110" => + -- SET b,(HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + when "10000000"|"10000001"|"10000010"|"10000011"|"10000100"|"10000101"|"10000111" + |"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001111" + |"10010000"|"10010001"|"10010010"|"10010011"|"10010100"|"10010101"|"10010111" + |"10011000"|"10011001"|"10011010"|"10011011"|"10011100"|"10011101"|"10011111" + |"10100000"|"10100001"|"10100010"|"10100011"|"10100100"|"10100101"|"10100111" + |"10101000"|"10101001"|"10101010"|"10101011"|"10101100"|"10101101"|"10101111" + |"10110000"|"10110001"|"10110010"|"10110011"|"10110100"|"10110101"|"10110111" + |"10111000"|"10111001"|"10111010"|"10111011"|"10111100"|"10111101"|"10111111" => + -- RES b,r + if XY_State="00" then + if MCycle = "001" then + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + end if; + else + -- RES b,(IX+d),Reg, undocumented + MCycles <= "011"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end if; + + when "10000110"|"10001110"|"10010110"|"10011110"|"10100110"|"10101110"|"10110110"|"10111110" => + -- RES b,(HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 | 7 => + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end case; + + when others => + +------------------------------------------------------------------------------ +-- +-- ED prefixed instructions +-- +------------------------------------------------------------------------------ + + case IRB is + when "00000000"|"00000001"|"00000010"|"00000011"|"00000100"|"00000101"|"00000110"|"00000111" + |"00001000"|"00001001"|"00001010"|"00001011"|"00001100"|"00001101"|"00001110"|"00001111" + |"00010000"|"00010001"|"00010010"|"00010011"|"00010100"|"00010101"|"00010110"|"00010111" + |"00011000"|"00011001"|"00011010"|"00011011"|"00011100"|"00011101"|"00011110"|"00011111" + |"00100000"|"00100001"|"00100010"|"00100011"|"00100100"|"00100101"|"00100110"|"00100111" + |"00101000"|"00101001"|"00101010"|"00101011"|"00101100"|"00101101"|"00101110"|"00101111" + |"00110000"|"00110001"|"00110010"|"00110011"|"00110100"|"00110101"|"00110110"|"00110111" + |"00111000"|"00111001"|"00111010"|"00111011"|"00111100"|"00111101"|"00111110"|"00111111" + + + |"10000000"|"10000001"|"10000010"|"10000011"|"10000100"|"10000101"|"10000110"|"10000111" + |"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111" + |"10010000"|"10010001"|"10010010"|"10010011"|"10010100"|"10010101"|"10010110"|"10010111" + |"10011000"|"10011001"|"10011010"|"10011011"|"10011100"|"10011101"|"10011110"|"10011111" + | "10100100"|"10100101"|"10100110"|"10100111" + | "10101100"|"10101101"|"10101110"|"10101111" + | "10110100"|"10110101"|"10110110"|"10110111" + | "10111100"|"10111101"|"10111110"|"10111111" + |"11000000"|"11000001"|"11000010"|"11000011"|"11000100"|"11000101"|"11000110"|"11000111" + |"11001000"|"11001001"|"11001010"|"11001011"|"11001100"|"11001101"|"11001110"|"11001111" + |"11010000"|"11010001"|"11010010"|"11010011"|"11010100"|"11010101"|"11010110"|"11010111" + |"11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111" + |"11100000"|"11100001"|"11100010"|"11100011"|"11100100"|"11100101"|"11100110"|"11100111" + |"11101000"|"11101001"|"11101010"|"11101011"|"11101100"|"11101101"|"11101110"|"11101111" + |"11110000"|"11110001"|"11110010"|"11110011"|"11110100"|"11110101"|"11110110"|"11110111" + |"11111000"|"11111001"|"11111010"|"11111011"|"11111100"|"11111101"|"11111110"|"11111111" => + null; -- NOP, undocumented + when "01111110"|"01111111" => + -- NOP, undocumented + null; +-- 8 BIT LOAD GROUP + when "01010111" => + -- LD A,I + Special_LD <= "100"; + TStates <= "101"; + when "01011111" => + -- LD A,R + Special_LD <= "101"; + TStates <= "101"; + when "01000111" => + -- LD I,A + Special_LD <= "110"; + TStates <= "101"; + when "01001111" => + -- LD R,A + Special_LD <= "111"; + TStates <= "101"; +-- 16 BIT LOAD GROUP + when "01001011"|"01011011"|"01101011"|"01111011" => + -- LD dd,(nn) + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + when 4 => + Read_To_Reg <= '1'; + if IR(5 downto 4) = "11" then + Set_BusA_To <= "1000"; + else + Set_BusA_To(2 downto 1) <= IR(5 downto 4); + Set_BusA_To(0) <= '1'; + end if; + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + when 5 => + Read_To_Reg <= '1'; + if IR(5 downto 4) = "11" then + Set_BusA_To <= "1001"; + else + Set_BusA_To(2 downto 1) <= IR(5 downto 4); + Set_BusA_To(0) <= '0'; + end if; + when others => null; + end case; + when "01000011"|"01010011"|"01100011"|"01110011" => + -- LD (nn),dd + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + if IR(5 downto 4) = "11" then + Set_BusB_To <= "1000"; + else + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + Set_BusB_To(3) <= '0'; + end if; + when 4 => + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + Write <= '1'; + if IR(5 downto 4) = "11" then + Set_BusB_To <= "1001"; + else + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '0'; + Set_BusB_To(3) <= '0'; + end if; + when 5 => + Write <= '1'; + when others => null; + end case; + when "10100000" | "10101000" | "10110000" | "10111000" => + -- LDI, LDD, LDIR, LDDR + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- BC + when 2 => + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0000"; + Set_Addr_To <= aDE; + if IR(3) = '0' then + IncDec_16 <= "0110"; -- IX + else + IncDec_16 <= "1110"; + end if; + when 3 => + I_BT <= '1'; + TStates <= "101"; + Write <= '1'; + if IR(3) = '0' then + IncDec_16 <= "0101"; -- DE + else + IncDec_16 <= "1101"; + end if; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + when "10100001" | "10101001" | "10110001" | "10111001" => + -- CPI, CPD, CPIR, CPDR + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- BC + when 2 => + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0111"; + Save_ALU <= '1'; + PreserveC <= '1'; + if IR(3) = '0' then + IncDec_16 <= "0110"; + else + IncDec_16 <= "1110"; + end if; + when 3 => + NoRead <= '1'; + I_BC <= '1'; + TStates <= "101"; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + when "01000100"|"01001100"|"01010100"|"01011100"|"01100100"|"01101100"|"01110100"|"01111100" => + -- NEG + Alu_OP <= "0010"; + Set_BusB_To <= "0111"; + Set_BusA_To <= "1010"; + Read_To_Acc <= '1'; + Save_ALU <= '1'; + when "01000110"|"01001110"|"01100110"|"01101110" => + -- IM 0 + IMode <= "00"; + when "01010110"|"01110110" => + -- IM 1 + IMode <= "01"; + when "01011110"|"01110111" => + -- IM 2 + IMode <= "10"; +-- 16 bit arithmetic + when "01001010"|"01011010"|"01101010"|"01111010" => + -- ADC HL,ss + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + ALU_Op <= "0001"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "101"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + when others => + Set_BusB_To <= "1000"; + end case; + TStates <= "100"; + when 3 => + NoRead <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0001"; + Set_BusA_To(2 downto 0) <= "100"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '0'; + when others => + Set_BusB_To <= "1001"; + end case; + when others => + end case; + when "01000010"|"01010010"|"01100010"|"01110010" => + -- SBC HL,ss + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + ALU_Op <= "0011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "101"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + when others => + Set_BusB_To <= "1000"; + end case; + TStates <= "100"; + when 3 => + NoRead <= '1'; + ALU_Op <= "0011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "100"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + when others => + Set_BusB_To <= "1001"; + end case; + when others => + end case; + when "01101111" => + -- RLD + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + Set_Addr_To <= aXY; + when 3 => + Read_To_Reg <= '1'; + Set_BusB_To(2 downto 0) <= "110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "1101"; + TStates <= "100"; + Set_Addr_To <= aXY; + Save_ALU <= '1'; + when 4 => + I_RLD <= '1'; + Write <= '1'; + when others => + end case; + when "01100111" => + -- RRD + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Set_Addr_To <= aXY; + when 3 => + Read_To_Reg <= '1'; + Set_BusB_To(2 downto 0) <= "110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "1110"; + TStates <= "100"; + Set_Addr_To <= aXY; + Save_ALU <= '1'; + when 4 => + I_RRD <= '1'; + Write <= '1'; + when others => + end case; + when "01000101"|"01001101"|"01010101"|"01011101"|"01100101"|"01101101"|"01110101"|"01111101" => + -- RETI, RETN + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + I_RETN <= '1'; + when others => null; + end case; + when "01000000"|"01001000"|"01010000"|"01011000"|"01100000"|"01101000"|"01110000"|"01111000" => + -- IN r,(C) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + TStates <= "100"; -- MIKEJ should be 4 for IO cycle + IORQ <= '1'; + if IR(5 downto 3) /= "110" then + Read_To_Reg <= '1'; + Set_BusA_To(2 downto 0) <= IR(5 downto 3); + end if; + I_INRC <= '1'; + when others => + end case; + when "01000001"|"01001001"|"01010001"|"01011001"|"01100001"|"01101001"|"01110001"|"01111001" => + -- OUT (C),r + -- OUT (C),0 + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To(2 downto 0) <= IR(5 downto 3); + if IR(5 downto 3) = "110" then + Set_BusB_To(3) <= '1'; + end if; + when 2 => + TStates <= "100"; -- MIKEJ should be 4 for IO cycle + Write <= '1'; + IORQ <= '1'; + when others => + end case; + when "10100010" | "10101010" | "10110010" | "10111010" => + -- INI, IND, INIR, INDR + -- note B is decremented AFTER being put on the bus + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To <= "1010"; + Set_BusA_To <= "0000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0010"; + when 2 => + TStates <= "100"; -- MIKEJ should be 4 for IO cycle + IORQ <= '1'; + Set_BusB_To <= "0110"; + Set_Addr_To <= aXY; + when 3 => + if IR(3) = '0' then + --IncDec_16 <= "0010"; + IncDec_16 <= "0110"; + else + --IncDec_16 <= "1010"; + IncDec_16 <= "1110"; + end if; + TStates <= "100"; + Write <= '1'; + I_BTR <= '1'; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + when "10100011" | "10101011" | "10110011" | "10111011" => + -- OUTI, OUTD, OTIR, OTDR + -- note B is decremented BEFORE being put on the bus. + -- mikej fix for hl inc + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + Set_Addr_To <= aXY; + Set_BusB_To <= "1010"; + Set_BusA_To <= "0000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0010"; + when 2 => + Set_BusB_To <= "0110"; + Set_Addr_To <= aBC; + when 3 => + if IR(3) = '0' then + IncDec_16 <= "0110"; -- mikej + else + IncDec_16 <= "1110"; -- mikej + end if; + TStates <= "100"; -- MIKEJ should be 4 for IO cycle + IORQ <= '1'; + Write <= '1'; + I_BTR <= '1'; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + end case; + + end case; + + if Mode = 1 then + if MCycle = "001" then +-- TStates <= "100"; + else + TStates <= "011"; + end if; + end if; + + if Mode = 3 then + if MCycle = "001" then +-- TStates <= "100"; + else + TStates <= "100"; + end if; + end if; + + if Mode < 2 then + if MCycle = "110" then + Inc_PC <= '1'; + if Mode = 1 then + Set_Addr_To <= aXY; + TStates <= "100"; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + end if; + if IRB = "00110110" or IRB = "11001011" then + Set_Addr_To <= aNone; + end if; + end if; + if MCycle = "111" then + if Mode = 0 then + TStates <= "101"; + end if; + if ISet /= "01" then + Set_Addr_To <= aXY; + end if; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + if IRB = "00110110" or ISet = "01" then + -- LD (HL),n + Inc_PC <= '1'; + else + NoRead <= '1'; + end if; + end if; + end if; + + end process; + +end; diff --git a/src/T80/T80_Pack.vhd b/src/T80/T80_Pack.vhd new file mode 100644 index 0000000..4d84334 --- /dev/null +++ b/src/T80/T80_Pack.vhd @@ -0,0 +1,229 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 303 add undocumented DDCB and FDCB opcodes by TobiFlex 20.04.2010 +-- Ver 300 started tidyup +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- Z80 compatible microprocessor core +-- +-- Version : 0242 +-- +-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t80/ +-- +-- Limitations : +-- +-- File history : +-- + +library IEEE; +use IEEE.std_logic_1164.all; + +package T80_Pack is + + constant aNone : std_logic_vector(2 downto 0) := "111"; + constant aBC : std_logic_vector(2 downto 0) := "000"; + constant aDE : std_logic_vector(2 downto 0) := "001"; + constant aXY : std_logic_vector(2 downto 0) := "010"; + constant aIOA : std_logic_vector(2 downto 0) := "100"; + constant aSP : std_logic_vector(2 downto 0) := "101"; + constant aZI : std_logic_vector(2 downto 0) := "110"; + + component T80 + generic( + Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB + IOWait : integer := 0; -- 1 => Single cycle I/O, 1 => Std I/O cycle + Flag_C : integer := 0; + Flag_N : integer := 1; + Flag_P : integer := 2; + Flag_X : integer := 3; + Flag_H : integer := 4; + Flag_Y : integer := 5; + Flag_Z : integer := 6; + Flag_S : integer := 7 + ); + port( + RESET_n : in std_logic; + CLK_n : in std_logic; + CEN : in std_logic; + WAIT_n : in std_logic; + INT_n : in std_logic; + NMI_n : in std_logic; + BUSRQ_n : in std_logic; + M1_n : out std_logic; + IORQ : out std_logic; + NoRead : out std_logic; + Write : out std_logic; + RFSH_n : out std_logic; + HALT_n : out std_logic; + BUSAK_n : out std_logic; + A : out std_logic_vector(15 downto 0); + DInst : in std_logic_vector(7 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + MC : out std_logic_vector(2 downto 0); + TS : out std_logic_vector(2 downto 0); + IntCycle_n : out std_logic; + IntE : out std_logic; + Stop : out std_logic; + Regs : out std_logic_vector(63 downto 0) + ); + end component; + + component T80_Reg + port( + Clk : in std_logic; + CEN : in std_logic; + WEH : in std_logic; + WEL : in std_logic; + AddrA : in std_logic_vector(2 downto 0); + AddrB : in std_logic_vector(2 downto 0); + AddrC : in std_logic_vector(2 downto 0); + DIH : in std_logic_vector(7 downto 0); + DIL : in std_logic_vector(7 downto 0); + DOAH : out std_logic_vector(7 downto 0); + DOAL : out std_logic_vector(7 downto 0); + DOBH : out std_logic_vector(7 downto 0); + DOBL : out std_logic_vector(7 downto 0); + DOCH : out std_logic_vector(7 downto 0); + DOCL : out std_logic_vector(7 downto 0) + ); + end component; + + component T80_MCode + generic( + Mode : integer := 0; + Flag_C : integer := 0; + Flag_N : integer := 1; + Flag_P : integer := 2; + Flag_X : integer := 3; + Flag_H : integer := 4; + Flag_Y : integer := 5; + Flag_Z : integer := 6; + Flag_S : integer := 7 + ); + port( + IR : in std_logic_vector(7 downto 0); + ISet : in std_logic_vector(1 downto 0); + MCycle : in std_logic_vector(2 downto 0); + F : in std_logic_vector(7 downto 0); + NMICycle : in std_logic; + IntCycle : in std_logic; + XY_State : in std_logic_vector(1 downto 0); + MCycles : out std_logic_vector(2 downto 0); + TStates : out std_logic_vector(2 downto 0); + Prefix : out std_logic_vector(1 downto 0); -- None,BC,ED,DD/FD + Inc_PC : out std_logic; + Inc_WZ : out std_logic; + IncDec_16 : out std_logic_vector(3 downto 0); -- BC,DE,HL,SP 0 is inc + Read_To_Reg : out std_logic; + Read_To_Acc : out std_logic; + Set_BusA_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F + Set_BusB_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0 + ALU_Op : out std_logic_vector(3 downto 0); + -- ADD, ADC, SUB, SBC, AND, XOR, OR, CP, ROT, BIT, SET, RES, DAA, RLD, RRD, None + Save_ALU : out std_logic; + PreserveC : out std_logic; + Arith16 : out std_logic; + Set_Addr_To : out std_logic_vector(2 downto 0); -- aNone,aXY,aIOA,aSP,aBC,aDE,aZI + IORQ : out std_logic; + Jump : out std_logic; + JumpE : out std_logic; + JumpXY : out std_logic; + Call : out std_logic; + RstP : out std_logic; + LDZ : out std_logic; + LDW : out std_logic; + LDSPHL : out std_logic; + Special_LD : out std_logic_vector(2 downto 0); -- A,I;A,R;I,A;R,A;None + ExchangeDH : out std_logic; + ExchangeRp : out std_logic; + ExchangeAF : out std_logic; + ExchangeRS : out std_logic; + I_DJNZ : out std_logic; + I_CPL : out std_logic; + I_CCF : out std_logic; + I_SCF : out std_logic; + I_RETN : out std_logic; + I_BT : out std_logic; + I_BC : out std_logic; + I_BTR : out std_logic; + I_RLD : out std_logic; + I_RRD : out std_logic; + I_INRC : out std_logic; + SetDI : out std_logic; + SetEI : out std_logic; + IMode : out std_logic_vector(1 downto 0); + Halt : out std_logic; + NoRead : out std_logic; + Write : out std_logic; + XYbit_undoc : out std_logic + ); + end component; + + component T80_ALU + generic( + Mode : integer := 0; + Flag_C : integer := 0; + Flag_N : integer := 1; + Flag_P : integer := 2; + Flag_X : integer := 3; + Flag_H : integer := 4; + Flag_Y : integer := 5; + Flag_Z : integer := 6; + Flag_S : integer := 7 + ); + port( + Arith16 : in std_logic; + Z16 : in std_logic; + ALU_Op : in std_logic_vector(3 downto 0); + IR : in std_logic_vector(5 downto 0); + ISet : in std_logic_vector(1 downto 0); + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + F_In : in std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0); + F_Out : out std_logic_vector(7 downto 0) + ); + end component; + +end; diff --git a/src/T80/T80_Reg.vhd b/src/T80/T80_Reg.vhd new file mode 100644 index 0000000..fff324f --- /dev/null +++ b/src/T80/T80_Reg.vhd @@ -0,0 +1,114 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 started tidyup +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- T80 Registers, technology independent +-- +-- Version : 0244 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t51/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0242 : Initial release +-- +-- 0244 : Changed to single register file +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity T80_Reg is + port( + Clk : in std_logic; + CEN : in std_logic; + WEH : in std_logic; + WEL : in std_logic; + AddrA : in std_logic_vector(2 downto 0); + AddrB : in std_logic_vector(2 downto 0); + AddrC : in std_logic_vector(2 downto 0); + DIH : in std_logic_vector(7 downto 0); + DIL : in std_logic_vector(7 downto 0); + DOAH : out std_logic_vector(7 downto 0); + DOAL : out std_logic_vector(7 downto 0); + DOBH : out std_logic_vector(7 downto 0); + DOBL : out std_logic_vector(7 downto 0); + DOCH : out std_logic_vector(7 downto 0); + DOCL : out std_logic_vector(7 downto 0) + ); +end T80_Reg; + +architecture rtl of T80_Reg is + + type Register_Image is array (natural range <>) of std_logic_vector(7 downto 0); + signal RegsH : Register_Image(0 to 7); + signal RegsL : Register_Image(0 to 7); + +begin + + process (Clk) + begin + if Clk'event and Clk = '1' then + if CEN = '1' then + if WEH = '1' then + RegsH(to_integer(unsigned(AddrA))) <= DIH; + end if; + if WEL = '1' then + RegsL(to_integer(unsigned(AddrA))) <= DIL; + end if; + end if; + end if; + end process; + + DOAH <= RegsH(to_integer(unsigned(AddrA))); + DOAL <= RegsL(to_integer(unsigned(AddrA))); + DOBH <= RegsH(to_integer(unsigned(AddrB))); + DOBL <= RegsL(to_integer(unsigned(AddrB))); + DOCH <= RegsH(to_integer(unsigned(AddrC))); + DOCL <= RegsL(to_integer(unsigned(AddrC))); + +end; diff --git a/src/T80/T80_RegX.vhd b/src/T80/T80_RegX.vhd new file mode 100644 index 0000000..7b61be0 --- /dev/null +++ b/src/T80/T80_RegX.vhd @@ -0,0 +1,176 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 started tidyup +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- T80 Registers for Xilinx Select RAM +-- +-- Version : 0244 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t51/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0242 : Initial release +-- +-- 0244 : Removed UNISIM library and added componet declaration +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity T80_Reg is + port( + Clk : in std_logic; + CEN : in std_logic; + WEH : in std_logic; + WEL : in std_logic; + AddrA : in std_logic_vector(2 downto 0); + AddrB : in std_logic_vector(2 downto 0); + AddrC : in std_logic_vector(2 downto 0); + DIH : in std_logic_vector(7 downto 0); + DIL : in std_logic_vector(7 downto 0); + DOAH : out std_logic_vector(7 downto 0); + DOAL : out std_logic_vector(7 downto 0); + DOBH : out std_logic_vector(7 downto 0); + DOBL : out std_logic_vector(7 downto 0); + DOCH : out std_logic_vector(7 downto 0); + DOCL : out std_logic_vector(7 downto 0) + ); +end T80_Reg; + +architecture rtl of T80_Reg is + + component RAM16X1D + port( + DPO : out std_ulogic; + SPO : out std_ulogic; + A0 : in std_ulogic; + A1 : in std_ulogic; + A2 : in std_ulogic; + A3 : in std_ulogic; + D : in std_ulogic; + DPRA0 : in std_ulogic; + DPRA1 : in std_ulogic; + DPRA2 : in std_ulogic; + DPRA3 : in std_ulogic; + WCLK : in std_ulogic; + WE : in std_ulogic); + end component; + + signal ENH : std_logic; + signal ENL : std_logic; + +begin + + ENH <= CEN and WEH; + ENL <= CEN and WEL; + + bG1: for I in 0 to 7 generate + begin + Reg1H : RAM16X1D + port map( + DPO => DOBH(i), + SPO => DOAH(i), + A0 => AddrA(0), + A1 => AddrA(1), + A2 => AddrA(2), + A3 => '0', + D => DIH(i), + DPRA0 => AddrB(0), + DPRA1 => AddrB(1), + DPRA2 => AddrB(2), + DPRA3 => '0', + WCLK => Clk, + WE => ENH); + Reg1L : RAM16X1D + port map( + DPO => DOBL(i), + SPO => DOAL(i), + A0 => AddrA(0), + A1 => AddrA(1), + A2 => AddrA(2), + A3 => '0', + D => DIL(i), + DPRA0 => AddrB(0), + DPRA1 => AddrB(1), + DPRA2 => AddrB(2), + DPRA3 => '0', + WCLK => Clk, + WE => ENL); + Reg2H : RAM16X1D + port map( + DPO => DOCH(i), + SPO => open, + A0 => AddrA(0), + A1 => AddrA(1), + A2 => AddrA(2), + A3 => '0', + D => DIH(i), + DPRA0 => AddrC(0), + DPRA1 => AddrC(1), + DPRA2 => AddrC(2), + DPRA3 => '0', + WCLK => Clk, + WE => ENH); + Reg2L : RAM16X1D + port map( + DPO => DOCL(i), + SPO => open, + A0 => AddrA(0), + A1 => AddrA(1), + A2 => AddrA(2), + A3 => '0', + D => DIL(i), + DPRA0 => AddrC(0), + DPRA1 => AddrC(1), + DPRA2 => AddrC(2), + DPRA3 => '0', + WCLK => Clk, + WE => ENL); + end generate; + +end; diff --git a/src/T80/T80a.vhd b/src/T80/T80a.vhd new file mode 100644 index 0000000..48c6d9b --- /dev/null +++ b/src/T80/T80a.vhd @@ -0,0 +1,286 @@ +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 started tidyup +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- Z80 compatible microprocessor core, asynchronous top level +-- +-- Version : 0247 +-- +-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t80/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0208 : First complete release +-- +-- 0211 : Fixed interrupt cycle +-- +-- 0235 : Updated for T80 interface change +-- +-- 0238 : Updated for T80 interface change +-- +-- 0240 : Updated for T80 interface change +-- +-- 0242 : Updated for T80 interface change +-- +-- 0247 : Fixed bus req/ack cycle +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T80_Pack.all; + +entity T80a is + generic( + Mode : integer := 0 -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB + ); + port( + -- Additions + TS : out std_logic_vector(2 downto 0); + WAIT_s_out : out std_logic; + Regs : out std_logic_vector(63 downto 0); + Write_out : out std_logic; + -- Original Signals + RESET_n : in std_logic; + CLK_n : in std_logic; + WAIT_n : in std_logic; + INT_n : in std_logic; + NMI_n : in std_logic; + BUSRQ_n : in std_logic; + M1_n : out std_logic; + MREQ_n : out std_logic; + IORQ_n : out std_logic; + RD_n : out std_logic; + WR_n : out std_logic; + RFSH_n : out std_logic; + HALT_n : out std_logic; + BUSAK_n : out std_logic; + A : out std_logic_vector(15 downto 0); + D : inout std_logic_vector(7 downto 0) + ); +end T80a; + +architecture rtl of T80a is + + signal CEN : std_logic; + signal Reset_s : std_logic; + signal IntCycle_n : std_logic; + signal IORQ : std_logic; + signal NoRead : std_logic; + signal Write : std_logic; + signal MREQ : std_logic; + signal MReq_Inhibit : std_logic; + signal Req_Inhibit : std_logic; + signal RD : std_logic; + signal MREQ_n_i : std_logic; + signal IORQ_n_i : std_logic; + signal RD_n_i : std_logic; + signal WR_n_i : std_logic; + signal RFSH_n_i : std_logic; + signal BUSAK_n_i : std_logic; + signal A_i : std_logic_vector(15 downto 0); + signal DO : std_logic_vector(7 downto 0); + signal DI_Reg : std_logic_vector (7 downto 0); -- Input synchroniser + signal Wait_s : std_logic; + signal MCycle : std_logic_vector(2 downto 0); + signal TState : std_logic_vector(2 downto 0); + +begin + + CEN <= '1'; + + BUSAK_n <= BUSAK_n_i; + MREQ_n_i <= not MREQ or (Req_Inhibit and MReq_Inhibit); + RD_n_i <= not RD or Req_Inhibit; + + MREQ_n <= MREQ_n_i when BUSAK_n_i = '1' else 'Z'; + IORQ_n <= IORQ_n_i when BUSAK_n_i = '1' else 'Z'; + RD_n <= RD_n_i when BUSAK_n_i = '1' else 'Z'; + WR_n <= WR_n_i when BUSAK_n_i = '1' else 'Z'; + RFSH_n <= RFSH_n_i when BUSAK_n_i = '1' else 'Z'; + A <= A_i when BUSAK_n_i = '1' else (others => 'Z'); + D <= DO when Write = '1' and BUSAK_n_i = '1' else (others => 'Z'); + + process (RESET_n, CLK_n) + begin + if RESET_n = '0' then + Reset_s <= '0'; + elsif CLK_n'event and CLK_n = '1' then + Reset_s <= '1'; + end if; + end process; + + u0 : T80 + generic map( + Mode => Mode, + IOWait => 1) + port map( + CEN => CEN, + M1_n => M1_n, + IORQ => IORQ, + NoRead => NoRead, + Write => Write, + RFSH_n => RFSH_n_i, + HALT_n => HALT_n, + WAIT_n => Wait_s, + INT_n => INT_n, + NMI_n => NMI_n, + RESET_n => Reset_s, + BUSRQ_n => BUSRQ_n, + BUSAK_n => BUSAK_n_i, + CLK_n => CLK_n, + A => A_i, + DInst => D, + DI => DI_Reg, + DO => DO, + MC => MCycle, + TS => TState, + IntCycle_n => IntCycle_n, + Regs => Regs + ); + + + process (CLK_n) + begin + if CLK_n'event and CLK_n = '0' then + Wait_s <= WAIT_n; + if TState = "011" and BUSAK_n_i = '1' then + DI_Reg <= to_x01(D); + end if; + end if; + end process; + + process (Reset_s,CLK_n) + begin + if Reset_s = '0' then + WR_n_i <= '1'; + elsif CLK_n'event and CLK_n = '1' then + WR_n_i <= '1'; + if TState = "001" or (TState = "010" and Wait_s = '0') then -- To short for IO writes !!!!!!!!!!!!!!!!!!! + WR_n_i <= not Write; + end if; + end if; + end process; + +-- process (Reset_s,CLK_n) +-- begin +-- if Reset_s = '0' then +-- WR_n_i <= '1'; +-- elsif CLK_n'event and CLK_n = '0' then +-- WR_n_i <= '1'; +-- if TState = "010" then -- To short for IO writes !!!!!!!!!!!!!!!!!!! +-- WR_n_i <= not Write; +-- end if; +-- end if; +-- end process; + + process (Reset_s,CLK_n) + begin + if Reset_s = '0' then + Req_Inhibit <= '0'; + elsif CLK_n'event and CLK_n = '1' then + if MCycle = "001" and TState = "010" then + Req_Inhibit <= '1'; + else + Req_Inhibit <= '0'; + end if; + end if; + end process; + + process (Reset_s,CLK_n) + begin + if Reset_s = '0' then + MReq_Inhibit <= '0'; + elsif CLK_n'event and CLK_n = '0' then + if MCycle = "001" and TState = "010" then + MReq_Inhibit <= '1'; + else + MReq_Inhibit <= '0'; + end if; + end if; + end process; + + process(Reset_s,CLK_n) + begin + if Reset_s = '0' then + RD <= '0'; + IORQ_n_i <= '1'; + MREQ <= '0'; + elsif CLK_n'event and CLK_n = '0' then + + if MCycle = "001" then + if TState = "001" then + RD <= IntCycle_n; + MREQ <= IntCycle_n; + IORQ_n_i <= IntCycle_n; + end if; + if TState = "011" then + RD <= '0'; + IORQ_n_i <= '1'; + MREQ <= '1'; + end if; + if TState = "100" then + MREQ <= '0'; + end if; + else + if TState = "001" and NoRead = '0' then + RD <= not Write; + IORQ_n_i <= not IORQ; + MREQ <= not IORQ; + end if; + if TState = "011" then + RD <= '0'; + IORQ_n_i <= '1'; + MREQ <= '0'; + end if; + end if; + end if; + end process; + + TS <= TState; + WAIT_s_out <= WAIT_s; + Write_out <= Write; +end; diff --git a/src/Z80CpuMon.bmm b/src/Z80CpuMon.bmm new file mode 100644 index 0000000..3b0f272 --- /dev/null +++ b/src/Z80CpuMon.bmm @@ -0,0 +1,38 @@ +ADDRESS_MAP avrmap PPC405 0 + + ADDRESS_SPACE rom_code RAMB16 [0x00000000:0x00003fff] + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word0 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word1 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word2 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word3 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word4 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word5 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word6 [15:0]; + END_BUS_BLOCK; + + BUS_BLOCK + mon/Inst_AVR8/PM_Inst/RAM_Word7 [15:0]; + END_BUS_BLOCK; + + END_ADDRESS_SPACE; + +END_ADDRESS_MAP; \ No newline at end of file diff --git a/src/Z80CpuMon.ucf b/src/Z80CpuMon.ucf new file mode 100644 index 0000000..2bde8f9 --- /dev/null +++ b/src/Z80CpuMon.ucf @@ -0,0 +1,83 @@ + +NET "CLK_n" CLOCK_DEDICATED_ROUTE = FALSE; + +NET "clock49" LOC="P89" | IOSTANDARD = LVCMOS33 | PERIOD = 20.35ns ; # 49.152 MHz Oscillator + +NET "Addr<11>" LOC="P16" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 1 +NET "Addr<12>" LOC="P95" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 2 +NET "Addr<13>" LOC="P18" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 3 +NET "Addr<14>" LOC="P17" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 4 +NET "Addr<15>" LOC="P94" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 5 +NET "CLK_n" LOC="P22" | IOSTANDARD = LVCMOS33 | PERIOD = 250.0 ; # Z80 pin 6 +NET "Data<4>" LOC="P23" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 7 +NET "Data<3>" LOC="P33" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 8 +NET "Data<5>" LOC="P32" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 9 +NET "Data<6>" LOC="P34" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 10 +#NET "VCC" LOC="P40" | IOSTANDARD = LVCMOS33 ; # Z80 pin 11 +NET "Data<2>" LOC="P41" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 12 +NET "Data<7>" LOC="P36" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 13 +NET "Data<0>" LOC="P35" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 14 +NET "Data<1>" LOC="P53" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 15 +NET "INT_n" LOC="P54" | IOSTANDARD = LVCMOS33 ; # Z80 pin 16 +NET "NMI_n" LOC="P57" | IOSTANDARD = LVCMOS33 ; # Z80 pin 17 +NET "HALT_n" LOC="P58" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 18 +NET "MREQ_n" LOC="P60" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 19 +NET "IORQ_n" LOC="P61" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 20 +NET "RD_n" LOC="P67" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 21 +NET "WR_n" LOC="P68" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 22 +NET "BUSAK_n" LOC="P70" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 23 +NET "WAIT_n" LOC="P71" | IOSTANDARD = LVCMOS33 ; # Z80 pin 24 +NET "BUSRQ_n" LOC="P86" | IOSTANDARD = LVCMOS33 ; # Z80 pin 25 +NET "RESET_n" LOC="P84" | IOSTANDARD = LVCMOS33 ; # Z80 pin 26 +NET "M1_n" LOC="P83" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 27 +NET "RFSH_n" LOC="P78" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 28 +#NET "GND" LOC="P79" | IOSTANDARD = LVCMOS33 ; # Z80 pin 29 +NET "Addr<0>" LOC="P85" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 30 +NET "Addr<1>" LOC="P92" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 31 +NET "Addr<2>" LOC="P98" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 32 +NET "Addr<3>" LOC="P3" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 33 +NET "Addr<4>" LOC="P2" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 34 +NET "Addr<5>" LOC="P4" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 35 +NET "Addr<6>" LOC="P5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 36 +NET "Addr<7>" LOC="P90" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 37 +NET "Addr<8>" LOC="P9" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 38 +NET "Addr<9>" LOC="P10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 39 +NET "Addr<10>" LOC="P11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; # Z80 pin 40 + +NET "led3" LOC="P43" | IOSTANDARD = LVCMOS33 ; # Red LED (near SW1) +NET "led6" LOC="P25" | IOSTANDARD = LVCMOS33 ; # Red LED (just left of FPGA) +NET "led8" LOC="P47" | IOSTANDARD = LVCMOS33 ; # Green LED (near SW1) +NET "sw1" LOC="P39" | IOSTANDARD = LVCMOS33 ; # Bottom Switch +NET "nsw2" LOC="P69" | IOSTANDARD = LVCMOS33 | PULLUP ; # Top Switch + +# I/O's for test connector +#NET tvs1 LOC=P48 | IOSTANDARD = LVCMOS33 | DRIVE=16 ; +#NET tvs0 LOC=P49 | IOSTANDARD = LVCMOS33 | DRIVE=16 ; +NET tmosi LOC=P27 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; +NET tdin LOC=P44 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; +NET tcclk LOC=P50 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; +#NET tm1 LOC=P42 | IOSTANDARD = LVCMOS33 | DRIVE=16 ; +#NET thsw LOC=P99 | IOSTANDARD = LVCMOS33 | DRIVE=16 ; + +NET "avr_TxD" LOC="P26" | IOSTANDARD = LVCMOS33 ; +NET "avr_RxD" LOC="P15" | IOSTANDARD = LVCMOS33 ; + +NET "trig<0>" LOC="P62" | IOSTANDARD = LVCMOS33 ; +NET "trig<1>" LOC="P63" | IOSTANDARD = LVCMOS33 ; + +NET "test1" LOC="P65" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; +NET "test2" LOC="P66" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; +NET "test3" LOC="P12" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; +NET "test4" LOC="P91" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 2 ; + + +# NET "" LOC="P48" | IOSTANDARD = LVCMOS33 ; # connector pin E2 +# NET "" LOC="P49" | IOSTANDARD = LVCMOS33 ; # connector pin E3 +# NET "" LOC="P27" | IOSTANDARD = LVCMOS33 ; # connector pin E4 +# NET "" LOC="P44" | IOSTANDARD = LVCMOS33 ; # connector pin E5 +# NET "" LOC="P50" | IOSTANDARD = LVCMOS33 ; # connector pin E6 +# NET "" LOC="P42" | IOSTANDARD = LVCMOS33 ; # connector pin E7 +# NET "" LOC="P99" | IOSTANDARD = LVCMOS33 ; # connector pin E8 + + + \ No newline at end of file diff --git a/src/Z80CpuMon.vhd b/src/Z80CpuMon.vhd new file mode 100644 index 0000000..5f2919b --- /dev/null +++ b/src/Z80CpuMon.vhd @@ -0,0 +1,266 @@ +-------------------------------------------------------------------------------- +-- Copyright (c) 2015 David Banks +-- +-------------------------------------------------------------------------------- +-- ____ ____ +-- / /\/ / +-- /___/ \ / +-- \ \ \/ +-- \ \ +-- / / Filename : Z80CpuMon.vhd +-- /___/ /\ Timestamp : 22/06/2015 +-- \ \ / \ +-- \___\/\___\ +-- +--Design Name: Z80CpuMon +--Device: XC3S250E + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.OhoPack.all ; + +entity Z80CpuMon is + generic ( + UseT80Core : boolean := true + ); + port ( + clock49 : in std_logic; + + -- Z80 Signals + RESET_n : in std_logic; + CLK_n : in std_logic; + WAIT_n : in std_logic; + INT_n : in std_logic; + NMI_n : in std_logic; + BUSRQ_n : in std_logic; + M1_n : out std_logic; + MREQ_n : out std_logic; + IORQ_n : out std_logic; + RD_n : out std_logic; + WR_n : out std_logic; + RFSH_n : out std_logic; + HALT_n : out std_logic; + BUSAK_n : out std_logic; + Addr : out std_logic_vector(15 downto 0); + Data : inout std_logic_vector(7 downto 0); + + -- External trigger inputs + trig : in std_logic_vector(1 downto 0); + + -- Serial Console + avr_RxD : in std_logic; + avr_TxD : out std_logic; + + -- GODIL Switches + sw1 : in std_logic; + nsw2 : in std_logic; + + -- GODIL LEDs + led3 : out std_logic; + led6 : out std_logic; + led8 : out std_logic; + + -- OHO_DY1 connected to test connector + tmosi : out std_logic; + tdin : out std_logic; + tcclk : out std_logic; + + -- Debugging signals + test1 : out std_logic; + test2 : out std_logic; + test3 : out std_logic; + test4 : out std_logic + + ); +end Z80CpuMon; + +architecture behavioral of Z80CpuMon is + +signal RESET_n_int : std_logic; +signal cpu_clk : std_logic; +signal busmon_clk : std_logic; + +signal Addr_int : std_logic_vector(15 downto 0); +signal RD_n_int : std_logic; +signal WR_n_int : std_logic; +signal MREQ_n_int : std_logic; +signal IORQ_n_int : std_logic; +signal M1_n_int : std_logic; +signal WAIT_n_int : std_logic; +signal WAIT_s : std_logic; +signal TState : std_logic_vector(2 downto 0); +signal SS_Single : std_logic; +signal SS_Step : std_logic; +signal SS_Step_held : std_logic; + +signal Regs : std_logic_vector(63 downto 0); +signal Write : std_logic; + +signal INT_n_sync : std_logic; +signal NMI_n_sync : std_logic; + +signal Rdy : std_logic; +signal Read_n : std_logic; +signal Read_n0 : std_logic; +signal Read_n1 : std_logic; +signal Write_n : std_logic; +signal Write_n0 : std_logic; +signal Sync : std_logic; +signal Sync0 : std_logic; +signal nRST : std_logic; + +signal ex_data : std_logic_vector(7 downto 0); +signal rd_data : std_logic_vector(7 downto 0); +signal mon_data : std_logic_vector(7 downto 0); + +begin + + mon : entity work.BusMonCore + generic map ( + num_comparators => 1 + ) + port map ( + clock49 => clock49, + Addr => Addr_int, + Data => mon_data, + Phi2 => busmon_clk, + Rd_n => Read_n, + Wr_n => Write_n, + Sync => Sync, + Rdy => Rdy, + SS_Single => SS_Single, + SS_Step => SS_Step, + nRSTin => RESET_n_int, + nRSTout => nRST, + trig => trig, + lcd_rs => open, + lcd_rw => open, + lcd_e => open, + lcd_db => open, + avr_RxD => avr_RxD, + avr_TxD => avr_TxD, + sw1 => '0', + nsw2 => nsw2, + led3 => led3, + led6 => led6, + led8 => led8, + tmosi => tmosi, + tdin => tdin, + tcclk => tcclk, + Regs => Regs(63 downto 0), + RdOut => open, + WrOut => open, + AddrOut => open, + DataOut => open, + DataIn => (others => '0') + ); + + GenT80Core: if UseT80Core generate + inst_t80: entity work.T80a port map ( + TS => TState, + WAIT_s_out => WAIT_s, + Regs => Regs, + Write_out => Write, + RESET_n => RESET_n_int, + CLK_n => cpu_clk, + WAIT_n => WAIT_n_int, + INT_n => INT_n_sync, + NMI_n => NMI_n_sync, + BUSRQ_n => BUSRQ_n, + M1_n => M1_n_int, + MREQ_n => MREQ_n_int, + IORQ_n => IORQ_n_int, + RD_n => RD_n_int, + WR_n => WR_n_int, + RFSH_n => RFSH_n, + HALT_n => HALT_n, + BUSAK_n => BUSAK_n, + A => Addr_int, + D => Data + ); + end generate; + + WAIT_n_int <= WAIT_n when SS_Single = '0' + else WAIT_n and SS_Step_held; + + + sync_gen : process(CLK_n, RESET_n_int) + begin + if RESET_n_int = '0' then + NMI_n_sync <= '1'; + INT_n_sync <= '1'; + SS_Step_held <= '1'; + elsif rising_edge(CLK_n) then + NMI_n_sync <= NMI_n; + INT_n_sync <= INT_n; + if (M1_n_int = '0' and TState = "001") then + -- stop at the end of T1 instruction fetch + SS_Step_held <= '0'; + elsif (SS_Step = '1') then + -- start again when the single step command is issues + SS_Step_held <= '1'; + end if; + end if; + end process; + + + -- Make the monitoring decision in the middle of T2, but only if WAIT_n is '1' + Sync0 <= (WAIT_n_int and (not Write) and (not MREQ_n_int) and (not M1_n_int)) when TState = "010" else '0'; + Read_n0 <= not (WAIT_n_int and (not Write) and (not MREQ_n_int) and (M1_n_int)) when TState = "010" else '1'; + Write_n0 <= not (WAIT_n_int and ( Write) and (not MREQ_n_int) and (M1_n_int)) when TState = "010" else '1'; + + -- Hold the monitoring decision so it is valid on the rising edge of the clock + -- For instruction fetches and writes, the monitor sees these at the start of T3 + -- For reads, the data can arrive in the middle of T3 so delay until end of T3 + watch_gen : process(CLK_n) + begin + if falling_edge(CLK_n) then + Sync <= Sync0; + Read_n1 <= Read_n0; + Read_n <= Read_n1; + Write_n <= Write_n0; + end if; + end process; + + -- Register the exec/write data on the rising at the end of T2 + ex_data_latch : process(CLK_n) + begin + if rising_edge(CLK_n) then + if (Sync = '1' or Write_n = '0') then + ex_data <= Data; + end if; + end if; + end process; + + -- Register the read data on the falling edge of clock in the middle of T3 + rd_data_latch : process(CLK_n) + begin + if falling_edge(CLK_n) then + if (Read_n1 = '0') then + rd_data <= Data; + end if; + end if; + end process; + + -- Mux the data seen by the bus monitor appropriately + mon_data <= rd_data when Read_n <= '0' else ex_data; + + Addr <= Addr_int; + WR_n <= WR_n_int; + RD_n <= RD_n_int; + MREQ_n <= MREQ_n_int; + IORQ_n <= IORQ_n_int; + M1_n <= M1_n_int; + RESET_n_int <= RESET_n and (not sw1) and nRST; + + test1 <= TState(0); + test2 <= TState(1); + test3 <= TState(2); + test4 <= CLK_n; + + cpu_clk <= CLK_n; + busmon_clk <= CLK_n; + +end behavioral;