Rebuilt state machine again
This commit is contained in:
parent
6f2f67ef05
commit
5377d05895
303
se-xga.sv
303
se-xga.sv
|
@ -40,19 +40,11 @@ logic [10:0] hCount; // 0..1343
|
||||||
logic [9:0] vCount; // 0..805
|
logic [9:0] vCount; // 0..805
|
||||||
wire nhSyncInner;
|
wire nhSyncInner;
|
||||||
|
|
||||||
// horizontal counter
|
// Primary video sync counters -- Now more synchronous!
|
||||||
always @(negedge pixClk or negedge nReset) begin
|
always @(negedge pixClk) begin
|
||||||
if(!nReset) hCount <= 0;
|
if(hCount < 11'd1343) hCount <= hCount + 11'd1;
|
||||||
else begin
|
|
||||||
if(hCount < 11'd1343) hCount <= hCount + 11'd1;
|
|
||||||
else hCount <= 11'd0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// vertical counter
|
|
||||||
always @(negedge nhSyncInner or negedge nReset) begin
|
|
||||||
if(!nReset) vCount <= 0;
|
|
||||||
else begin
|
else begin
|
||||||
|
hCount <= 11'd0;
|
||||||
if(vCount < 10'd805) vCount <= vCount + 10'd1;
|
if(vCount < 10'd805) vCount <= vCount + 10'd1;
|
||||||
else vCount <= 10'd0;
|
else vCount <= 10'd0;
|
||||||
end
|
end
|
||||||
|
@ -96,138 +88,79 @@ end
|
||||||
* VRAM reads, VRAM writes, VIA writes, and idle states
|
* VRAM reads, VRAM writes, VIA writes, and idle states
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// used to align primary state machine with horizontal counter
|
||||||
|
wire [3:0] vSeq = hCount[3:0];
|
||||||
|
|
||||||
// define state machine states (Gray code)
|
// define state machine states (Gray code)
|
||||||
parameter
|
parameter
|
||||||
P0 = 4'b0000, // VRAM Read 0
|
S0 = 4'b0000, // VRAM Read 0
|
||||||
P1 = 4'b0001, // VRAM Read 1
|
S1 = 4'b0001, // VRAM Read 1
|
||||||
P2 = 4'b0011, // Idle 0
|
S2 = 4'b0011, // Idle
|
||||||
P3 = 4'b0010, // Idle 1
|
S3 = 4'b0010, // VRAM Write Upper 0
|
||||||
P4 = 4'b0110, // VRAM Write Upper 0
|
S4 = 4'b0110, // VRAM Write Upper 1
|
||||||
P5 = 4'b0111, // VRAM Write Upper 1
|
S5 = 4'b0111, // VRAM Write Lower 0
|
||||||
P6 = 4'b0101, // VRAM Write Lower 0
|
S6 = 4'b0101, // VRAM Write Lower 1
|
||||||
P7 = 4'b0100, // VRAM Write Lower 1
|
S7 = 4'b0100, // VIA Write
|
||||||
P8 = 4'b1100, // VIA Write 0
|
S8 = 4'b1100, // VSync (to be added later)
|
||||||
P9 = 4'b1101, // VIA Write 1
|
S9 = 4'b1101, // undefined
|
||||||
P10 = 4'b1111, // undefined
|
S10 = 4'b1111, // undefined
|
||||||
P11 = 4'b1110, // undefined
|
S11 = 4'b1110, // undefined
|
||||||
P12 = 4'b1010, // undefined
|
S12 = 4'b1010, // undefined
|
||||||
P13 = 4'b1011, // undefined
|
S13 = 4'b1011, // undefined
|
||||||
P14 = 4'b1001, // undefined
|
S14 = 4'b1001, // undefined
|
||||||
P15 = 4'b1000; // undefined
|
S15 = 4'b1000; // undefined
|
||||||
|
|
||||||
logic [3:0] pState;
|
logic [3:0] pState;
|
||||||
|
|
||||||
|
// And here is the much simplified primary state machine
|
||||||
always @(negedge pixClk or negedge nReset) begin
|
always @(negedge pixClk or negedge nReset) begin
|
||||||
if(!nReset) pState <= P0;
|
if(!nReset) pState <= S2; // resync on reset by jumping to idle state
|
||||||
else begin
|
else begin
|
||||||
case (pState)
|
case(pState)
|
||||||
P0 : begin
|
S0: pState <= S1; // first VRAM read state, always move to S1
|
||||||
// first VRAM read state, always move to P1
|
S3: pState <= S4; // first UDS write state, always move to S4
|
||||||
pState <= P1;
|
S5: pState <= S6; // first LDS write state, always move to S6
|
||||||
end
|
/*S7: begin
|
||||||
P1 : begin
|
|
||||||
// move to appropriate VRAM write state or idle
|
pState <= S2;
|
||||||
if(cpuUWriteReq && !cpuUWriteSrv) pState <= P4;
|
end*/
|
||||||
else if(cpuLWriteReq && !cpuLWriteSrv) pState <= P6;
|
S2: begin
|
||||||
else if(cpuVIAReq && !cpuVIASrv) pState <= P8;
|
// here is where everything actually happens.
|
||||||
else pState <= P2;
|
if(vSeq == 4'hF) pState <= S0; // time for a read state
|
||||||
end
|
else if(cpuUWriteReq && !cpuUWriteSrv && vSeq < 4'hD) pState <= S3;
|
||||||
P2 : begin
|
else if(cpuLWriteReq && !cpuLWriteSrv && vSeq < 4'hD) pState <= S5;
|
||||||
// first idle state.
|
else if(cpuVIAReq && !cpuVIASrv && vSeq < 4'hE) pState <= S7;
|
||||||
// we'll use this state to make sure we're synchronized with
|
else pState <= S2;
|
||||||
// the tick-tock clock states, so if we've made it here on a
|
|
||||||
// tock state, stay here until the next tick state.
|
|
||||||
if(tick) pState <= P3;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
|
||||||
P3 : begin
|
|
||||||
// second idle state. Here is where things get fun.
|
|
||||||
case (vidSeq)
|
|
||||||
7 : begin
|
|
||||||
pState <= P0;
|
|
||||||
end
|
|
||||||
6 : begin
|
|
||||||
if(cpuUWriteReq && !cpuUWriteSrv && !cpuLWriteReq) pState <= P4;
|
|
||||||
else if(cpuLWriteReq && !cpuLWriteSrv) pState <= P6;
|
|
||||||
else if(cpuVIAReq && !cpuVIASrv) pState <= P8;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
if(cpuUWriteReq && !cpuUWriteSrv) pState <= P4;
|
|
||||||
else if(cpuLWriteReq && !cpuLWriteSrv) pState <= P6;
|
|
||||||
else if(cpuVIAReq && !cpuVIASrv) pState <= P8;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
P4 : begin
|
|
||||||
// first VRAM Write Upper state, always move to P5
|
|
||||||
pState <= P5;
|
|
||||||
end
|
|
||||||
P5 : begin
|
|
||||||
// second VRAM Write Upper state,
|
|
||||||
if(vidSeq == 7) pState <= P0;
|
|
||||||
else if(cpuBufAddr && !ncpuLDS) pState <= P6;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
|
||||||
P6 : begin
|
|
||||||
// first VRAM Write Lower state, always move to P7
|
|
||||||
pState <= P7;
|
|
||||||
end
|
|
||||||
P7 : begin
|
|
||||||
// second VRAM Write Lower state
|
|
||||||
if(vidSeq == 7) pState <= P0;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
|
||||||
P8 : begin
|
|
||||||
// first VIA write state, always move to P9
|
|
||||||
pState <= P9;
|
|
||||||
end
|
|
||||||
P9 : begin
|
|
||||||
// second VIA write state
|
|
||||||
vidBufSel <= ~cpuData[14];
|
|
||||||
if(vidSeq == 7) pState <= P0;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
// how did we end up here? We need to align with the sequence
|
|
||||||
// counter before we move to S0
|
|
||||||
if(vidSeq == 7 && tock) pState <= P0;
|
|
||||||
else if(tick) pState <= P3;
|
|
||||||
else pState <= P2;
|
|
||||||
end
|
end
|
||||||
|
default: pState <= S2; // everyone ends up at S2 (idle)
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// primary signal combination, based on the state machine above
|
// primary VRAM signal combination, based on the primary state machine
|
||||||
always_comb begin
|
always_comb begin
|
||||||
// VRAM Read strobe
|
// VRAM Read Strobe
|
||||||
if((pState == P0 || pState == P1) && vidActive) nvramOE <= 0;
|
if((pState == S0 || pState == S1) && hLoad) nvramOE <= 0;
|
||||||
else nvramOE <= 1;
|
else nvramOE <= 1;
|
||||||
|
|
||||||
// VRAM Write strobe
|
// VRAM Write Strobe
|
||||||
if(pState == P4 || pState == P6) nvramWE <= 0;
|
if(pState == S3 || pState == S5) nvramWE <= 0;
|
||||||
else nvramWE <= 1;
|
else nvramWE <= 1;
|
||||||
|
|
||||||
// VRAM Chip Enable signals
|
// VRAM Chip Enable Signals
|
||||||
case(pState)
|
case(pState)
|
||||||
P0, P1 : begin
|
S0, S1: begin
|
||||||
if(vidActive) begin
|
if(hLoad) begin
|
||||||
nvramCE0 <= hCount[4];
|
nvramCE0 <= ~vidBufSel;
|
||||||
nvramCE1 <= ~hCount[4];
|
nvramCE1 <= vidBufSel;
|
||||||
end else begin
|
end else begin
|
||||||
nvramCE0 <= 1;
|
nvramCE0 <= 1;
|
||||||
nvramCE1 <= 1;
|
nvramCE1 <= 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
P4, P5 : begin
|
S3, S4, S5, S6: begin
|
||||||
nvramCE0 <= 0;
|
nvramCE0 <= ~cpuBufSel;
|
||||||
nvramCE1 <= 1;
|
nvramCE1 <= cpuBufSel;
|
||||||
end
|
|
||||||
P6, P7 : begin
|
|
||||||
nvramCE0 <= 1;
|
|
||||||
nvramCE1 <= 0;
|
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
nvramCE0 <= 1;
|
nvramCE0 <= 1;
|
||||||
|
@ -235,30 +168,37 @@ always_comb begin
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
// VRAM Address bus
|
// VRAM Address Bus
|
||||||
case(pState)
|
case(pState)
|
||||||
P0, P1 : begin
|
S0, S1: begin
|
||||||
|
// address bus for read cycles
|
||||||
if(hLoad) begin
|
if(hLoad) begin
|
||||||
vramAddr[14] <= vidBufSel;
|
vramAddr[14:6] <= vCount[9:1];
|
||||||
vramAddr[13:5] <= vCount[9:1];
|
vramAddr[5:0] <= hCount[9:4];
|
||||||
vramAddr[4:0] <= hCount[9:5];
|
|
||||||
end else begin
|
end else begin
|
||||||
vramAddr <= 0;
|
vramAddr <= 0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
P4, P5, P6, P7 : begin
|
S3, S4: begin
|
||||||
vramAddr[14] <= cpuBufSel;
|
// address bus for upper write cycles
|
||||||
vramAddr[13:0] <= cpuAddr[14:1] - 14'h1380;
|
vramAddr[14:1] <= cpuAddr[14:1] - 14'h1380;
|
||||||
|
vramAddr[0] <= 0;
|
||||||
|
end
|
||||||
|
S5, S6: begin
|
||||||
|
// address bus for lower write cycles
|
||||||
|
vramAddr[14:1] <= cpuAddr[14:1] - 14'h1380;
|
||||||
|
vramAddr[0] <= 1;
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
|
// address bus for idle cycles
|
||||||
vramAddr <= 0;
|
vramAddr <= 0;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
// VRAM Data bus
|
// VRAM Data bus
|
||||||
case(pState)
|
case(pState)
|
||||||
P4, P5 : vramData <= cpuData[15:8];
|
S3, S4 : vramData <= cpuData[15:8];
|
||||||
P6, P7 : vramData <= cpuData[7:0];
|
S5, S6 : vramData <= cpuData[7:0];
|
||||||
default: vramData <= 8'hZ;
|
default: vramData <= 8'hZ;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -270,39 +210,27 @@ end
|
||||||
* signals and see the strapped pattern output on screen.
|
* signals and see the strapped pattern output on screen.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
logic [8:0] vidData; // the video data we are displaying
|
logic [8:0] vidData; // the video data we are displaying
|
||||||
wire [2:0] vidSeq; // sequence counter, derived from hCount
|
//wire [2:0] vidSeq; // sequence counter, derived from hCount
|
||||||
wire tick, tock; // even/odd pulses of pixel clock divided by 2
|
//wire tick, tock; // even/odd pulses of pixel clock divided by 2
|
||||||
|
|
||||||
assign vidSeq = hCount[3:1];
|
// output shift register
|
||||||
assign tick = !hCount[0];
|
always @(posedge pixClk) begin
|
||||||
assign tock = hCount[0];
|
if(pState == S1 && hLoad) begin
|
||||||
|
// store VRAM data in shift register
|
||||||
// for some reason changing this function to use pState==P1 instead of the old
|
vidData[7:0] <= vramData;
|
||||||
// tock && vidSeq==0 caused utilization to jump up 10 macrocells, and the
|
end else if(!hCount[0] && vidActive) begin
|
||||||
// monitor reported sync out of range. No idea what happened there so we'll
|
// shift out video data
|
||||||
// leave this function as it is, since it seems to be working.
|
vidData[8:1] <= vidData[7:0];
|
||||||
always @(negedge pixClk or negedge nReset) begin
|
vidData[0] <= 0;
|
||||||
if(!nReset) vidData <= 0;
|
|
||||||
else begin
|
|
||||||
if(tock && hLoad && vidSeq == 3'd0) begin
|
|
||||||
//if(pState == P1 && hLoad) begin
|
|
||||||
// store the VRAM data in vidData[7:0]
|
|
||||||
vidData[7:0] <= vramData;
|
|
||||||
end else if(tick && hLoad) begin
|
|
||||||
// shift vidData
|
|
||||||
vidData[8:1] <= vidData[7:0];
|
|
||||||
vidData[0] <= 0;
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// final video output
|
||||||
always_comb begin
|
always_comb begin
|
||||||
// here is where the shifted video data actually gets output
|
|
||||||
if(vidActive) vidOut <= ~vidData[8];
|
if(vidActive) vidOut <= ~vidData[8];
|
||||||
else vidOut <= 0;
|
else vidOut <= 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* CPU Bus Snooping
|
* CPU Bus Snooping
|
||||||
* Watch the CPU bus for writes to the video buffer regions of memory and write
|
* Watch the CPU bus for writes to the video buffer regions of memory and write
|
||||||
|
@ -332,34 +260,49 @@ end
|
||||||
// keep track of pending CPU write requests and whether they have been serviced
|
// keep track of pending CPU write requests and whether they have been serviced
|
||||||
wire cpuUWriteReq, cpuLWriteReq, cpuVIAReq;
|
wire cpuUWriteReq, cpuLWriteReq, cpuVIAReq;
|
||||||
reg cpuUWriteSrv, cpuLWriteSrv, cpuVIASrv;
|
reg cpuUWriteSrv, cpuLWriteSrv, cpuVIASrv;
|
||||||
wire cpuBufSel = ~cpuAddr[15];
|
wire cpuBufSel;
|
||||||
wire cpuBufAddr;
|
wire cpuBufAddr;
|
||||||
reg vidBufSel;
|
reg vidBufSel;
|
||||||
|
|
||||||
// these are some helpful signals that shortcut the CPU buffer & VIA addresses
|
// these are some helpful signals that shortcut the CPU buffer & VIA addresses
|
||||||
always_comb begin
|
always_comb begin
|
||||||
// remember cpuAddr is shifted right by one since 68000 does not output A0
|
|
||||||
if(!ncpuAS && !cpuRnW
|
if(!ncpuAS && !cpuRnW
|
||||||
&& cpuAddr[23:22] == 2'b00 // initial constant
|
&& !cpuAddr[23] && !cpuAddr[22] // first two bits always 0
|
||||||
&& ramSize == cpuAddr[21:19] // ram size selection
|
&& !(cpuAddr[21] ^ ramSize[2]) // compare with RAM Size bits
|
||||||
&& cpuAddr[18:16] == 3'b111 // trailing constant
|
&& !(cpuAddr[20] ^ ramSize[1])
|
||||||
// next bit is main/alt select
|
&& !(cpuAddr[19] ^ ramSize[0])
|
||||||
&& (cpuAddr[14:1] >= 14'h1380 // bottom of buffer range (0x2700>>1)
|
&& cpuAddr[18] && cpuAddr[17] // next three bits always 1
|
||||||
&& cpuAddr[14:1] <= 14'h3e3f) // top of buffer range (0x7C70>>1)
|
&& cpuAddr[16] // skip 15, it selects buffers
|
||||||
) begin
|
&& (cpuAddr[14] || cpuAddr[13]) // if neither 13|14 then not buffer
|
||||||
cpuBufAddr <= 1'b1;
|
) begin
|
||||||
|
cpuBufAddr <= 1;
|
||||||
end else begin
|
end else begin
|
||||||
cpuBufAddr <= 1'b0;
|
cpuBufAddr <= 0;
|
||||||
end
|
end
|
||||||
|
cpuBufSel <= ~cpuAddr[15]; // address bit 15 selects buffer
|
||||||
|
|
||||||
if(cpuBufAddr && !ncpuUDS) cpuUWriteReq <= 1;
|
if(cpuBufAddr && !ncpuUDS) cpuUWriteReq <= 1;
|
||||||
else cpuUWriteReq <= 0;
|
else cpuUWriteReq <= 0;
|
||||||
if(cpuBufAddr && !ncpuLDS) cpuLWriteReq <= 1;
|
if(cpuBufAddr && !ncpuLDS) cpuLWriteReq <= 1;
|
||||||
else cpuLWriteReq <= 0;
|
else cpuLWriteReq <= 0;
|
||||||
|
|
||||||
if(!ncpuAS && !cpuRnW && !ncpuUDS
|
// VIA is in address block $E8,0000 - $EF,FFFF
|
||||||
&& cpuAddr[23:19] == 5'h1D
|
// VIA register select pins (RS[3:0]) are wired to cpuAddr[12:9]
|
||||||
&& cpuAddr[12:8] == 5'h1F) cpuVIAReq <= 1;
|
// VIA Output Register A is selected when RS[3:0]==$F
|
||||||
|
/*if(!ncpuAS && !cpuRnW && !ncpuUDS
|
||||||
|
&& cpuAddr[23] && cpuAddr[22] // VIA Address Select
|
||||||
|
&& cpuAddr[21] && !cpuAddr[20]
|
||||||
|
&& cpuAddr[19]
|
||||||
|
&& cpuAddr[12] && cpuAddr[11] // VIA ORA
|
||||||
|
&& cpuAddr[10] && cpuAddr[9]
|
||||||
|
) cpuVIAReq <= 1;
|
||||||
|
else cpuVIAReq <= 0;*/
|
||||||
|
// Mac ROM addresses Data Register A as vBase+vBufA:
|
||||||
|
// $EF,E1FE + (512*15) = $EF,FFFE
|
||||||
|
// shift right by one because no A0 and we get $77,FFFF
|
||||||
|
// This bit is giving me hell, so let's expand it
|
||||||
|
if(ncpuAS==0 && cpuRnW==0 && ncpuUDS==0
|
||||||
|
&& cpuAddr == 22'h77FFFF) cpuVIAReq <= 1;
|
||||||
else cpuVIAReq <= 0;
|
else cpuVIAReq <= 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -376,20 +319,18 @@ always @(posedge pixClk or posedge ncpuAS) begin
|
||||||
cpuLWriteSrv <= 0;
|
cpuLWriteSrv <= 0;
|
||||||
cpuVIASrv <= 0;
|
cpuVIASrv <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
if(cpuUWriteReq && pState == P4) cpuUWriteSrv <= 1;
|
if(cpuUWriteReq && pState == S3) cpuUWriteSrv <= 1;
|
||||||
if(cpuLWriteReq && pState == P6) cpuLWriteSrv <= 1;
|
if(cpuLWriteReq && pState == S5) cpuLWriteSrv <= 1;
|
||||||
if(cpuVIAReq && pState == P8) cpuVIASrv <= 1;
|
if(cpuVIAReq && pState == S7) cpuVIASrv <= 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// when servicing a CPU VIA request, read the CPU data bus to set the video
|
// store the video buffer selection bit
|
||||||
// buffer selection bit. Main: 1, Alt: 0
|
always @(posedge pixClk or negedge nReset) begin
|
||||||
/*always @(posedge pixClk or negedge nReset) begin
|
if(!nReset) vidBufSel <= 0;
|
||||||
if(!nReset) vidBufSel <= 1;
|
// fine. no video buffer select. we use Main only.
|
||||||
else if(pState == P8) begin
|
//else if(pState == S7) vidBufSel <= ~cpuData[14];
|
||||||
vidBufSel <= ~cpuData[14];
|
end
|
||||||
end
|
|
||||||
end*/
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
Loading…
Reference in New Issue