ULA revistited.
Re: ULA revistited.
I love it when I have no idea what you're talking about! PHWAORRR! <rubs trousers>
Re: ULA revistited.
Prevert!sirmorris wrote:I love it when I have no idea what you're talking about! PHWAORRR! <rubs trousers>
You could always take the plunge, get some CPLDs and learn to program them, cirtainly none of that tedious mucking about with remembering the polaritys of inputs / outputs as the (Xilinx's anyways) software works it all out for you, unlike CUPL.
If it would help I can give you the schematics / verilog code for the Atom RAMROM, and th ZXULA.....humm wonder if I could re-implement ZXPAND using a CPLD....prolly an XC9536 would do the trick.
Phill.
Re: ULA revistited.
Ok, cheers Andy, I'll give that a go this evening and see how we get on.Andy Rea wrote:or simpler still...
since as the always block is triggered on the negedge of clk325 we know that clk65 has already gone low (a few ns previously) and in either case turbo / non turbo clkout will also be low too.Code: Select all
always @ (negedge clk325) begin //if (turboon & clk325) turbo <= 1'b1 ; //else if (turbooff & clk325) turbo <= 1'b0; if (turboon) turbo <= 1'b1 ; else if (turbooff) turbo <= 1'b0; else turbo <= turbo ; end
of course you need to wrap it up in the rest of the switching code![]()
That is of course asuming that my Z80B will run at 6.5MHz, if not I'm gonna order some faster ones from Farnell as they are only about a fiver each

Cheers.
Phill.
Re: ULA revistited.
sirmorris wrote:I love it when I have no idea what you're talking about! PHWAORRR! <rubs trousers>


i picked verilog, because it seemed to have a fair amount of information on the web about it, i first looked at altera's own HDL becuase it looked similar to cupl, but couldn't find much info about it, but then again verilog is accepted by most compilers anyway.
Regards Andy
what's that Smell.... smells like fresh flux and solder fumes...
Re: ULA revistited.


built minus 3 resistors, tape-in and the video-csync, the tape-in will need tweaking i reckon, and since as the video and csync are now 3.3v outputs that will probably want tweaking too.
pity i can't program the thing yet, still waiting on an ebay purchase

no idea if it will work


should of made those 4 pads at the bottom bigger, but they'll do, only for solderng the jtag wires to, and i'll pick up gnd and 3.3v at the regulator

Oh hurry up chinese post....
Regards Andy
what's that Smell.... smells like fresh flux and solder fumes...
Re: ULA revistited.
WHAAAAAT?!
Woooooooowoooo!
Lookin' good, Andy!
How are you mounting the pins? It looks like you have pads on the underside only.
Woooooooowoooo!
Lookin' good, Andy!
How are you mounting the pins? It looks like you have pads on the underside only.
Re: ULA revistited.
Erm yeah, just pads on the underside, the CPLD is just a touch too wide to allow through pins, i could do with making the pads a little wider, but it shouldn't be a problem as it's not exactly a part thats going to be in and out all the time.sirmorris wrote: How are you mounting the pins? It looks like you have pads on the underside only.
what's that Smell.... smells like fresh flux and solder fumes...
Re: ULA revistited.
Looking good, you could of course move the CPLD south a bit, I'm asuming that it's at the bottom end of the board....that way your pins will be able to be through the board, meaning the board will sit lower in the machine, should still fit how it is.Andy Rea wrote:Erm yeah, just pads on the underside, the CPLD is just a touch too wide to allow through pins, i could do with making the pads a little wider, but it shouldn't be a problem as it's not exactly a part thats going to be in and out all the time.sirmorris wrote: How are you mounting the pins? It looks like you have pads on the underside only.
Depending on what manufacturer the CPLD is you may find that you have problems if it's a 3.3V but 5.0V tollerent chip I made a second prototype with a xilinx XC9572XL and while it works it got really hot and I was only able to program it once, I have not yet had a chance to try and remove it from the board and try mounting another chip so I'm not sure what happened, could be that I accidentally spiked one of the programming pins

Finally feel free to rip bist of my Verilog code if you want / need as it might help you get going quicker.
Cheers.
Phill.
Re: ULA revistited.
few more pictures...



That Gal is not soldered in yet, i'll make sure i get the program right first
cheap skate is my middle name... the parts (not counting the PCB) cost just over £5-00 the most expensive been the cpld at £3-00, the gal does 2 things, 1) latches the databus ( char code grab ) and then puts that on the alternate address lines (bits 3 to 8) and also does the memory decoding (broken just like the original
) the idea with this bord is to not take up any more space than is really necessary, pity it overlaps the rom socket slightly could be a problem if peeps have extra gizmo's plugged in there, however the pads at the bottom can be cut off once the CPLD is programmed and working, it would still be a bit close....
Thought my parcel had turned up today as when i got home from work there was a post office card on the floor, but alas it was for the missus
And now something for the geeks... ( are we all geeky here anyway ??? )
my verilog code...
zx81ula TOP LEVEL CODE.
Ah ah got ya... it's modular, i did this so that i could stick close to my gal design logic, and each module can be test-benched and modified without affecting the other modules. the modules share the same names as my gal design.
Decode
LNC (line counter)
nmi207
ferd
state
vshf



That Gal is not soldered in yet, i'll make sure i get the program right first

cheap skate is my middle name... the parts (not counting the PCB) cost just over £5-00 the most expensive been the cpld at £3-00, the gal does 2 things, 1) latches the databus ( char code grab ) and then puts that on the alternate address lines (bits 3 to 8) and also does the memory decoding (broken just like the original

Thought my parcel had turned up today as when i got home from work there was a post office card on the floor, but alas it was for the missus

And now something for the geeks... ( are we all geeky here anyway ??? )
my verilog code...
zx81ula TOP LEVEL CODE.
Code: Select all
Andy Rea march/april 2011
*/
// in sinclair fashion the device is not big enough for the job...
// so i use a gal16v8 to handle 6 of the 9 alternate address lines
// and also does the memory decoding
// this needs 2 pins, but relives the cpld of 10 pins
// making a saving of 8 pins in total
// this design is modular
// very little happens here.
// each module is a close approximation to the Gal design that i built
// and tested. they share the same name, for comparison.
module zx81ula (
//inputs
osc, //oscilator input
read, //z80 read sig
iorq, //z80 io request
write, //z80 write sig
m1, //z80 m1 sig
halt, //z80 halt sig
a15, //z80 address line 15 (msb)
tape_in, //tape input
kbd, // 5 pins (kbd0 - kbd4)
//inouts
data_bus, // z80 databus
add_low, // a0, a1, a2, actually a2 is only an output...
//outputs
clock_out, //3.25Mhz to Z80
nmi, //non maskable int to z80
vid, //video otput
sync, //composite sync output
load_alt_address, //to the gal
alt_address_en //to the gal
);
//inputs
input osc;
input read;
input iorq;
input write;
input m1;
input halt;
input a15;
input tape_in;
input [4:0] kbd;
//inouts
inout [7:0] data_bus;
inout [2:0] add_low;
//outputs
output clock_out;
output nmi;
output vid;
output sync;
output load_alt_address;
output alt_address_en;
// register declarations
reg bit7; //used in vshf to invert the video
// signal declarations
wire [2:0] alt_add;
wire blanking; //used in vshf to add a back porch to the video signal
wire hsync; //video sync signal
wire vsync; //video sync signal
wire ferd; //signal to read port $FE
wire force_nop; //signal to force 8b'00000000 onto databus
wire enable_alt_address; //signal to enable the alerternative addressing (for video data)
wire back_porch; //back porch timer
wire load_vid; //signal to load databus into vshf
wire csync; //composite sync (generated with Hsync and Vsync)
// the logic, not much in this top_level module.
assign sync = !csync; // the real csync needs to be inverted from whats used internally
assign load_alt_address = force_nop; // 1 of 2 controls to the Gal
assign alt_address_en = enable_alt_address ; // 2 of 2 controls to the Gal
assign add_low = (enable_alt_address ? alt_add : 3'bzzz ); // alternate address line control
always @ (posedge force_nop) bit7 <= data_bus [7]; //grab bit 7 used in module Vshf (invert bit)
// the following modules roughly follow my original Gal design
decode u0 (
//inputs
.clock (osc),
.a0 (add_low [0]),
.a1 (add_low [1]),
.rd (read),
.iorq (iorq),
.wr (write),
.hsync (hsync),
//outputs
.vsync (vsync),
.ferd (ferd),
.nmi (nmi),
.clock_out (clock_out)
);
nmi207 u1 (
//inputs
.clock3 (clock_out),
.reset (vsync),
//outputs
.bit4 (blanking),
.last16 (hsync)
);
lnc u2 (
//inputs
.clock (osc),
.vsync (vsync),
.blank_time (blanking),
.hsync (hsync),
//outputs
.csync (csync),
.back_porch (back_porch),
.alt_address (alt_add)
);
vshf u3 (
//inputs
.clock (osc),
.data_in (data_bus),
.invert (bit7),
.blanking (back_porch),
.load_vshf (load_vid),
//outputs
.vid_out (vid)
);
state u4 (
//inputs
.clock6 (osc),
.m1 (m1),
.halt (halt),
.a15 (a15),
.d6 (data_bus [6]),
//outputs
.force_nop (force_nop),
.alt_address (enable_alt_address),
.load_vshf (load_vid)
);
//module ferd also controls the tri-state of the databus.
ferd u5 (
//inputs
.ferd (ferd),
.force_nop (force_nop),
.kbd (kbd),
.uk_us (1'b0),
.tape_in (tape_in),
//outputs
.data_out (data_bus)
);
endmodule
Decode
Code: Select all
/*
ZX81 ULA implementation
Andy Rea march/april 2011
*/
// this module generates the 3.25Mhz clock
// contains the nmi latch
// contains the Vsync latch
// and generates ferd signal
// and nmi (to z80) signal
module decode (
// input ports
clock,
a0,
a1,
rd,
iorq,
wr,
hsync,
//output ports
vsync,
ferd,
nmi,
clock_out
);
input clock; // 6.5Mhz clock from osc
input a0; // z80 address line 0
input a1; // z80 address line 1
input iorq; // z80 io request
input wr; // z80 write sig
input rd; // z80 read sig
input hsync; // hsync, used to generate the nmi pulses
output vsync; //vsync
output ferd; // read port $FE
output nmi; //nmi pulse to z80
output clock_out; //3.25Mhz clock to Z80
reg clock_out;
reg vsync;
reg nmi_latch;
wire nmi;
wire ferd;
assign ferd = !(iorq | a0 | rd) ; //always generates a FERD signal when iorq, a0, rd are all low.
assign nmi = !(nmi_latch & hsync) ; //generate an NMI pulse on every hsync if nmi_latch is set.
always @ (posedge clock)
clock_out <= !clock_out; //clock divider, 3.25Mhz from 6.5Mhz.
wire nmi_set = iorq | wr | a0 ; // nmi_latch set/reset signals
wire nmi_reset = iorq | wr | a1 ; // both produce an active low signal
// modified the following to make the latches syncronous
//always @ (negedge nmi_set or negedge nmi_reset )
always @ (posedge clock)
begin
if (!nmi_set) nmi_latch <= 1'b1 ;
else if (!nmi_reset) nmi_latch <= 1'b0 ;
else nmi_latch <= nmi_latch;
end
wire io_wr = iorq | wr ; //any io write will reset Vsync
//always @ (negedge io_wr or posedge ferd )
always @ (posedge clock)
begin
if (!io_wr) vsync <= 1'b0 ; //any write reset Vsync
else if (nmi_latch) vsync <= 1'b0 ; //only latch if nmi_latch is reset.
else if (ferd) vsync <= 1'b1 ;
else vsync <= vsync ;
end
endmodule
Code: Select all
/*
ZX81 ULA implementation
Andy Rea march/april 2011
*/
// this module lnc (line counter) generates the lowest 3 address lines
// for the alternative addressing during video generation.
//
// the lowest 3 address is basically a 3 bit binary counter
// incremented on hsync pulses
// and reset (to zero) on vsync pulses
//
// this module also creates csync from hsync and vsync
//
// and generates a back porch timing pulse that starts
// on a vsync or hsync and continues whilst
// blank_time is low
//
// blank_time is bit4 from nmi207
module lnc (
clock,
vsync,
blank_time,
hsync,
csync,
back_porch,
alt_address
);
input clock;
input vsync;
input blank_time;
input hsync;
output csync;
output back_porch;
output [2:0] alt_address;
wire csync;
reg back_porch;
reg [2:0] alt_address;
assign csync = vsync | hsync;
always @ (posedge vsync or posedge hsync)
begin
if (vsync) alt_address <= 3'b000 ;
else alt_address <= alt_address + 1'b1 ;
end
always @ (posedge clock or posedge csync)
begin
if (csync) back_porch <= 1'b1 ;
else
if (blank_time) back_porch <= 1'b0;
end
endmodule
Code: Select all
/*
ZX81 ULA implementation
Andy Rea march/april 2011
*/
// this module runs off the 3.25Mhz clock
// has a reset (and hold) input
// and 2 outputs
//
// the reset signal when asserted will set the count to 1
// and hold it there for as long as the reset signal is asserted.
//
// bit4 is just bit 4 of the binary count and is used to time
// the back_porch generation in the video.
//
// last 16, is bits 6 & 7 logically anded
// and gives a 16 clock cycle pulse that is used
// to generate Hsync's and the nmi pulses
//
// when left free running (reset de-asserted)
// the count increments by 1 on each cycle
module nmi207 (
clock3,
reset,
bit4,
last16
);
input clock3;
input reset;
output bit4;
output last16;
reg [7:0] count;
assign bit4 = count[4];
assign last16 = count[6] & count[7];
always @ (posedge clock3)
begin
if (!reset & (count != 8'd207))
begin
count <= count + 1'd1 ;
end
else
count <= 8'd1 ;
end
endmodule
Code: Select all
/*
ZX81 ULA implementation
Andy Rea march/april 2011
*/
// this module handle the keyboard io along with tape io and the uk/us bit
//outputs on the databus are never driven high, only low
// this is done because every way i tried i couldn't get the
// output to go open drain if they drove high at any time.
module ferd (
ferd,
force_nop,
kbd,
uk_us,
tape_in,
data_out
);
input ferd;
input force_nop;
input [4:0] kbd;
input uk_us;
input tape_in;
output [7:0] data_out;
// what a load of tosh....
// bit convoluted but it was the only way i could be sure the databus pins
// will be open drain.
// by never driving a logic '1' but 'z' instead
//
// if any drove a '1' the pin was no longer open drain :(
// each line if force_nop is true, drives '0' else it then evaluates ferd
// if ferd is true it then evaluates kbd input if that is true drives 'z' else drives '0'
// if ferd was not true frives 'z'
assign data_out [0] = (force_nop ? 1'b0 : (ferd ? (kbd [0] ? 1'bz : 1'b0 ) : 1'bz ) );
assign data_out [1] = (force_nop ? 1'b0 : (ferd ? (kbd [1] ? 1'bz : 1'b0 ) : 1'bz ) );
assign data_out [2] = (force_nop ? 1'b0 : (ferd ? (kbd [2] ? 1'bz : 1'b0 ) : 1'bz ) );
assign data_out [3] = (force_nop ? 1'b0 : (ferd ? (kbd [3] ? 1'bz : 1'b0 ) : 1'bz ) );
assign data_out [4] = (force_nop ? 1'b0 : (ferd ? (kbd [4] ? 1'bz : 1'b0 ) : 1'bz ) );
//assign data_out [4:0] = ( force_nop ? 5'b00000 : ( ferd ? kbd [4:0] : 5'bzzzzz ) ) ;
assign data_out [5] = (force_nop ? 1'b0 : 1'bz );
assign data_out [6] = (force_nop ? 1'b0 : (ferd ? (uk_us ? 1'bz : 1'b0 ) : 1'bz ) ) ;
assign data_out [7] = (force_nop ? 1'b0 : (ferd ? (tape_in ? 1'bz : 1'b0 ) : 1'bz ) ) ;
endmodule
Code: Select all
/*
ZX81 ULA implementation
Andy Rea march/april 2011
*/
//small state machine to control the sequence of events during a video cycle
module state (
clock6,
m1,
halt,
a15,
d6,
force_nop,
alt_address,
load_vshf
);
input clock6;
input m1;
input halt;
input a15;
input d6;
output force_nop;
output alt_address;
output load_vshf;
wire vid_detect;
wire vid_set;
wire vid_reset;
wire alt_address_start;
wire alt_address_stop;
wire force_nop_start;
wire force_nop_stop;
wire load_vshf_start;
wire load_vshf_stop;
reg vid_cycle;
reg force_nop;
reg alt_address;
reg load_vshf;
reg [2:0] q ;
assign vid_detect = !d6 & a15 & halt & !m1 ;
assign vid_set = (vid_detect & (q == 3)) ;
assign vid_reset = (q != 0) ;
always @ (posedge vid_set or posedge vid_reset) begin
if (vid_set) vid_cycle = 1'b1 ;
else vid_cycle = 1'b0 ;
end
assign force_nop_start = (vid_cycle & !clock6 & (q == 3)) ;
assign force_nop_stop = (!clock6 & (q == 4)) ;
always @ (posedge force_nop_start or posedge force_nop_stop)
begin
if (force_nop_start) force_nop <= 1'b1 ;
else force_nop <= 1'b0 ;
end
assign alt_address_start = ((q == 5) & vid_cycle ) ;
assign alt_address_stop = (!clock6 & (q == 7)) ;
always @ (posedge alt_address_start or posedge alt_address_stop)
begin
if (alt_address_start) alt_address <= 1'b1 ;
else alt_address <= 1'b0 ;
end
assign load_vshf_start = (!clock6 & (q == 6) & vid_cycle) ;
assign load_vshf_stop = (!clock6 & (q == 7) ) ;
always @ (posedge load_vshf_start or posedge load_vshf_stop)
begin
if (load_vshf_start) load_vshf <= 1'b1 ;
else load_vshf <= 1'b0 ;
end
always @ (posedge clock6)
begin
if (q == 0)
if (!m1) q <= 3'b001 ;
else
q <= 3'b000 ;
if (q == 1) q<= 3'b010 ;
if (q == 2) q<= 3'b011 ;
if (q == 3) q<= 3'b100 ;
if (q == 4) q<= 3'b101 ;
if (q == 5) q<= 3'b110 ;
if (q == 6) q<= 3'b111 ;
if (q == 7) q <= 3'b000 ;
end
endmodule
Code: Select all
/*
ZX81 ULA implementation
Andy Rea march/april 2011
*/
// this is the video shifter, it takes the data on the bus and loads
// it in parralell and then shifts it out serially at 6.5Mhz
// when not loading new data zero are shifted in at the lsb end
// the output is the msb end, and each shift is from lsb to msb
//
// there is also an invert signal that is took into consideration
// during a load the data bus can be inverted to produce inverted video
// this is a per load signal and is derived from bit 7 of the char-code
//
// additionally, the back porch is mixed in here, so when the blanking
// is asserted during a load cycle or a shift cycle the output bit will
// remain a logic 1
//
// the video stream is inverted from the shifter to the final output
//
// in zx81 video data is stored in the rom inverted
module vshf (
clock,
data_in,
invert,
blanking,
load_vshf,
vid_out
);
input clock;
input [7:0] data_in;
input invert;
input blanking;
input load_vshf;
output vid_out;
reg [7:0] shifter;
wire vid_out = !shifter [7]; // inverted.
always @ (posedge clock)
begin
if (load_vshf) begin
shifter [7] <= ( blanking ? 1'b1 : (data_in [7] ^ invert) );
shifter [6:0] <= (invert ? ~data_in [6:0] : data_in [6:0] );
end else begin
shifter [7] <= (blanking ? 1'b1 : shifter [6]);
shifter [6:1] <= shifter [5:0];
shifter [0] <= 1'b0 ;
end
end
endmodule
what's that Smell.... smells like fresh flux and solder fumes...