mirror of
https://github.com/holub/mame
synced 2025-07-03 00:56:03 +03:00
HLE of HP9845 internal printer (#2884)
* hp9845 & hp64k: fixed breakage caused by c46e1007a8
* hp9845: HLE of internal printer added
* hp9845: fix to printer interrupt line
* hp9845: moved src/devices/machine/hp9845_printer.* to src/mame/machine
This commit is contained in:
parent
d972ebf6f0
commit
6ab7c6949f
@ -2132,6 +2132,8 @@ files {
|
||||
MAME_DIR .. "src/mame/drivers/hp48.cpp",
|
||||
MAME_DIR .. "src/mame/includes/hp48.h",
|
||||
MAME_DIR .. "src/mame/machine/hp48.cpp",
|
||||
MAME_DIR .. "src/mame/machine/hp9845_printer.cpp",
|
||||
MAME_DIR .. "src/mame/machine/hp9845_printer.h",
|
||||
MAME_DIR .. "src/mame/video/hp48.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/hp49gp.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/hp9845.cpp",
|
||||
|
@ -1025,9 +1025,9 @@ void hp_hybrid_cpu_device::do_pw(uint16_t opcode)
|
||||
}
|
||||
WM(tmp_addr >> 1 , tmp);
|
||||
} else {
|
||||
// Extend address
|
||||
uint16_t val = (tmp_addr & 1) ? uint8_t(tmp) << 8 : uint8_t(tmp);
|
||||
uint16_t mask = (tmp_addr & 1) ? 0xff00 : 0x00ff;
|
||||
// Extend address, form byte address
|
||||
uint16_t val = (tmp_addr & 1) ? uint8_t(tmp) : (tmp << 8);
|
||||
uint16_t mask = (tmp_addr & 1) ? 0x00ff : 0xff00;
|
||||
tmp_addr = add_mae(AEC_CASE_C , tmp_addr >> 1);
|
||||
m_program->write_word(tmp_addr , val, mask);
|
||||
}
|
||||
@ -1130,7 +1130,7 @@ uint16_t hp_hybrid_cpu_device::RIO(uint8_t pa , uint8_t ic)
|
||||
|
||||
void hp_hybrid_cpu_device::WIO(uint8_t pa , uint8_t ic , uint16_t v)
|
||||
{
|
||||
m_io->write_word(HP_MAKE_IOADDR(pa, ic), v);
|
||||
m_io->write_word(HP_MAKE_IOADDR(pa, ic) , v);
|
||||
}
|
||||
|
||||
hp_5061_3001_cpu_device::hp_5061_3001_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
|
@ -25,6 +25,7 @@
|
||||
// - Correct character generator ROMs (a huge "thank you" to Ansgar Kueckes for the dumps!)
|
||||
// - 98775 light pen controller
|
||||
// - Display softkeys on 45C & 45T
|
||||
// - HLE of integral printer
|
||||
// What's not yet in:
|
||||
// - Better naming of tape drive image (it's now "magt1" and "magt2", should be "t15" and "t14")
|
||||
// - Better documentation of this file
|
||||
@ -32,7 +33,6 @@
|
||||
// - Speed, as usual
|
||||
// - Light pen tracing sometimes behaves erratically in 45C and 45T
|
||||
// What will probably never be in:
|
||||
// - Integral printer (firmware and character generator ROMs are very difficult to dump)
|
||||
// - Fast LPU processor (dump of microcode PROMs is not available)
|
||||
|
||||
#include "emu.h"
|
||||
@ -48,6 +48,7 @@
|
||||
|
||||
#include "hp9845b.lh"
|
||||
|
||||
#include "machine/hp9845_printer.h"
|
||||
|
||||
// Debugging
|
||||
#define VERBOSE 0
|
||||
@ -187,6 +188,7 @@ constexpr unsigned LP_FOV = 9; // Field of view
|
||||
constexpr unsigned LP_XOFFSET = 5; // x-offset of LP (due to delay in hit recognition)
|
||||
|
||||
// Peripheral Addresses (PA)
|
||||
#define PRINTER_PA 0
|
||||
#define IO_SLOT_FIRST_PA 1
|
||||
#define IO_SLOT_LAST_PA 12
|
||||
#define GVIDEO_PA 13
|
||||
@ -523,6 +525,8 @@ void hp9845_base_state::machine_reset()
|
||||
|
||||
m_beeper->set_state(0);
|
||||
|
||||
m_prt_irl = false;
|
||||
|
||||
logerror("STS=%04x FLG=%04x\n" , m_sts_status , m_flg_status);
|
||||
}
|
||||
|
||||
@ -708,8 +712,8 @@ TIMER_DEVICE_CALLBACK_MEMBER(hp9845_base_state::kb_scan)
|
||||
// Key pressed, store scancode & generate IRL
|
||||
//logerror("idx=%u msl=%d\n" , max_seq_idx , max_seq_len);
|
||||
m_kb_scancode = max_seq_idx;
|
||||
irq_w(0 , 1);
|
||||
BIT_SET(m_kb_status, 0);
|
||||
update_kb_prt_irq();
|
||||
|
||||
// Special case: pressing stop key sets LPU "status" flag
|
||||
if (max_seq_idx == 0x47) {
|
||||
@ -732,8 +736,8 @@ READ16_MEMBER(hp9845_base_state::kb_status_r)
|
||||
|
||||
WRITE16_MEMBER(hp9845_base_state::kb_irq_clear_w)
|
||||
{
|
||||
irq_w(0 , 0);
|
||||
BIT_CLR(m_kb_status, 0);
|
||||
update_kb_prt_irq();
|
||||
m_lpu->status_w(0);
|
||||
|
||||
if (BIT(data , 15)) {
|
||||
@ -743,6 +747,12 @@ WRITE16_MEMBER(hp9845_base_state::kb_irq_clear_w)
|
||||
}
|
||||
}
|
||||
|
||||
void hp9845_base_state::update_kb_prt_irq()
|
||||
{
|
||||
bool state = BIT(m_kb_status , 0) || m_prt_irl;
|
||||
irq_w(0 , state);
|
||||
}
|
||||
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(hp9845_base_state::beeper_off)
|
||||
{
|
||||
m_beeper->set_state(0);
|
||||
@ -756,6 +766,22 @@ WRITE8_MEMBER(hp9845_base_state::pa_w)
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp9845_base_state::prt_irl_w)
|
||||
{
|
||||
m_prt_irl = state;
|
||||
update_kb_prt_irq();
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp9845_base_state::prt_flg_w)
|
||||
{
|
||||
flg_w(PRINTER_PA , state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp9845_base_state::prt_sts_w)
|
||||
{
|
||||
sts_w(PRINTER_PA , state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp9845_base_state::t14_irq_w)
|
||||
{
|
||||
irq_w(T14_PA , state);
|
||||
@ -3695,6 +3721,9 @@ ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(ppu_io_map , AS_IO , 16 , hp9845_base_state)
|
||||
ADDRESS_MAP_UNMAP_LOW
|
||||
// PA = 0, IC = 0..1
|
||||
// Internal printer
|
||||
AM_RANGE(HP_MAKE_IOADDR(PRINTER_PA , 0) , HP_MAKE_IOADDR(PRINTER_PA , 1)) AM_DEVREADWRITE("printer" , hp9845_printer_device , printer_r , printer_w)
|
||||
// PA = 0, IC = 2
|
||||
// Keyboard scancode input
|
||||
AM_RANGE(HP_MAKE_IOADDR(0 , 2) , HP_MAKE_IOADDR(0 , 2)) AM_READ(kb_scancode_r)
|
||||
@ -3791,6 +3820,12 @@ static MACHINE_CONFIG_START(hp9845_base)
|
||||
MCFG_RAM_ADD(RAM_TAG)
|
||||
MCFG_RAM_DEFAULT_SIZE("192K")
|
||||
MCFG_RAM_EXTRA_OPTIONS("64K, 320K, 448K")
|
||||
|
||||
// Internal printer
|
||||
MCFG_DEVICE_ADD("printer" , HP9845_PRINTER , 0)
|
||||
MCFG_9845PRT_IRL_HANDLER(WRITELINE(hp9845_base_state , prt_irl_w))
|
||||
MCFG_9845PRT_FLG_HANDLER(WRITELINE(hp9845_base_state , prt_flg_w))
|
||||
MCFG_9845PRT_STS_HANDLER(WRITELINE(hp9845_base_state , prt_sts_w))
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_START(hp9845b)
|
||||
|
@ -47,6 +47,9 @@ public:
|
||||
|
||||
DECLARE_WRITE8_MEMBER(pa_w);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(prt_irl_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(prt_flg_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(prt_sts_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(t14_irq_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(t14_flg_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(t14_sts_w);
|
||||
@ -55,7 +58,6 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER(t15_sts_w);
|
||||
|
||||
DECLARE_INPUT_CHANGED_MEMBER(togglekey_changed);
|
||||
|
||||
protected:
|
||||
required_device<hp_5061_3001_cpu_device> m_lpu;
|
||||
required_device<hp_5061_3001_cpu_device> m_ppu;
|
||||
@ -81,6 +83,7 @@ protected:
|
||||
|
||||
virtual void advance_gv_fsm(bool ds , bool trigger) = 0;
|
||||
void kb_scan_ioport(ioport_value pressed , ioport_port *port , unsigned idx_base , int& max_seq_len , unsigned& max_seq_idx);
|
||||
void update_kb_prt_irq();
|
||||
|
||||
// Character generator
|
||||
required_region_ptr<uint8_t> m_chargen;
|
||||
@ -141,6 +144,9 @@ protected:
|
||||
ioport_value m_kb_state[ 4 ];
|
||||
uint8_t m_kb_scancode;
|
||||
uint16_t m_kb_status;
|
||||
|
||||
// Printer
|
||||
bool m_prt_irl;
|
||||
};
|
||||
|
||||
#endif /* _HP9845_H_ */
|
||||
|
971
src/mame/machine/hp9845_printer.cpp
Normal file
971
src/mame/machine/hp9845_printer.cpp
Normal file
@ -0,0 +1,971 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hp9845_printer.cpp
|
||||
|
||||
HP9845 internal printer HLE
|
||||
|
||||
The internal printer of HP9845-series machines is a thermal
|
||||
printer. It prints by heating the resistors in a fixed line
|
||||
of 560 elements. A stepper motor advances the paper (and in some
|
||||
cases backs it up).
|
||||
A HP nanoprocessor controls the operation of the printer.
|
||||
The NP runs firmware from a 2 kB ROM and it has 256 bytes of
|
||||
RAM. A second 2 kB ROM acts as character generator.
|
||||
Character cells are 7 pixels wide and 12 pixels high.
|
||||
Shape of characters in the character generator is "compressed"
|
||||
in a peculiar way (see patent) so that the 7x12 cell fits in 8
|
||||
bytes. These 8 bytes are addressed according to a Gray code, not
|
||||
a binary code, to speed up access.
|
||||
Each step of the motor moves the paper by 1/154 of inch. Each
|
||||
line in a normal sized character is 2 steps high. Lines of big
|
||||
sized characters are 3 steps high. The horizontal size of
|
||||
pixels is equal to 2 steps.
|
||||
HLE is necessary because it's very difficult to dump ROMs (they're
|
||||
non-standard HP parts and they're soldered on the PCB).
|
||||
Content of char.gen. was reconstructed by looking at the shape
|
||||
of each character on paper.
|
||||
Thanks to Ansgar Kueckes for letting me run tests "remotely" on
|
||||
his printer.
|
||||
|
||||
Output of printer:
|
||||
- bitbanger 1: raw dump of all bytes from PPU to printer
|
||||
- bitbanger 2: output of printer pixels. Each line has this form:
|
||||
<line_no>:<pixels>, where line_no is the line number (counted in
|
||||
motor steps, see above) and <pixels> is the 560-pixel line. Each
|
||||
character of <pixels> is either a space (no dot) or '*'. This
|
||||
stream can be post-processed to produce a bitmapped graphic.
|
||||
Each '*' is to be translated to a 2x2 black square to preserve
|
||||
the 1:1 aspect-ratio of pixels.
|
||||
|
||||
What's not implemented:
|
||||
- A realistic simulation of printer speed
|
||||
- Form Feed
|
||||
- Handling of page length & top/bottom margins
|
||||
- ESC & l <octal> [ST] commands (set vertical size of lines &
|
||||
top margin of paper)
|
||||
|
||||
References:
|
||||
- US Patent 4,180,854
|
||||
- HP 09845-93000, sep 81, HP9845 BASIC programming (appendix A)
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "hp9845_printer.h"
|
||||
|
||||
// Debugging
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
// Bit manipulation
|
||||
namespace {
|
||||
template<typename T> constexpr T BIT_MASK(unsigned n)
|
||||
{
|
||||
return (T)1U << n;
|
||||
}
|
||||
|
||||
template<typename T> void BIT_CLR(T& w , unsigned n)
|
||||
{
|
||||
w &= ~BIT_MASK<T>(n);
|
||||
}
|
||||
|
||||
template<typename T> void BIT_SET(T& w , unsigned n)
|
||||
{
|
||||
w |= BIT_MASK<T>(n);
|
||||
}
|
||||
|
||||
template<typename T> void COPY_BIT(bool bit , T& w , unsigned n)
|
||||
{
|
||||
if (bit) {
|
||||
BIT_SET(w , n);
|
||||
} else {
|
||||
BIT_CLR(w , n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Character constants
|
||||
constexpr uint8_t CH_BS = 0x08;
|
||||
constexpr uint8_t CH_TAB = 0x09;
|
||||
constexpr uint8_t CH_LF = 0x0a;
|
||||
constexpr uint8_t CH_CR = 0x0d;
|
||||
constexpr uint8_t CH_SH_OUT = 0x0e;
|
||||
constexpr uint8_t CH_SH_IN = 0x0f;
|
||||
constexpr uint8_t CH_ESC = 0x1b;
|
||||
|
||||
// Bits in m_attrs
|
||||
constexpr unsigned ATTRS_NEW_BIT = 7; // Redefined character
|
||||
constexpr unsigned ATTRS_TAB_BIT = 6; // Tab position
|
||||
constexpr unsigned ATTRS_U_L_BIT = 5; // Underlined
|
||||
constexpr unsigned ATTRS_BIG_BIT = 4; // Big character
|
||||
constexpr uint8_t ATTRS_REDEF_NO_MASK = 0x0f; // Redefined character number
|
||||
constexpr uint8_t ATTRS_NEW_MASK = BIT_MASK<uint8_t>(ATTRS_NEW_BIT);
|
||||
constexpr uint8_t ATTRS_BIG_MASK = BIT_MASK<uint8_t>(ATTRS_BIG_BIT);
|
||||
constexpr uint8_t ATTRS_U_L_MASK = BIT_MASK<uint8_t>(ATTRS_U_L_BIT);
|
||||
|
||||
// Various timing constants
|
||||
constexpr unsigned MAX_PIXELS_BURNED = 62; // Maximum number of pixels burned in parallel
|
||||
constexpr unsigned USEC_LT_16_PIXELS = 4960; // microseconds to burn < 16 pixels
|
||||
constexpr unsigned USEC_LT_32_PIXELS = 5984; // microseconds to burn < 32 pixels
|
||||
constexpr unsigned USEC_LT_48_PIXELS = 6464; // microseconds to burn < 48 pixels
|
||||
constexpr unsigned USEC_GE_48_PIXELS = 6976; // microseconds to burn >= 48 pixels
|
||||
constexpr unsigned USEC_1_STEP = 3456; // microseconds for 1 motor step
|
||||
|
||||
// Device type definition
|
||||
DEFINE_DEVICE_TYPE(HP9845_PRINTER, hp9845_printer_device, "hp9845_prt", "HP9845 internal printer")
|
||||
|
||||
hp9845_printer_device::hp9845_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig , HP9845_PRINTER , tag , owner , clock),
|
||||
m_irl_handler(*this),
|
||||
m_flg_handler(*this),
|
||||
m_sts_handler(*this),
|
||||
m_prt_graph_out(*this , "prt_graphic"),
|
||||
m_prt_alpha_out(*this , "prt_alpha"),
|
||||
m_prt_chargen(*this , "prt_chargen")
|
||||
{
|
||||
}
|
||||
|
||||
ROM_START(hp9845_printer)
|
||||
ROM_REGION(0x800, "prt_chargen", 0)
|
||||
ROM_LOAD("1818-2687.bin", 0, 0x800, CRC(cce64de8) SHA1(1dfabd32f4bdef85f88a514bd1978b80b25a6e80))
|
||||
ROM_END
|
||||
|
||||
const tiny_rom_entry *hp9845_printer_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME(hp9845_printer);
|
||||
}
|
||||
|
||||
MACHINE_CONFIG_MEMBER(hp9845_printer_device::device_add_mconfig)
|
||||
MCFG_DEVICE_ADD("prt_alpha", BITBANGER, 0)
|
||||
MCFG_DEVICE_ADD("prt_graphic", BITBANGER, 0)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
void hp9845_printer_device::device_start()
|
||||
{
|
||||
m_irl_handler.resolve_safe();
|
||||
m_flg_handler.resolve_safe();
|
||||
m_sts_handler.resolve_safe();
|
||||
|
||||
save_item(NAME(m_display_mode));
|
||||
save_item(NAME(m_shifted));
|
||||
save_item(NAME(m_current_u_l));
|
||||
save_item(NAME(m_current_big));
|
||||
save_item(NAME(m_ibf));
|
||||
save_item(NAME(m_inten));
|
||||
save_item(NAME(m_busy));
|
||||
save_item(NAME(m_ib));
|
||||
save_item(NAME(m_pos));
|
||||
save_item(NAME(m_line));
|
||||
save_item(NAME(m_attrs));
|
||||
save_item(NAME(m_redef_count));
|
||||
save_item(NAME(m_redef_idx));
|
||||
save_item(NAME(m_redef_chars));
|
||||
save_item(NAME(m_replace_count));
|
||||
save_item(NAME(m_redef_buff));
|
||||
save_item(NAME(m_next_replace));
|
||||
save_item(NAME(m_rep_str_len));
|
||||
save_item(NAME(m_rep_str_ptr));
|
||||
save_item(NAME(m_octal_accum));
|
||||
save_item(NAME(m_fsm_state));
|
||||
save_item(NAME(m_cur_line));
|
||||
|
||||
m_timer = timer_alloc(0);
|
||||
}
|
||||
|
||||
void hp9845_printer_device::device_reset()
|
||||
{
|
||||
state_reset();
|
||||
m_cur_line = 0;
|
||||
m_inten = false;
|
||||
m_ibf = false;
|
||||
m_busy = false;
|
||||
update_flg();
|
||||
m_sts_handler(true);
|
||||
}
|
||||
|
||||
void hp9845_printer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
m_busy = false;
|
||||
update_fsm();
|
||||
update_flg();
|
||||
}
|
||||
|
||||
READ16_MEMBER(hp9845_printer_device::printer_r)
|
||||
{
|
||||
uint16_t res = 0;
|
||||
|
||||
switch (offset) {
|
||||
case 0:
|
||||
case 1:
|
||||
// Bit 7: Interrupt enabled
|
||||
// Bit 5: 1
|
||||
// Bit 1: Printer powered (1)
|
||||
// Bit 0: Interrupt pending
|
||||
if (m_inten) {
|
||||
BIT_SET(res , 7);
|
||||
}
|
||||
BIT_SET(res , 5);
|
||||
BIT_SET(res , 1);
|
||||
if (m_inten && !m_ibf && !m_busy) {
|
||||
BIT_SET(res , 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(hp9845_printer_device::printer_w)
|
||||
{
|
||||
switch (offset) {
|
||||
case 0:
|
||||
// New character
|
||||
m_ib = (uint8_t)data;
|
||||
m_ibf = true;
|
||||
update_fsm();
|
||||
update_flg();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Control word
|
||||
m_inten = BIT(data , 7);
|
||||
update_flg();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hp9845_printer_device::state_reset()
|
||||
{
|
||||
m_display_mode = false;
|
||||
m_shifted = false;
|
||||
m_current_u_l = false;
|
||||
m_current_big = false;
|
||||
memset(m_attrs , 0 , sizeof(m_attrs));
|
||||
memset(m_redef_buff, 0, sizeof(m_redef_buff));
|
||||
m_redef_count = 0;
|
||||
m_replace_count = 0;
|
||||
m_next_replace = REDEF_BUFF_LEN - 1;
|
||||
m_rep_str_len = 0;
|
||||
m_rep_str_ptr = 0;
|
||||
start_new_line();
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
|
||||
void hp9845_printer_device::insert_char(uint8_t ch)
|
||||
{
|
||||
if (m_pos == 80) {
|
||||
crlf();
|
||||
}
|
||||
COPY_BIT(m_current_big , m_attrs[ m_pos ] , ATTRS_BIG_BIT);
|
||||
COPY_BIT(m_current_u_l , m_attrs[ m_pos ] , ATTRS_U_L_BIT);
|
||||
if (ch == '_') {
|
||||
BIT_SET(m_attrs[ m_pos ] , ATTRS_U_L_BIT);
|
||||
} else {
|
||||
m_line[ m_pos ] = ch;
|
||||
// Check for redefined characters
|
||||
unsigned redef_idx;
|
||||
if (is_ch_redef(ch , redef_idx)) {
|
||||
m_attrs[ m_pos ] = (m_attrs[ m_pos ] & ~ATTRS_REDEF_NO_MASK) | (uint8_t)redef_idx | ATTRS_NEW_MASK;
|
||||
} else {
|
||||
BIT_CLR(m_attrs[ m_pos ] , ATTRS_NEW_BIT);
|
||||
}
|
||||
}
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
void hp9845_printer_device::start_new_line()
|
||||
{
|
||||
m_pos = 0;
|
||||
memset(m_line, ' ', sizeof(m_line));
|
||||
for (auto& x : m_attrs) {
|
||||
x &= ~(ATTRS_NEW_MASK | ATTRS_BIG_MASK | ATTRS_U_L_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t hp9845_printer_device::get_ch_matrix_line(const uint8_t *matrix_base , unsigned line_no , const uint8_t *seq)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
|
||||
switch (line_no) {
|
||||
case 0:
|
||||
{
|
||||
uint8_t b0 = matrix_base[ seq[ 0 ] ];
|
||||
if (BIT(b0 , 0)) {
|
||||
res = b0 >> 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
uint8_t b3 = matrix_base[ seq[ 3 ] ];
|
||||
if (BIT(b3 , 0)) {
|
||||
res = matrix_base[ seq[ 0 ] ] >> 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
uint8_t b1 = matrix_base[ seq[ 1 ] ];
|
||||
if (!BIT(b1 , 0)) {
|
||||
res = b1 >> 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
uint8_t b2 = matrix_base[ seq[ 2 ] ];
|
||||
if (!BIT(b2 , 0)) {
|
||||
res = b2 >> 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
res = matrix_base[ seq[ line_no - 1 ] ] >> 1;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
{
|
||||
uint8_t b1 = matrix_base[ seq[ 1 ] ];
|
||||
if (BIT(b1 , 0)) {
|
||||
res = b1 >> 1;
|
||||
} else {
|
||||
uint8_t b5 = matrix_base[ seq[ 5 ] ];
|
||||
if (BIT(b5 , 0)) {
|
||||
res = matrix_base[ seq[ 0 ] ] >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
{
|
||||
uint8_t b2 = matrix_base[ seq[ 2 ] ];
|
||||
if (BIT(b2 , 0)) {
|
||||
res = b2 >> 1;
|
||||
} else {
|
||||
uint8_t b6 = matrix_base[ seq[ 6 ] ];
|
||||
if (BIT(b6 , 0)) {
|
||||
res = matrix_base[ seq[ 0 ] ] >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
{
|
||||
uint8_t b7 = matrix_base[ seq[ 7 ] ];
|
||||
if (BIT(b7 , 0)) {
|
||||
res = matrix_base[ seq[ 0 ] ] >> 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
unsigned hp9845_printer_device::print_560_pixels(unsigned line_no , const uint8_t *pixels)
|
||||
{
|
||||
std::ostringstream buff;
|
||||
buff << line_no;
|
||||
buff << ':';
|
||||
unsigned pixel_count = 0;
|
||||
for (unsigned i = 0; i < 70; i++) {
|
||||
uint8_t pop_count = pixels[ i ];
|
||||
pop_count = (pop_count & 0x55) + ((pop_count >> 1) & 0x55);
|
||||
pop_count = (pop_count & 0x33) + ((pop_count >> 2) & 0x33);
|
||||
pop_count = (pop_count & 0x0f) + ((pop_count >> 4) & 0x0f);
|
||||
pixel_count += pop_count;
|
||||
for (uint8_t mask = 0x80; mask; mask >>= 1) {
|
||||
buff << ((mask & pixels[ i ]) ? '*' : ' ');
|
||||
}
|
||||
}
|
||||
if (pixel_count) {
|
||||
buff << '\n';
|
||||
std::string out{buff.str()};
|
||||
for (auto c : out) {
|
||||
m_prt_graph_out->output(c);
|
||||
}
|
||||
}
|
||||
LOG("pc=%u\n" , pixel_count);
|
||||
return pixel_count;
|
||||
}
|
||||
|
||||
static const uint8_t linear_seq[] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 };
|
||||
static const uint8_t gray_seq[] = { 0 , 1 , 3 , 2 , 6 , 7 , 5 , 4 };
|
||||
|
||||
uint8_t hp9845_printer_device::get_ch_pixels(uint8_t ch , uint8_t attrs , unsigned matrix_line) const
|
||||
{
|
||||
uint8_t pixels;
|
||||
bool new_ch = BIT(attrs , ATTRS_NEW_BIT);
|
||||
if (new_ch) {
|
||||
const uint8_t *matrix = &m_redef_buff[ (attrs & ATTRS_REDEF_NO_MASK) * 8 ];
|
||||
pixels = get_ch_matrix_line(matrix, matrix_line, linear_seq);
|
||||
} else {
|
||||
const uint8_t *matrix = &m_prt_chargen[ ch * 8 ];
|
||||
pixels = get_ch_matrix_line(matrix, matrix_line, gray_seq);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
attotime hp9845_printer_device::burn_time(unsigned pixel_count)
|
||||
{
|
||||
if (pixel_count == 0) {
|
||||
return attotime::zero;
|
||||
}
|
||||
unsigned full_burns = pixel_count / MAX_PIXELS_BURNED;
|
||||
unsigned rem_pixels = pixel_count - full_burns * MAX_PIXELS_BURNED;
|
||||
unsigned usec = full_burns * USEC_GE_48_PIXELS;
|
||||
if (rem_pixels < 16) {
|
||||
usec += USEC_LT_16_PIXELS;
|
||||
} else if (rem_pixels < 32) {
|
||||
usec += USEC_LT_32_PIXELS;
|
||||
} else if (rem_pixels < 48) {
|
||||
usec += USEC_LT_48_PIXELS;
|
||||
} else {
|
||||
usec += USEC_GE_48_PIXELS;
|
||||
}
|
||||
return attotime::from_usec(usec);
|
||||
}
|
||||
|
||||
void hp9845_printer_device::print_line()
|
||||
{
|
||||
attotime print_time;
|
||||
bool any_big = false;
|
||||
// Normal-sized character range is [0..22], every other line
|
||||
// Big-sized characters range is [-8..22], one line every 3
|
||||
for (int line_off = -8; line_off < 23; line_off++) {
|
||||
if ((line_off + int(m_cur_line)) < 0) {
|
||||
continue;
|
||||
}
|
||||
bool norm_line = line_off >= 0 && line_off % 2 == 0;
|
||||
bool big_line = (line_off + 8) % 3 == 0;
|
||||
|
||||
if (norm_line || big_line) {
|
||||
uint8_t pixel_line[ 70 ];
|
||||
memset(pixel_line, 0, sizeof(pixel_line));
|
||||
|
||||
unsigned pixel_line_idx = 0;
|
||||
uint8_t pixel_line_mask = 0x80;
|
||||
|
||||
for (unsigned pos = 0; pos < m_pos; pos++) {
|
||||
uint8_t ch = m_line[ pos ];
|
||||
uint8_t attrs = m_attrs[ pos ];
|
||||
uint8_t pixels = 0;
|
||||
|
||||
if (line_off == 22 && BIT(attrs , ATTRS_U_L_BIT)) {
|
||||
// Underline
|
||||
pixels = 0x7f;
|
||||
} else if (BIT(attrs , ATTRS_BIG_BIT) && big_line) {
|
||||
any_big = true;
|
||||
unsigned matrix_line = (line_off + 8) / 3;
|
||||
pixels = get_ch_pixels(ch, attrs, matrix_line);
|
||||
} else if (!BIT(attrs , ATTRS_BIG_BIT) && norm_line) {
|
||||
unsigned matrix_line = line_off / 2;
|
||||
pixels = get_ch_pixels(ch, attrs, matrix_line);
|
||||
}
|
||||
for (uint8_t mask = 0x40; mask; mask >>= 1) {
|
||||
if (pixels & mask) {
|
||||
pixel_line[ pixel_line_idx ] |= pixel_line_mask;
|
||||
}
|
||||
pixel_line_mask >>= 1;
|
||||
if (pixel_line_mask == 0) {
|
||||
pixel_line_mask = 0x80;
|
||||
pixel_line_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned pixel_count = print_560_pixels(unsigned(line_off + int(m_cur_line)) , pixel_line);
|
||||
print_time += burn_time(pixel_count);
|
||||
}
|
||||
}
|
||||
m_cur_line += 24;
|
||||
// Computing an accurate printing time is a lot more complex than this.
|
||||
// This should be a reasonable estimate.
|
||||
if (any_big) {
|
||||
print_time += attotime::from_usec(USEC_1_STEP * 32);
|
||||
} else {
|
||||
print_time += attotime::from_usec(USEC_1_STEP * 24);
|
||||
}
|
||||
LOG("A time=%.6f\n" , print_time.as_double());
|
||||
m_timer->adjust(print_time);
|
||||
m_busy = true;
|
||||
}
|
||||
|
||||
void hp9845_printer_device::print_graphic_line()
|
||||
{
|
||||
unsigned pixel_count = print_560_pixels(m_cur_line , m_line);
|
||||
attotime print_time{burn_time(pixel_count)};
|
||||
print_time += attotime::from_usec(USEC_1_STEP * 2);
|
||||
m_cur_line += 2;
|
||||
LOG("G time=%.6f\n" , print_time.as_double());
|
||||
m_timer->adjust(print_time);
|
||||
m_busy = true;
|
||||
}
|
||||
|
||||
void hp9845_printer_device::crlf()
|
||||
{
|
||||
print_line();
|
||||
start_new_line();
|
||||
}
|
||||
|
||||
void hp9845_printer_device::set_tab()
|
||||
{
|
||||
if (m_pos > 0) {
|
||||
BIT_SET(m_attrs[ m_pos - 1 ] , ATTRS_TAB_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void hp9845_printer_device::clear_tabs()
|
||||
{
|
||||
for (auto& x : m_attrs) {
|
||||
BIT_CLR(x , ATTRS_TAB_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void hp9845_printer_device::move_to_next_tab()
|
||||
{
|
||||
for (unsigned i = m_pos; i < 80; i++) {
|
||||
if (BIT(m_attrs[ i ] , ATTRS_TAB_BIT)) {
|
||||
m_pos = i + 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
crlf();
|
||||
}
|
||||
|
||||
void hp9845_printer_device::update_flg()
|
||||
{
|
||||
m_flg_handler(!m_ibf && !m_busy);
|
||||
m_irl_handler(!m_ibf && !m_busy && m_inten);
|
||||
}
|
||||
|
||||
bool hp9845_printer_device::is_ch_redef(uint8_t ch , unsigned& redef_number) const
|
||||
{
|
||||
for (unsigned i = 0; i < m_redef_count; i++) {
|
||||
if (m_redef_chars[ i ] == ch) {
|
||||
redef_number = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t hp9845_printer_device::allocate_ch_redef(uint8_t& idx)
|
||||
{
|
||||
if (m_redef_count >= REDEF_CH_COUNT) {
|
||||
idx = REDEF_CH_COUNT - 1;
|
||||
return true;
|
||||
} else if (m_next_replace < 8) {
|
||||
return false;
|
||||
} else {
|
||||
uint8_t max_idx = (m_next_replace - 8) / 8;
|
||||
if (max_idx < m_redef_count) {
|
||||
idx = max_idx;
|
||||
} else {
|
||||
idx = m_redef_count++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool hp9845_printer_device::is_ch_replaced(uint8_t ch , uint8_t& len , uint8_t& ptr) const
|
||||
{
|
||||
uint8_t idx = REDEF_BUFF_LEN - 1;
|
||||
for (unsigned i = 0; i < m_replace_count; i++) {
|
||||
if (m_redef_buff[ idx-- ] == ch) {
|
||||
len = m_redef_buff[ idx-- ];
|
||||
ptr = idx;
|
||||
return true;
|
||||
} else {
|
||||
idx -= (m_redef_buff[ idx ] + 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t hp9845_printer_device::free_redef_space() const
|
||||
{
|
||||
return m_next_replace - m_redef_count * 8;
|
||||
}
|
||||
|
||||
uint8_t hp9845_printer_device::apply_shifting(uint8_t ch) const
|
||||
{
|
||||
if ((ch & 0x60) == 0 || !m_shifted) {
|
||||
return ch;
|
||||
} else {
|
||||
return ch | 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
bool hp9845_printer_device::parse_octal(uint8_t ch)
|
||||
{
|
||||
if (ch >= '0' && ch <= '7') {
|
||||
m_octal_accum = (m_octal_accum * 8) + (ch - '0');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool hp9845_printer_device::parse_ch(uint8_t ch)
|
||||
{
|
||||
bool consume = true;
|
||||
|
||||
switch (m_fsm_state) {
|
||||
case FSM_NORMAL_TEXT:
|
||||
if (m_display_mode) {
|
||||
insert_char(apply_shifting(ch));
|
||||
if (ch == CH_CR) {
|
||||
crlf();
|
||||
} else if (ch == CH_ESC) {
|
||||
m_fsm_state = FSM_WAIT_ESC_Z;
|
||||
}
|
||||
} else {
|
||||
switch (ch) {
|
||||
case CH_BS:
|
||||
if (m_pos > 0) {
|
||||
m_pos--;
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_TAB:
|
||||
move_to_next_tab();
|
||||
break;
|
||||
|
||||
case CH_LF:
|
||||
{
|
||||
auto save_pos = m_pos;
|
||||
crlf();
|
||||
m_pos = save_pos;
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_CR:
|
||||
m_fsm_state = FSM_AFTER_CR;
|
||||
break;
|
||||
|
||||
case CH_SH_OUT:
|
||||
m_shifted = true;
|
||||
break;
|
||||
|
||||
case CH_SH_IN:
|
||||
m_shifted = false;
|
||||
break;
|
||||
|
||||
case CH_ESC:
|
||||
m_fsm_state = FSM_AFTER_ESC;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((ch & 0xe4) == 0x80) {
|
||||
m_current_u_l = false;
|
||||
} else if ((ch & 0xe4) == 0x84) {
|
||||
m_current_u_l = true;
|
||||
} else if ((ch & 0x60) != 0) {
|
||||
insert_char(apply_shifting(ch));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_CR:
|
||||
if (ch == CH_LF) {
|
||||
// CR + LF sequence
|
||||
crlf();
|
||||
} else {
|
||||
// CR + something not LF
|
||||
auto save_cur_line = m_cur_line;
|
||||
crlf();
|
||||
m_cur_line = save_cur_line;
|
||||
// Ch is pushed back for next iteration of FSM
|
||||
consume = false;
|
||||
}
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC:
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
switch (ch) {
|
||||
case '1':
|
||||
set_tab();
|
||||
break;
|
||||
|
||||
case '3':
|
||||
clear_tabs();
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
LOG("State reset\n");
|
||||
state_reset();
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
m_display_mode = true;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
if (m_pos > 0) {
|
||||
crlf();
|
||||
}
|
||||
m_pos = 0;
|
||||
m_fsm_state = FSM_COLLECT_ESC_QMARK;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown ESC sequence
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP:
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_D;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_K;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_L;
|
||||
m_octal_accum = 0;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_N;
|
||||
m_octal_accum = 0;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_O;
|
||||
m_octal_accum = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown ESC & sequence
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_COLLECT_ESC_QMARK:
|
||||
m_line[ m_pos++ ] = ch;
|
||||
if (m_pos == 70) {
|
||||
print_graphic_line();
|
||||
start_new_line();
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_K:
|
||||
switch (ch) {
|
||||
case '0':
|
||||
case '1':
|
||||
m_octal_accum = ch != '0';
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_K_01;
|
||||
break;
|
||||
|
||||
default:
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_K_01:
|
||||
if (ch == 'S') {
|
||||
m_current_big = m_octal_accum;
|
||||
}
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_D:
|
||||
switch (ch) {
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
m_current_u_l = true;
|
||||
break;
|
||||
|
||||
case '@':
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
m_current_u_l = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_N:
|
||||
if (!parse_octal(ch)) {
|
||||
if (ch == 'c') {
|
||||
unsigned dummy;
|
||||
if (is_ch_redef(m_octal_accum, dummy) || !allocate_ch_redef(m_redef_idx)) {
|
||||
// Character redefined twice or space exhausted
|
||||
m_redef_idx = 0xff;
|
||||
}
|
||||
LOG("Redef ch %02x @%u\n" , m_octal_accum , m_redef_idx);
|
||||
if (m_redef_idx < REDEF_CH_COUNT) {
|
||||
m_redef_chars[ m_redef_idx ] = m_octal_accum;
|
||||
}
|
||||
m_octal_accum = 0;
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_N_C;
|
||||
} else {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_O:
|
||||
if (!parse_octal(ch)) {
|
||||
if (ch == 'c') {
|
||||
uint8_t dummy1;
|
||||
uint8_t dummy2;
|
||||
if (is_ch_replaced(m_octal_accum, dummy1, dummy2) || free_redef_space() < 2) {
|
||||
// Character replaced twice or space exhausted
|
||||
m_redef_idx = 0xff;
|
||||
} else {
|
||||
m_redef_idx = m_next_replace;
|
||||
m_redef_buff[ m_redef_idx-- ] = m_octal_accum;
|
||||
m_redef_buff[ m_redef_idx ] = 0;
|
||||
m_next_replace -= 2;
|
||||
m_replace_count++;
|
||||
}
|
||||
m_octal_accum = 0;
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_O_C;
|
||||
} else {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_O_C:
|
||||
if (!parse_octal(ch)) {
|
||||
if (ch == 'L') {
|
||||
if (m_redef_idx < REDEF_BUFF_LEN) {
|
||||
uint8_t max_len = std::min(m_octal_accum , free_redef_space());
|
||||
m_next_replace -= max_len;
|
||||
m_redef_buff[ m_redef_idx-- ] = max_len;
|
||||
LOG("Repl ch %02x with str @%u, len=%u\n" , m_redef_buff[ m_redef_idx + 2 ] , m_redef_idx , max_len);
|
||||
}
|
||||
if (m_octal_accum) {
|
||||
m_fsm_state = FSM_AFTER_ESC_AMP_O_C_L;
|
||||
} else {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
} else {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_O_C_L:
|
||||
if (m_redef_idx < REDEF_BUFF_LEN && m_redef_idx >= m_next_replace) {
|
||||
m_redef_buff[ m_redef_idx-- ] = ch;
|
||||
}
|
||||
if (--m_octal_accum == 0) {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_L:
|
||||
if (!parse_octal(ch)) {
|
||||
// TODO: ESC & l <octal> [ST]
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_AFTER_ESC_AMP_N_C:
|
||||
if (!parse_octal(ch)) {
|
||||
if (ch >= 'p' && ch <= 'w') {
|
||||
if (m_redef_idx < REDEF_CH_COUNT) {
|
||||
m_redef_buff[ m_redef_idx * 8 + ch - 'p' ] = m_octal_accum;
|
||||
}
|
||||
m_octal_accum = 0;
|
||||
} else if (ch >= 'P' && ch <= 'W') {
|
||||
if (m_redef_idx < REDEF_CH_COUNT) {
|
||||
m_redef_buff[ m_redef_idx * 8 + ch - 'P' ] = m_octal_accum;
|
||||
}
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
} else {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_WAIT_ESC_Z:
|
||||
insert_char(ch);
|
||||
if (ch == 'Z') {
|
||||
m_display_mode = false;
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
} else if (ch != CH_ESC) {
|
||||
m_fsm_state = FSM_NORMAL_TEXT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return consume;
|
||||
}
|
||||
|
||||
void hp9845_printer_device::update_fsm()
|
||||
{
|
||||
while (!m_busy && m_ibf) {
|
||||
bool consume = false;
|
||||
if (m_rep_str_len != 0) {
|
||||
consume = parse_ch(m_redef_buff[ m_rep_str_ptr ]);
|
||||
} else if ((m_fsm_state == FSM_NORMAL_TEXT || m_fsm_state == FSM_AFTER_CR || m_fsm_state == FSM_COLLECT_ESC_QMARK) &&
|
||||
is_ch_replaced(apply_shifting(m_ib), m_rep_str_len, m_rep_str_ptr)) {
|
||||
LOG("Subst ch %02x with str @%u (len = %u)\n" , m_ib , m_rep_str_ptr , m_rep_str_len);
|
||||
if (m_rep_str_len == 0) {
|
||||
consume = true;
|
||||
}
|
||||
} else {
|
||||
consume = parse_ch(m_ib);
|
||||
}
|
||||
if (consume) {
|
||||
if (m_rep_str_len) {
|
||||
m_rep_str_len--;
|
||||
m_rep_str_ptr--;
|
||||
}
|
||||
if (m_rep_str_len == 0) {
|
||||
m_prt_alpha_out->output(m_ib);
|
||||
m_ibf = false;
|
||||
update_flg();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
134
src/mame/machine/hp9845_printer.h
Normal file
134
src/mame/machine/hp9845_printer.h
Normal file
@ -0,0 +1,134 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hp9845_printer.h
|
||||
|
||||
HP9845 internal printer HLE
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_HP9845_PRINTER_H
|
||||
#define MAME_MACHINE_HP9845_PRINTER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imagedev/bitbngr.h"
|
||||
|
||||
#define MCFG_9845PRT_IRL_HANDLER(_devcb) \
|
||||
devcb = &hp9845_printer_device::set_irl_handler(*device , DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_9845PRT_FLG_HANDLER(_devcb) \
|
||||
devcb = &hp9845_printer_device::set_flg_handler(*device , DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_9845PRT_STS_HANDLER(_devcb) \
|
||||
devcb = &hp9845_printer_device::set_sts_handler(*device , DEVCB_##_devcb);
|
||||
|
||||
class hp9845_printer_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
hp9845_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// static configuration helpers
|
||||
template <class Object> static devcb_base &set_irl_handler(device_t &device, Object &&cb) { return downcast<hp9845_printer_device &>(device).m_irl_handler.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &set_flg_handler(device_t &device, Object &&cb) { return downcast<hp9845_printer_device &>(device).m_flg_handler.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &set_sts_handler(device_t &device, Object &&cb) { return downcast<hp9845_printer_device &>(device).m_sts_handler.set_callback(std::forward<Object>(cb)); }
|
||||
|
||||
// device-level overrides
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
// PPU access
|
||||
DECLARE_READ16_MEMBER(printer_r);
|
||||
DECLARE_WRITE16_MEMBER(printer_w);
|
||||
|
||||
private:
|
||||
devcb_write_line m_irl_handler;
|
||||
devcb_write_line m_flg_handler;
|
||||
devcb_write_line m_sts_handler;
|
||||
|
||||
required_device<bitbanger_device> m_prt_graph_out;
|
||||
required_device<bitbanger_device> m_prt_alpha_out;
|
||||
required_region_ptr<uint8_t> m_prt_chargen;
|
||||
|
||||
emu_timer *m_timer;
|
||||
|
||||
// Size of various buffers
|
||||
static constexpr unsigned REDEF_CH_COUNT = 9;
|
||||
static constexpr unsigned REDEF_BUFF_LEN = 77;
|
||||
|
||||
// State
|
||||
bool m_display_mode;
|
||||
bool m_shifted;
|
||||
bool m_current_u_l;
|
||||
bool m_current_big;
|
||||
bool m_ibf;
|
||||
bool m_inten;
|
||||
bool m_busy;
|
||||
uint8_t m_ib;
|
||||
uint8_t m_pos;
|
||||
uint8_t m_line[ 80 ];
|
||||
uint8_t m_attrs[ 80 ];
|
||||
uint8_t m_redef_count;
|
||||
uint8_t m_redef_idx;
|
||||
uint8_t m_redef_chars[ REDEF_CH_COUNT ];
|
||||
uint8_t m_replace_count;
|
||||
uint8_t m_redef_buff[ REDEF_BUFF_LEN ];
|
||||
uint8_t m_next_replace;
|
||||
uint8_t m_rep_str_len;
|
||||
uint8_t m_rep_str_ptr;
|
||||
uint8_t m_octal_accum;
|
||||
int m_fsm_state;
|
||||
unsigned m_cur_line;
|
||||
|
||||
// FSM states
|
||||
enum {
|
||||
FSM_NORMAL_TEXT,
|
||||
FSM_AFTER_CR,
|
||||
FSM_AFTER_ESC,
|
||||
FSM_AFTER_ESC_AMP,
|
||||
FSM_COLLECT_ESC_QMARK,
|
||||
FSM_AFTER_ESC_AMP_K,
|
||||
FSM_AFTER_ESC_AMP_K_01,
|
||||
FSM_AFTER_ESC_AMP_D,
|
||||
FSM_AFTER_ESC_AMP_N,
|
||||
FSM_AFTER_ESC_AMP_O,
|
||||
FSM_AFTER_ESC_AMP_O_C,
|
||||
FSM_AFTER_ESC_AMP_O_C_L,
|
||||
FSM_AFTER_ESC_AMP_L,
|
||||
FSM_AFTER_ESC_AMP_N_C,
|
||||
FSM_WAIT_ESC_Z
|
||||
};
|
||||
|
||||
void state_reset();
|
||||
void insert_char(uint8_t ch);
|
||||
void start_new_line();
|
||||
static uint8_t get_ch_matrix_line(const uint8_t *matrix_base , unsigned line_no , const uint8_t *seq);
|
||||
unsigned print_560_pixels(unsigned line_no , const uint8_t *pixels);
|
||||
uint8_t get_ch_pixels(uint8_t ch , uint8_t attrs , unsigned matrix_line) const;
|
||||
static attotime burn_time(unsigned pixel_count);
|
||||
void print_line();
|
||||
void print_graphic_line();
|
||||
void crlf();
|
||||
void set_tab();
|
||||
void clear_tabs();
|
||||
void move_to_next_tab();
|
||||
void update_flg();
|
||||
bool is_ch_redef(uint8_t ch , unsigned& redef_number) const;
|
||||
uint8_t allocate_ch_redef(uint8_t& idx);
|
||||
bool is_ch_replaced(uint8_t ch , uint8_t& len , uint8_t& ptr) const;
|
||||
uint8_t free_redef_space() const;
|
||||
uint8_t apply_shifting(uint8_t ch) const;
|
||||
bool parse_octal(uint8_t ch);
|
||||
bool parse_ch(uint8_t ch);
|
||||
void update_fsm();
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(HP9845_PRINTER, hp9845_printer_device)
|
||||
|
||||
#endif // MAME_MACHINE_HP9845_PRINTER_H
|
Loading…
Reference in New Issue
Block a user