Re: Cart Design Questions
Posted: Tue Jul 09, 2019 3:55 am
Thanks Tiido, that's a good idea.
Sega Megadrive/Genesis development
https://gendev.spritesmind.net/forum/
https://gendev.spritesmind.net/forum/viewtopic.php?f=2&t=2901
Code: Select all
module DebugCart(
// SDRAM
output[11:0] sdramAddr,
output[1:0] sdramBankAddr,
inout[15:0] sdramData,
output sdramClockEnable,
output sdramClk,
output sdramCS,
output sdramRAS,
output sdramCAS,
output sdramWriteEnablePin,
output sdramDataMaskLow,
output sdramDataMaskHigh,
// MD BRIDGE
input mdPresence,
input[21:0] mdAddress,
inout[15:0] mdData,
input mdRead,
// bus transceivers
output mdAddressEnable,
output mdDataEnable,
output mdDataDirectionIsOutput);
/////////////////////////////////////////////////////////
// MD
/////////////////////////////////////////////////////////
reg mdPresence_m1, mdPresence_m2 = 0;
reg mdRead_m1, mdRead_m2 = 1'd1;
reg[21:0] mdAddress_m1, mdAddress_m2;
// assigns
assign mdAddressEnable = !mdPresence_m2; // low activate. so when presence is 3v (active), we set the bus transceiver LOW which activates it
assign mdDataEnable = !(mdPresence_m2 && !mdRead_m2);
assign mdDataDirectionIsOutput = 1'd1; // just keep simple for now
assign mdData = sdramReadResultForMD;
/////////////////////////////////////////////////////////
// SDRAM
/////////////////////////////////////////////////////////
wire[22:0] sdramAddress;
reg [15:0] sdramWriteData = 0;
wire sdramWriteEnable;
wire [15:0] sdramReadData;
wire sdramReadReady;
wire sdramReadEnable;
wire sdramBusy;
reg [15:0] sdramReadResultForMD = 0;
reg sdramClkEnable = 1'd1;
reg sdramRefreshRequest = 1'd0;
sdram_controller2 sdram_controller(
clk,
sdramClkEnable,
armReset,
// host interface
sdramAddress,
sdramWriteEnable,
sdramReadEnable,
sdramRefreshRequest,
sdramWriteData,
sdramReadData,
sdramBusy,
// sdram interface
sdramClk,
sdramClockEnable,
sdramDataMaskHigh,
sdramDataMaskLow,
sdramAddr,
sdramBankAddr,
sdramCS,
sdramWriteEnablePin,
sdramRAS,
sdramCAS,
sdramData);
assign sdramAddress[22] = 0;
assign sdramAddress[21:0] = mdAddress_m2;
assign sdramReadEnable = cpld_state == STATE_SDRAM_ReadForMD_ReadWord;
assign sdramWriteEnable = cpld_state == STATE_SDRAM_WriteForARM_BeginWriteFromARM; // don't worry about this
localparam COMMAND_reset_sdram_read_counter = 3'd0,
COMMAND_reset_sdram_write_counter = 3'd1,
COMMAND_read_sdram = 3'd2,
COMMAND_write_begin_sdram = 3'd3,
COMMAND_write_end_sdram = 3'd4,
COMMAND_change_to_sdram_mode = 3'd5;
localparam STATE_CPLD_Idle = 6'd0,
STATE_SDRAM_ReadForMD_WaitUntilReady = 6'd7,
STATE_SDRAM_ReadForMD_ReadWord = 6'd8,
STATE_SDRAM_ReadForMD_ReadWordComplete = 6'd9,
STATE_SDRAM_ReadForMD_WaitForReadToFinish = 6'd10;
// obviously there are other states here, for reading ROM data to be written to the SDRAM, but I have removed them for readability.
reg[5:0] cpld_state, cpld_state_next;
// combinational section - state machine core state
always @ (*) begin
case (cpld_state)
/*=============================================
MAIN IDLE STATE
=============================================*/
STATE_CPLD_Idle: begin
if (!mdRead_m2) begin
// we need to read data for the MD
cpld_state_next = sdramBusy ? STATE_SDRAM_ReadForMD_WaitUntilReady : STATE_SDRAM_ReadForMD_ReadWord;
end
else cpld_state_next = STATE_CPLD_Idle;
end
/*=============================================
SDRAM READ FOR MD
=============================================*/
STATE_SDRAM_ReadForMD_WaitUntilReady: begin
cpld_state_next = sdramBusy ? STATE_SDRAM_ReadForMD_WaitUntilReady : STATE_SDRAM_ReadForMD_ReadWord;
end
STATE_SDRAM_ReadForMD_ReadWord: begin
cpld_state_next = sdramBusy ? STATE_SDRAM_ReadForMD_ReadWordComplete : STATE_SDRAM_ReadForMD_ReadWord;
end
STATE_SDRAM_ReadForMD_ReadWordComplete: begin
cpld_state_next = STATE_SDRAM_ReadForMD_WaitForReadToFinish;
end
STATE_SDRAM_ReadForMD_WaitForReadToFinish: begin
cpld_state_next = mdRead_m2 ? STATE_CPLD_Idle : STATE_SDRAM_ReadForMD_WaitForReadToFinish;
end
default: cpld_state_next = STATE_CPLD_Idle;
endcase
end
// sequential section - state machine guts
always @ (posedge clk or posedge armReset) begin
if (armReset) begin
cpld_state <= STATE_CPLD_Idle;
mdPresence_m1 <= !mdPresence;
mdPresence_m2 <= !mdPresence_m1;
mdRead_m2 <= 1'd1;
armSendDataToARMPlz <= 0;
// add more reset stuff here
debug_sdram_read_counter <= 0;
debug_sdram_write_counter <= 0;
end
else begin
cpld_state <= cpld_state_next;
mdPresence_m1 <= !mdPresence;
mdPresence_m2 <= !mdPresence_m1;
mdRead_m1 <= !mdRead;
mdRead_m2 <= mdPresence_m2 ? !mdRead_m1 : 1'd1;
mdAddress_m1 <= ~mdAddress;
mdAddress_m2 <= ~mdAddress_m1;
case (cpld_state)
STATE_SDRAM_ReadForMD_ReadWordComplete: begin
sdramReadResultForMD <= sdramReadData;
end
endcase
end
end
endmodule
Code: Select all
module AlcartDebug(
// ARM
//<ARM inputs, outputs>,
// SDRAM
//<SDRAM inputs, outputs>,
// MD BRIDGE
input mdPresence, // taken from 5V fingers on cart through reduction resistors to CPLD pin to sense if MD is running
input mdReset,
input[21:0] mdAddress,
inout[15:0] mdData,
input mdReadCAS0,
output mdAddressDisable, // goes to address and control level shifters
output mdDataDisable, // goes to data level shifter buffer
output mdDataDirectionIsOutput // changes data direction on data level shifter buffer
);
//<SDRAM, ARM, definitions go here, removed for easy reading and because they aren't necessary)
/////////////////////////////////////////////////////////
// MD
/////////////////////////////////////////////////////////
reg mdPresence_sync = 0;
reg mdReset_sync = 1'b1;
reg mdReadCAS0_sync = 1'b1;
reg[21:0] mdAddress_sync;
reg mdDataIsOutput = 1'd1;
reg mdDataDisable_sync = 1'b1;
// assigns
assign mdAddressDisable = ~mdPresence_sync;
assign mdDataDisable = mdDataDisable_sync;
assign mdDataDirectionIsOutput = mdDataIsOutput;
assign mdData = mdDataDirectionIsOutput ? sdramReadDataCached : 16'bz;
assign sdramAddress = (cpld_state == STATE_SDRAM_ReadForARM_WaitUntilReady || cpld_state == STATE_SDRAM_ReadForARM_ReadWord ||
cpld_state == STATE_SDRAM_ReadForArm_WaitForReadToFinish) ? debug_sdram_read_counter :
(cpld_state == STATE_SDRAM_WriteForARM_WaitUntilReady ||
cpld_state == STATE_SDRAM_WriteForARM_BeginWriteFromARM ||
cpld_state == STATE_SDRAM_WriteForARM_WriteFromARM_WaitUntilFinished ? debug_sdram_write_counter : { 1'b0, mdAddress_sync });
assign sdramReadEnable = cpld_state == STATE_SDRAM_ReadForMD_ReadWord || cpld_state == STATE_SDRAM_ReadForARM_ReadWord;
assign sdramWriteEnable = cpld_state == STATE_SDRAM_WriteForARM_BeginWriteFromARM;
/////////////////////////////////////////////////////////
// STATES
/////////////////////////////////////////////////////////
localparam COMMAND_reset_sdram_read_counter = 3'd0,
COMMAND_reset_sdram_write_counter = 3'd1,
COMMAND_read_sdram = 3'd2,
COMMAND_write_begin_sdram = 3'd3,
COMMAND_write_end_sdram = 3'd4,
COMMAND_change_to_sdram_mode = 3'd5;
localparam STATE_CPLD_Init = 6'd0,
STATE_CPLD_Idle = 6'd1,
STATE_SDRAM_ReadForMD_WaitUntilReady = 6'd8,
STATE_SDRAM_ReadForMD_ReadWord = 6'd9,
STATE_SDRAM_ReadForMD_WaitForReadToFinish = 6'd11,
STATE_SDRAM_ReadForARM_WaitUntilReady = 6'd12,
STATE_SDRAM_ReadForARM_ReadWord = 6'd13,
STATE_SDRAM_ReadForArm_WaitForReadToFinish = 6'd14,
STATE_SDRAM_ReadForARM_WaitFor1stReceipt = 6'd15,
STATE_SDRAM_ReadForARM_WaitFor2ndReceipt = 6'd16,
STATE_SDRAM_ReadForARM_FinishARMConversation = 6'd17,
STATE_SDRAM_WriteForARM_WaitForFirstByte = 6'd18,
STATE_SDRAM_WriteForARM_CollectFirstByte = 6'd19,
STATE_SDRAM_WriteForARM_WaitForSecondByte = 6'd20,
STATE_SDRAM_WriteForARM_CollectSecondByte = 6'd21,
STATE_SDRAM_WriteForARM_WaitUntilReady = 6'd22,
STATE_SDRAM_WriteForARM_BeginWriteFromARM = 6'd23,
STATE_SDRAM_WriteForARM_WriteFromARM_WaitUntilFinished = 6'd24,
STATE_SDRAM_WriteForARM_WriteFromARM_FINISH = 6'd25,
STATE_CPLD_AllowNextARMMsgToComeThrough = 6'd31,
STATE_CPLD_Reset_Debug_Read_Counter = 6'd32,
STATE_CPLD_Reset_Debug_Write_Counter = 6'd33,
STATE_SDRAM_DoAutoRefresh = 6'd34,
STATE_SDRAM_DoAutoRefreshForSDRAMWrite = 6'd35
;
reg[5:0] cpld_state = STATE_CPLD_Init, cpld_state_next;
// combinational section - state machine core state
always @ (*) begin
case (cpld_state)
/*=============================================
MAIN IDLE STATE
=============================================*/
STATE_CPLD_Idle: begin
if (mdReset_sync & ~mdReadCAS0_sync) begin
// we need to read data for the MD
cpld_state_next = STATE_SDRAM_ReadForMD_WaitUntilReady;
end
else if (sdramRefreshCounter > 11'd1024)
cpld_state_next = STATE_SDRAM_DoAutoRefresh;
else if (armDataPacketIsAwaitingProcessing) begin
// <removed>
end
else
cpld_state_next = STATE_CPLD_Idle;
end
/*=============================================
SDRAM READ FOR MD
=============================================*/
STATE_SDRAM_ReadForMD_WaitUntilReady: begin
cpld_state_next = sdramBusy ? STATE_SDRAM_ReadForMD_WaitUntilReady : STATE_SDRAM_ReadForMD_ReadWord;
end
STATE_SDRAM_ReadForMD_ReadWord: begin
cpld_state_next = sdramBusy ? STATE_SDRAM_ReadForMD_WaitForReadToFinish : STATE_SDRAM_ReadForMD_ReadWord;
end
STATE_SDRAM_ReadForMD_WaitForReadToFinish: begin
cpld_state_next = mdReadCAS0_sync ? STATE_CPLD_Idle : STATE_SDRAM_ReadForMD_WaitForReadToFinish;
end
// < other states removed here as they aren't necessary for reading this problem>
default: cpld_state_next = STATE_CPLD_Idle;
endcase
end
always @ (posedge clk) begin
if (cpld_state == STATE_SDRAM_DoAutoRefresh | cpld_state == STATE_SDRAM_DoAutoRefreshForSDRAMWrite) begin
sdramRefreshEnable <= 1'b1;
sdramRefreshCounter <= 0;
end
else begin
sdramRefreshEnable <= 0;
sdramRefreshCounter <= sdramRefreshCounter + 1'b1;
end
end
// sequential section - state machine guts
always @ (posedge clk or posedge armReset) begin
if (armReset) begin
cpld_state <= STATE_CPLD_Init;
mdPresence_sync <= mdPresence;
mdReset_sync <= mdReset;
mdReadCAS0_sync <= 1'b1;
mdDataDisable_sync <= 1'b1;
armSendDataToARMPlz <= 0;
sdramReset <= 1'd1;
mdDataIsOutput <= 0;
// add more reset stuff here
debug_sdram_read_counter <= 0;
debug_sdram_write_counter <= 0;
end
else begin
cpld_state <= cpld_state_next;
// sync md signals to our clock
mdPresence_sync <= mdPresence;
mdReset_sync <= mdReset;
mdReadCAS0_sync <= mdReadCAS0;
mdAddress_sync <= mdAddress;
mdDataDisable_sync <= 1'b1;
armSendDataToARMPlz <= 0;
sdramReset <= 0;
mdDataIsOutput <= 1'b1;
case (cpld_state)
STATE_SDRAM_ReadForMD_WaitForReadToFinish: begin
if (sdramReadValid) begin
sdramReadDataCached <= sdramReadData;
end
mdDataDisable_sync <= 0;
end
// <other states removed here as they aren't applicable to the probem>
endcase
end
end
endmodule
Code: Select all
dc.l 0,8
loop: reset
bra.s loop
Code: Select all
dc.l 0,8
repeat:
lea $0100.w, a0
movem.l (a0)+, d0-d3
bra.s repeat
Code: Select all
reg mdDataIsOutput = 1'b1;
assign mdDataTransceiverDataDirection = mdDataIsOutput;
assign mdDataTransceiverOutputEnable = ~mdCartPluggedIn | mdReadCAS0_sync; // active low, so a 0 result from this query means data is active, a 1 means transceiver is tri-stated
assign mdData = mdDataIsOutput ? sdramData : 16'bz;
assign sdramReadRequest = cpld_state == state_md_read;
// pseudo code for state machine
always @ (*) begin
case (cpld_state)
state_idle: begin
state_next = mdCartPluggedIn & ~mdReadCAS0_sync ? state_md_read_wait_for_ready : state_idle;
end
state_md_read_wait_for_ready: begin
state_next = sdramBusy ? state_md_read_wait_for_ready : state_md_read;
end
state_md_read: begin
state_next = state_md_wait_for_finish;
end
state_md_wait_for_finish: begin
state_next = ~mdCartPluggedIn | mdReadCAS0_sync ? state_idle : state_md_wait_for_finish;
end
default:
state_next = state_idle;
endcase
end
always @ (posedge clk) begin
cpld_state <= state_next;
if (reset) begin
// blah
end
else begin
// the following flip-flop copies are for metastability
mdReadCAS0_sync <= mdReadCAS0;
mdAddress_sync <= mdAddress;
mdDataIsOutput <= 1'b1;
case (cpld_state)
state_md_read: begin
sdramAddress <= mdAddress_sync;
end
endcase
end // else reset
end