First though, the integration of the seven segment display with the 6809 circuit.
This turned out to be easier then expected. I added a bus driver component which replaces the counter to drive the mux, and in turn is driven (and drives) the databus. It also uses the read/write line and chip select control lines.
The code for the bus driver is as follows:
entity busdriver is
port ( CS : in STD_LOGIC;
R : in STD_LOGIC;
W : in STD_LOGIC;
DATA : inout STD_LOGIC_VECTOR (7 downto 0);
RESET : in STD_LOGIC;
X : out STD_LOGIC_VECTOR (7 downto 0);
OE : out STD_LOGIC);
end busdriver;
architecture Behavioral of busdriver is
signal WRITING : STD_LOGIC;
signal READING : STD_LOGIC;
signal LATCH : STD_LOGIC_VECTOR (7 downto 0);
begin
WRITING <= CS nor W;
READING <= CS nor R;
process (RESET, WRITING)
begin
if (RESET = ‘0’) then
LATCH <= x”00″;
elsif (WRITING’Event and WRITING = ‘1’) then
LATCH <= DATA;
end if;
end process;
X <= LATCH;
OE <= ‘1’ when (READING = ‘1’) else ‘0’;
end Behavioral;
You can see here that a NOR operation is used with the write and chip select. This will then be low (active) only when both the select and write lines are low. When this happens the databus lines are copied in to the “latch” which feeds out and onto the mux. In addition to write handling, the bus driver also outputs an “output enable” line, which is low when the chip select and read lines are low. This is used by the top level architecture:
entity main is
port ( CS : in STD_LOGIC;
R : in STD_LOGIC;
W : in STD_LOGIC;
DATABUS : inout STD_LOGIC_VECTOR (7 downto 0);
RESET : in STD_LOGIC;
DIGIT_ADDR : in STD_LOGIC; — Which digit to show (Mux input)
DIGIT_A : out STD_LOGIC; — Show digit A (from Mux)
DIGIT_B : out STD_LOGIC; — Show digit B (from Mux)
EN : in STD_LOGIC; — Decoder enable
SEGS : out STD_LOGIC_VECTOR (6 downto 0)); — 7 segment output
end main;
architecture Behavioral of main is
…
signal LATCH : STD_LOGIC_VECTOR(7 downto 0);
signal OE : STD_LOGIC;
signal MUX_OUT : STD_LOGIC_VECTOR(3 downto 0); — 4 bits from Mux
signal NOT_SEGS : STD_LOGIC_VECTOR(6 downto 0); — 7 segment outputs
begin
bd1: busdriver port map (CS, R, W, DATABUS, RESET, LATCH, OE);
mux1: twobyfourmux port map (LATCH(3 downto 0), LATCH(7 downto 4), DIGIT_ADDR, MUX_OUT, DIGIT_A, DIGIT_B);
decoder1: sevensegdecoder port map(MUX_OUT, NOT_SEGS, EN);
SEGS <= not NOT_SEGS;
DATABUS <= LATCH when (OE = ‘1’) else (others => ‘Z’);
end Behavioral;
Note that the databus is “inout” so bi-directional. In some ways it would have been cleaner to put both the read and write databus logic in the databus component, but I could not get this to compile. It seemed like inout lines have to be at the top level. More research needed there.
In summary this worked very well, and first time too. Here’s a picture of some extremely messy breadboards:
This was very much a quick bodge. Note the RTC IC on the bottom right, which has no SPI controller to drive it.
There’s not a great deal more to say about this really. I did play about with a few additional ideas: I made it so the displayed value didn’t switch straight to the number put on the bus, but instead “clocked up” (or down) to the number from the current value. This involved using an additional latch, to hold the value read from the databus. Then on the change in the “count up or down” line, a comparison was done and if the number on the display was more then the number pushed onto the databus, then the display would count down, and likewise for counting up. The method used to implement the comparison is probably the most interesting aspect here. Initially I used the VHDL < and > operators. This turned out to be very expensive in terms of gates used in the CPLD, so in the end I switched to an explicit subtraction and then a check of the sign bit (bit 7) of the subtraction result. The comparison can then be done with a relatively cheap subtraction operation, and a bit test. The code for this part is here:
architecture Behavioral of mover is
signal COUNT : STD_LOGIC_VECTOR (7 downto 0);
signal DIFF : STD_LOGIC_VECTOR (7 downto 0);
begin
DIFF <= TARGET – COUNT;
process (MOVE_CLK, RESET)
begin
if (RESET = ‘0’) then
COUNT <= x”00″;
elsif (MOVE_CLK’Event and MOVE_CLK = ‘1’) then
if (DIFF /= x”00″) then
if (DIFF(7) = ‘0’) then
COUNT <= COUNT + 1;
else
COUNT <= COUNT – 1;
end if;
end if;
end if;
end process;
X <= COUNT;
end Behavioral;
It is also possible to read back the digits on the display as they are counting, such that repeated reading the value shows it reaching its “target” value. This proves that I can put a CPLD on the databus for both reads and (the simpler to implement) writes.
This leads me onto thinking about a new design for the “core” computer, ie. one that includes a CPLD for all the glue logic functions.
I have come up with a list of components for the core board and it is as follows:
- 8Mhz MC68B09
- 16KB EEPROM
- 512KB SRAM in 16KB banks
- Glue logic in an XC9572
- Including bank switching port for switching banks on the 512KB SRAM
- And an 8 bit latch for driving the IDE port in 16bit mode
- DUART along with a MAX323 and DB9 socket
- The second DUART port will be for other “auxiliary” devices and will have a TTL level header
- IDE interface
- Expansion interface
- Address decoding for all devices on the main board, plus some lines for the expansion interface
- Read/Write line generation
- Reset control (possibly)
- Interrupt routing
- Bank switching port
- Latches for the IDE port so it can read and write 16bits at a time
- The memory address (label)
- The mnemonic and any parameters
- The hex for the memory values in the whole instruction
- The printable ASCII for the above