summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/video/bbc.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2012-08-21 10:41:19 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2012-08-21 10:41:19 +0000
commit7285b359d259b2ae0fdf85096571c386ec8c991a (patch)
treea027aff57f1a255f9ec6cfd3b68cabe4b6683998 /src/mess/video/bbc.c
parent67c425e90757876a6716b7867df30c0149912e74 (diff)
Merge of MESS sources (no whatsnew)
Diffstat (limited to 'src/mess/video/bbc.c')
-rw-r--r--src/mess/video/bbc.c694
1 files changed, 694 insertions, 0 deletions
diff --git a/src/mess/video/bbc.c b/src/mess/video/bbc.c
new file mode 100644
index 00000000000..e113a04c4be
--- /dev/null
+++ b/src/mess/video/bbc.c
@@ -0,0 +1,694 @@
+/******************************************************************************
+ BBC Model B
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@romvault.com
+
+ This is the first go around at converting the BBC code over to using
+ mames built in mc6845, there are a number of features now incorrect
+ or missing in this build:
+
+ Cursors are missing.
+ Mode 7 is shifted to the right by a couple of character.
+ BBC split modes no longer work (Like is used in Elite.)
+
+******************************************************************************/
+
+#include "emu.h"
+#include "includes/bbc.h"
+#include "saa505x.h"
+#include "video/mc6845.h"
+
+/************************************************************************
+ * C0 and C1 along with MA12 output from the 6845 drive 4 NAND gates in ICs 27,36 and 40
+ * the outputs from these NAND gates (B1 to B4) along with MA8 to MA11 from the 6845 (A1 to B4) are added together
+ * in IC39 74LS283 4 bit adder to form (S1 to S4) the logic is used to loop the screen memory for hardware scrolling.
+ * when MA13 from the 6845 is low the latches IC8 and IC9 are enabled
+ * they control the memory addressing for the Hi-Res modes.
+ * when MA13 from the 6845 is high the latches IC10 and IC11 are enabled
+ * they control the memory addressing for the Teletext mode.
+ * IC 8 or IC10 drives the row select in the memory (the lower 7 bits in the memory address) and
+ * IC 9 or IC11 drives the column select in the memory (the next 7 bits in the memory address) this
+ * gives control of the bottom 14 bits of the memory, in a 32K model B 15 bits are needed to access
+ * all the RAM, so S4 for the adder drives the CAS0 and CAS1 to access the top bit, in a 16K model A
+ * the output of S4 is linked out to a 0v supply by link S25 to just access the 16K memory area.
+ ************************************************************************/
+
+unsigned int calculate_video_address(bbc_state *state,int ma,int ra)
+{
+ // ma = output from IC2 6845 MA address
+
+ int c0=state->m_b4_video0; // output from IC32 74LS259 bits 4 and 5
+ int c1=state->m_b5_video1;
+
+ /* the 4 bit input port b on IC39 are produced by 4 NAND gates.
+ these NAND gates take their
+ inputs from c0 and c1 (from IC32) and ma12 (from the 6845) */
+
+ /* get bit m12 from the 6845 */
+ int ma12=(ma>>12)&1;
+
+ // 4 bit input B on IC39 74LS283 (4 bit adder)
+ /* 3 input NAND part of IC 36 */
+ int b1=(~(c1 & c0 & ma12)) & 1;
+ /* 2 input NAND part of IC40 (b3 is calculated before b2 and b4 because b3 feed back into b2 and b4) */
+ int b3=(~(c0 & ma12)) & 1;
+ /* 3 input NAND part of IC 36 */
+ int b2=(~(c1 & b3 & ma12)) & 1;
+ /* 2 input NAND part of IC 27 */
+ int b4=(~(b3 & ma12)) & 1;
+
+ /* inputs port b to IC39 are taken from the NAND gates b1 to b4 */
+ int b=(b1<<0)|(b2<<1)|(b3<<2)|(b4<<3);
+
+ /* inputs port a to IC39 are MA8 to MA11 from the 6845 */
+ int a=(ma>>8)&0xf;
+
+ /* IC39 performs the 4 bit add with the carry input set high */
+ int s=(a+b+1)&0xf;
+
+ /* if MA13 (TTXVDU) is low then IC8 and IC9 are used to calculate
+ the memory location required for the hi res video.
+ if MA13 is hight then IC10 and IC11 are used to calculate the memory location for the teletext chip*/
+ unsigned int m;
+ if ((ma>>13)&1)
+ {
+ // IC 10 and IC 11
+ m=((ma&0x3ff)|0x3c00)|((s&0x8)<<11);
+ } else {
+ // IC 8 and IC 9
+ m=((ma&0xff)<<3)|(s<<11)|(ra&0x7);
+ }
+ if (state->m_memorySize==16)
+ return m & 0x3fff;
+
+ return m;
+}
+
+/************************************************************************
+ * VideoULA
+ ************************************************************************/
+
+static const int pixels_per_byte_set[8]={ 2,4,8,16,1,2,4,8 };
+
+static const int width_of_cursor_set[8]={ 0,0,1,2,1,0,2,4 };
+
+/* this is a quick lookup array that puts bits 0,2,4,6 into bits 0,1,2,3
+ this is used by the pallette lookup in the video ULA */
+static void set_pixel_lookup(bbc_state *state)
+{
+ int i;
+ for (i=0; i<256; i++)
+ {
+ state->m_pixel_bits[i] = (((i>>7)&1)<<3) | (((i>>5)&1)<<2) | (((i>>3)&1)<<1) | (((i>>1)&1)<<0);
+ }
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_videoULA_w)
+{
+
+ // Make sure vpos is never <0 2008-10-11 PHS.
+ int vpos=machine().primary_screen->vpos();
+ if(vpos==0)
+ machine().primary_screen->update_partial(vpos);
+ else
+ machine().primary_screen->update_partial(vpos -1 );
+
+ logerror("setting videoULA %.4x to:%.4x at :%d \n",data,offset,machine().primary_screen->vpos() );
+
+
+ switch (offset&0x01)
+ {
+ // Set the control register in the Video ULA
+ case 0:
+ {
+ m_videoULA_Reg=data;
+ m_videoULA_master_cursor_size= (m_videoULA_Reg>>7)&0x01;
+ m_videoULA_width_of_cursor= (m_videoULA_Reg>>5)&0x03;
+ m_videoULA_6845_clock_rate= (m_videoULA_Reg>>4)&0x01;
+ m_videoULA_characters_per_line= (m_videoULA_Reg>>2)&0x03;
+ m_videoULA_teletext_normal_select=(m_videoULA_Reg>>1)&0x01;
+ m_videoULA_flash_colour_select= m_videoULA_Reg &0x01;
+
+ m_videoULA_pallet_lookup=m_videoULA_flash_colour_select?m_videoULA_pallet0:m_videoULA_pallet1;
+
+ m_emulation_cursor_size=width_of_cursor_set[m_videoULA_width_of_cursor|(m_videoULA_master_cursor_size<<2)];
+
+ // this is the number of BBC pixels held in each byte
+ if (m_videoULA_teletext_normal_select)
+ {
+ m_pixels_per_byte=6;
+ } else {
+ m_pixels_per_byte=pixels_per_byte_set[m_videoULA_characters_per_line|(m_videoULA_6845_clock_rate<<2)];
+ }
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+ mc6845->set_hpixels_per_column(m_pixels_per_byte);
+ if (m_videoULA_6845_clock_rate)
+ mc6845->set_clock(2000000);
+ else
+ mc6845->set_clock(1000000);
+ }
+ break;
+ // Set a pallet register in the Video ULA
+ case 1:
+ int tpal=(data>>4)&0x0f;
+ int tcol=data&0x0f;
+ m_videoULA_pallet0[tpal]=tcol;
+ m_videoULA_pallet1[tpal]=tcol<8?tcol:tcol^7;
+ break;
+ }
+}
+
+// VideoULA Internal Cursor controls
+
+/*
+static void set_cursor(bbc_state *state)
+{
+ state->m_cursor_state=state->m_VideoULA_CR?0:7;
+}
+
+static void BBC_Clock_CR(bbc_state *state)
+{
+ if (state->m_VideoULA_CR)
+ {
+ state->m_VideoULA_CR_counter-=1;
+ if (state->m_VideoULA_CR_counter<=0) {
+ state->m_VideoULA_CR=0;
+ set_cursor(state);
+ }
+ }
+}
+*/
+/************************************************************************
+ * BBC circuits controlled by 6845 Outputs
+ ************************************************************************/
+
+int returned_pixel_count;
+int returned_pixels[6];
+
+static MC6845_UPDATE_ROW( vid_update_row )
+{
+
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ logerror("MC6845_UPDATE_ROW: ma=%d, ra=%d, y=%d, x_count=%d\n",ma,ra,y,x_count);
+
+ if (state->m_videoULA_teletext_normal_select)
+ {
+
+ teletext_LOSE_w(state->m_saa505x, 0,0);
+ teletext_LOSE_w(state->m_saa505x, 0,1);
+
+ for(int x_pos=0; x_pos<x_count; x_pos++)
+ {
+ //Teletext Latch bits 0 to 5 go to bits 0 to 5 on the Teletext chip
+ //Teletext Latch bit 6 is only passed onto bits 6 on the Teletext chip if DE is true
+ //Teletext Latch bit 7 goes to LOSE on the Teletext chip
+
+ returned_pixel_count=0;
+
+
+ teletext_F1(state->m_saa505x);
+
+ teletext_data_w(state->m_saa505x, 0, (state->m_Teletext_Latch&0x3f)|(state->m_Teletext_Latch&0x40));
+
+ if (((ma>>13)&1)==0)
+ {
+ state->m_Teletext_Latch=0;
+ } else {
+ state->m_Teletext_Latch=(state->m_BBC_Video_RAM[calculate_video_address(state,ma+x_pos,ra)]&0x7f);
+ }
+ for(int pixelno=0;pixelno<6;pixelno++)
+ {
+ int col=returned_pixels[pixelno];
+
+ bitmap.pix32(y, (x_pos*state->m_pixels_per_byte)+pixelno)=palette[col];
+ }
+
+
+ }
+ }
+ else
+ {
+ // this is IC38 and IC41 takes 6845 DisplayEnabled and 6845 RA3
+ int DE= !(ra>=8);
+
+ if (DE)
+ {
+ for(int x_pos=0; x_pos<x_count; x_pos++)
+ {
+ int vmem=calculate_video_address(state,ma+x_pos,ra);
+ unsigned char i=state->m_BBC_Video_RAM[vmem];
+
+ for(int pixelno=0;pixelno<state->m_pixels_per_byte;pixelno++)
+ {
+ int col=state->m_videoULA_pallet_lookup[state->m_pixel_bits[i]];
+ bitmap.pix32(y, (x_pos*state->m_pixels_per_byte)+pixelno)=palette[col];
+ i=(i<<1)|1;
+ }
+ }
+ }
+ else
+ {
+ for(int x_pos=0; x_pos<x_count; x_pos++)
+ {
+ for(int pixelno=0;pixelno<state->m_pixels_per_byte;pixelno++)
+ {
+ bitmap.pix32(y, (x_pos*state->m_pixels_per_byte)+pixelno)=palette[7];
+ }
+ }
+ }
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( bbc_vsync )
+{
+ bbc_state *bstate = device->machine().driver_data<bbc_state>();
+ teletext_DEW(bstate->m_saa505x);
+}
+
+
+const mc6845_interface bbc_mc6845_intf =
+{
+ "screen", /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ vid_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_NULL, /* on_hsync_changed */
+ DEVCB_LINE(bbc_vsync), /* on_vsync_changed */
+ NULL
+};
+
+
+void bbc_draw_RGB_in(device_t *device, int offset,int data)
+{
+ if (returned_pixel_count<6)
+ returned_pixels[returned_pixel_count++]=7-data;
+
+}
+
+
+
+
+/************************************************************************
+ * memory interface to BBC's 6845
+ ************************************************************************/
+
+WRITE8_MEMBER(bbc_state::bbc_6845_w)
+{
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+ switch(offset & 1)
+ {
+ case 0 :
+ mc6845->address_w(space,0,data);
+ break;
+ case 1 :
+ mc6845->register_w(space,0,data);
+ break;
+ }
+ return;
+}
+
+READ8_MEMBER(bbc_state::bbc_6845_r)
+{
+
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+
+ switch (offset&1)
+ {
+ case 0: return mc6845->status_r(space,0); break;
+ case 1: return mc6845->register_r(space,0); break;
+ }
+ return 0;
+}
+
+
+
+
+
+/**** BBC B+ Shadow Ram change ****/
+
+void bbcbp_setvideoshadow(running_machine &machine, int vdusel)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ if (vdusel)
+ {
+ state->m_BBC_Video_RAM= state->memregion("maincpu")->base()+0x8000;
+ } else {
+ state->m_BBC_Video_RAM= machine.root_device().memregion("maincpu")->base();
+ }
+}
+
+/************************************************************************
+ * bbc_vh_start
+ * Initialize the BBC video emulation
+ ************************************************************************/
+
+static void common_init(running_machine &machine, int memorySize)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->m_emulation_cursor_size = 1;
+
+ state->m_VideoULA_CR = 7;
+ state->m_VideoULA_CR_counter = 0;
+
+ set_pixel_lookup(state);
+ state->m_saa505x = machine.device("saa505x");
+
+ state->m_BBC_Video_RAM = state->memregion("maincpu")->base();
+ state->m_memorySize=memorySize;
+
+}
+
+VIDEO_START( bbca )
+{
+ common_init(machine,16);
+}
+
+VIDEO_START( bbcb )
+{
+ common_init(machine,32);
+}
+
+VIDEO_START( bbcbp )
+{
+ common_init(machine,32);
+}
+
+VIDEO_START( bbcm )
+{
+ common_init(machine,32);
+}
+
+
+/*
+
+Old removed BBC mc6845 video code.
+This has now all been replaced by MAMEs mc6845 code.
+
+
+
+static void BBC_draw_hi_res(running_machine &machine);
+static void BBC_draw_teletext(running_machine &machine);
+
+
+
+
+static void BBC_draw_teletext(running_machine &machine)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+
+ //Teletext Latch bits 0 to 5 go to bits 0 to 5 on the Teletext chip
+ //Teletext Latch bit 6 is only passed onto bits 6 on the Teletext chip if DE is true
+ //Teletext Latch bit 7 goes to LOSE on the Teletext chip
+
+ teletext_LOSE_w(state->m_saa505x, 0, (state->m_Teletext_Latch>>7)&1);
+
+ teletext_F1(state->m_saa505x);
+
+ teletext_data_w(state->m_saa505x, 0, (state->m_Teletext_Latch&0x3f)|((state->m_Teletext_Latch&0x40)|(m6845_display_enabled_r(0)?0:0x40)));
+
+ int meml=m6845_memory_address_r(0);
+
+ if (((meml>>13)&1)==0)
+ {
+ state->m_Teletext_Latch=0;
+ } else {
+ state->m_Teletext_Latch=(state->m_BBC_Video_RAM[calculate_video_address(state,meml)]&0x7f)|(m6845_display_enabled_r(0)?0x80:0);
+ }
+
+}
+
+
+
+
+
+// This is the actual output of the Video ULA this fuction does all the output to the screen in the BBC emulator
+
+static void BBC_ula_drawpixel(bbc_state *state, int col, int number_of_pixels)
+{
+ int pixel_count;
+ int pixel_temp;
+ if ((state->m_BBC_display>=state->m_BBC_display_left) && ((state->m_BBC_display+number_of_pixels)<state->m_BBC_display_right))
+ {
+
+ pixel_temp=col^state->m_cursor_state;
+ for(pixel_count=0;pixel_count<number_of_pixels;pixel_count++)
+ {
+ *(state->m_BBC_display++) = pixel_temp;
+ }
+ } else {
+ state->m_BBC_display += number_of_pixels;
+ }
+}
+
+
+// the Video ULA hi-res shift registers, pallette lookup and display enabled circuits
+
+
+
+
+
+static const struct m6845_interface BBC6845 =
+{
+ 0,// Memory Address register
+ 0,// Row Address register
+ BBC_Set_HSync,// Horizontal status
+ BBC_Set_VSync,// Vertical status
+ 0,// Display Enabled status
+ 0,// Cursor status
+ BBC_Set_CRE, // Cursor status Emulation
+};
+
+
+
+static void BBC_draw_hi_res(running_machine &machine)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ int meml;
+ unsigned char i=0;
+ int sc1;
+
+ // this is IC38 and IC41 takes 6845 DisplayEnabled and 6845 RA3
+ int DE=m6845_display_enabled_r(0) && (!(m6845_row_address_r(0)&8));
+
+ if (DE)
+ {
+ // read the memory location for the next screen location.
+ meml=calculate_video_address(state,m6845_memory_address_r(0));
+
+ i=state->m_BBC_Video_RAM[meml];
+
+ for(sc1=0;sc1<state->m_pixels_per_byte;sc1++)
+ {
+ BBC_ula_drawpixel(state, state->m_videoULA_pallet_lookup[state->m_pixel_bits[i]], state->m_emulation_pixels_per_real_pixel);
+ i=(i<<1)|1;
+ }
+
+ } else {
+ // if the display is not enable, just draw a blank area.
+ BBC_ula_drawpixel(state, 0, state->m_emulation_pixels_per_byte);
+ }
+}
+
+
+// RGB input to the Video ULA from the Teletext IC
+// Just pass on the output at the correct pixel size.
+void bbc_draw_RGB_in(device_t *device, int offset,int data)
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ BBC_ula_drawpixel(state, data, state->m_emulation_pixels_per_real_pixel);
+}
+
+
+
+
+
+
+// called when the 6845 changes the HSync
+static void BBC_Set_HSync(running_machine &machine, int offset, int data)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ // catch the falling edge
+ if((!data)&&(state->m_BBC_HSync))
+ {
+ state->m_y_screen_pos+=1;
+
+ if ((state->m_y_screen_pos>=0) && (state->m_y_screen_pos<300))
+ {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(state->m_y_screen_pos);
+ state->m_BBC_display_right = state->m_BBC_display_left + 800;
+
+ } else {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(0);
+ state->m_BBC_display_right = state->m_BBC_display_left;
+ }
+
+ state->m_BBC_display = state->m_BBC_display_left + state->m_x_screen_offset;
+
+ }
+ state->m_BBC_HSync=data;
+}
+
+// called when the 6845 changes the VSync
+static void BBC_Set_VSync(running_machine &machine, int offset, int data)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ // catch the falling edge
+ if ((!data)&&(state->m_BBC_VSync))
+ {
+ state->m_y_screen_pos=state->m_y_screen_offset;
+
+ if ((state->m_y_screen_pos>=0) && (state->m_y_screen_pos<300))
+ {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(state->m_y_screen_pos);
+ state->m_BBC_display_right = state->m_BBC_display_left + 800;
+
+ } else {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(0);
+ state->m_BBC_display_right = state->m_BBC_display_left;
+ }
+
+ state->m_BBC_display = state->m_BBC_display_left + state->m_x_screen_offset;
+
+ teletext_DEW(state->m_saa505x);
+ }
+ state->m_BBC_VSync=data;
+
+}
+
+// called when the 6845 changes the Cursor Enabled
+static void BBC_Set_CRE(running_machine &machine, int offset, int data)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ if (data&2) {
+ state->m_VideoULA_CR_counter=state->m_emulation_cursor_size;
+ state->m_VideoULA_CR=1;
+ // set the pallet on
+ if (data&1) set_cursor(state);
+ }
+}
+
+
+
+
+
+WRITE8_MEMBER(bbc_state::bbc_6845_w)
+{
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+ switch(offset & 1)
+ {
+ case 0 :
+ mc6845->address_w(space,0,data);
+ break;
+ case 1 :
+ mc6845->register_w(space,0,data);
+ break;
+ }
+ return;
+
+ switch (offset&1)
+ {
+ case 0:
+ m6845_address_w(0,data);
+ break;
+ case 1:
+ m6845_register_w(0,data);
+ break;
+ }
+
+}
+
+ READ8_HANDLER (bbc_6845_r)
+{
+
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>("mc6845");
+
+ switch (offset&1)
+ {
+ case 0: return mc6845->status_r(*space,0); break;
+ case 1: return mc6845->register_r(*space,0); break;
+ }
+ return 0;
+
+ int retval=0;
+
+ switch (offset&1)
+ {
+ case 0:
+ break;
+ case 1:
+ retval=m6845_register_r(0);
+ break;
+ }
+ return retval;
+}
+
+
+
+
+
+SCREEN_UPDATE_IND16( bbc )
+{
+
+ mc6845_device *mc6845 = screen.machine().device<mc6845_device>("mc6845");
+ mc6845->update( bitmap, cliprect);
+
+ return 0;
+
+
+
+ bbc_state *state = screen.machine().driver_data<bbc_state>();
+ long c;
+
+ //logerror ("Box %d by %d \n",cliprect.min_y,cliprect.max_y);
+
+ c = 0; // this is used to time out the screen redraw, in the case that the 6845 is in some way out state.
+
+
+ state->m_BBC_bitmap=bitmap;
+
+ state->m_BBC_display_left=&state->m_BBC_bitmap->pix16(0);
+ state->m_BBC_display_right=state->m_BBC_display_left;
+ state->m_BBC_display=state->m_BBC_display_left;
+
+ // loop until the end of the Vertical Sync pulse
+ // or until a timeout (this catches the 6845 with silly register values that would not give a VSYNC signal)
+ while((state->m_BBC_VSync)&&(c<60000))
+ {
+ // Clock the 6845
+ m6845_clock(screen.machine());
+ c++;
+ }
+
+
+ // loop until the Vertical Sync pulse goes high
+ // or until a timeout (this catches the 6845 with silly register values that would not give a VSYNC signal)
+ while((!state->m_BBC_VSync)&&(c<60000))
+ {
+ if ((state->m_y_screen_pos>=cliprect.min_y) && (state->m_y_screen_pos<=cliprect.max_y)) (state->m_draw_function)(screen.machine());
+
+ // and check the cursor
+ if (state->m_VideoULA_CR) BBC_Clock_CR(state);
+
+ // Clock the 6845
+ m6845_clock(screen.machine());
+ c++;
+ }
+
+ return 0;
+}
+
+void bbc_frameclock(running_machine &machine)
+{
+ m6845_frameclock();
+}
+
+*/